引言
情景:
<源码> linux:3.14.56 xfsprogs:3.2.0
<命令> mkfs.xfs -f /dev/[sdx] ; mount /dev/[sdx]; umount /dev/[sdx]
如情景所示,来分析分析,mkfs.xfs mount 以及umount操作都做了些什么事情。下述内容均为本人随意跟踪,看到那说到哪!仅作参考。
MKFS.XFS
本例格式化xfs文件系统,有关xfs文件系统就不介绍了。倒是首先要分析mkfs.xfs命令,先得获取相应的源码,源码获取可到github搜索xfsprogs,之前找了一个util-linux的包,编译后才发觉不支持mkfs.xfs,其它的文件系统倒还支持一些的,可见xfs还是比较“特殊”的,值得了解一下。好吧,总之下载即可。
- mkfs.xfs -f /dev/sdc
- 源码分析
1、进入 xfs_mkfs.c文件主函数main。对于一个提供给用户使用的终端命令(或说控制接口),它做的事情无非就是在接受用户指令后,对相应指令参数进行解析,而后下发给后端进/线程做进一步处理,当然最终会返回信息给当前主进程,处理完事务后(同步的话),进程也就退出了。
- 源码分析
... ...
while ((c = getopt(argc, argv, "b:d:i:l:L:m:n:KNp:qr:s:CfV")) != EOF) {
switch (c) {
case 'C':
case 'f':
force_overwrite = 1;
break;
... ...
跟踪force_overwrite标志:
memset(&ft, 0, sizeof(ft)); ----/1/
get_topology(&xi, &ft, force_overwrite); ----/2/
/1/ 首先初始化以ft为首地址的fs_topology结构体,那么不妨先来看看这个结构体的内容有哪些:
/*
* Device topology information.
*/
struct fs_topology {
int dsunit; /* stripe unit - data subvolume:*/
int dswidth; /* stripe width - data subvolume */
int rtswidth; /* stripe width - rt subvolume */
int lsectorsize; /* logical sector size &*/
int psectorsize; /* physical sector size */
int sectoralign; //扇区对齐标志:该标志位置位1时,要求处理的块大小与扇区大小相同(老linux版本中),因而通常不会置位。
};
/2/ 若ENABLE_BLKID有定义,即安装有blkid源码,即可执行blkid命令,获取设备的拓扑结构如下:
static void get_topology(
libxfs_init_t *xi,
struct fs_topology *ft,
int force_overwrite)
{
if (!xi->disfile) { ----/2.1/
const char *dfile = xi->volname ? xi->volname : xi->dname;
blkid_get_topology(dfile, &ft->dsunit, &ft->dswidth, ----/2.2/
&ft->lsectorsize, &ft->psectorsize,
force_overwrite);
}
if (xi->rtname && !xi->risfile) {
int dummy;
blkid_get_topology(xi->rtname, &dummy, &ft->rtswidth,
&dummy, &dummy, force_overwrite);
}
}
/2.1/ libxfs_init_t函数memset初始化为0,其成员变量disfile可知其初始化为0,又当前mkfs.xfs命令未加-d选项,则进入该分支处理。下面分支同理。
/2.2/ 处理获取设备拓扑结构,这里不好追踪就不展开了,关键函数定义实现在blkid命令源码中如:当前函数中的blkid_new_probe_from_filename。
/2// 若ENABLE_BLKID无定义,获取设备的拓扑结构:
static void get_topology(
libxfs_init_t *xi,
struct fs_topology *ft,
int force_overwrite)
{
char *dfile = xi->volname ? xi->volname : xi->dname;
int bsz = BBSIZE;
if (!xi->disfile) {
int fd;
long long dummy;
get_subvol_stripe_wrapper(dfile, SVTYPE_DATA, ----/2.1//
&ft->dsunit, &ft->dswidth, &ft->sectoralign);
fd = open(dfile, O_RDONLY);
/* If this fails we just fall back to BBSIZE */
if (fd >= 0) {
platform_findsizes(dfile, fd, &dummy, &bsz);
close(fd);
}
}
ft->lsectorsize = bsz;
ft->psectorsize = bsz;
if (xi->rtname && !xi->risfile) {
int dummy1;
get_subvol_stripe_wrapper(dfile, SVTYPE_RT, &dummy1,
&ft->rtswidth, &dummy1);
}
}
/2.1// 不妨进入该函数:
void
get_subvol_stripe_wrapper(
char *dev,
sv_type_t type,
int *sunit,
int *swidth,
int *sectalign)
{
struct stat64 sb;
if (dev == NULL)
return;
if (stat64(dev, &sb)) {
fprintf(stderr, _("Cannot stat %s: %s\n"),
dev, strerror(errno));
exit(1);
}
if ( dm_get_subvol_stripe(dev, type, sunit, swidth, sectalign, &sb))
return;
if ( md_get_subvol_stripe(dev, type, sunit, swidth, sectalign, &sb)) ----/2.1.1//
return;
if ( lvm_get_subvol_stripe(dev, type, sunit, swidth, sectalign, &sb))
return;
if ( xvm_get_subvol_stripe(dev, type, sunit, swidth, sectalign, &sb))
return;
if (evms_get_subvol_stripe(dev, type, sunit, swidth, sectalign, &sb))
return;
//可添加其它类型的设备驱动,信息获取如上格式
/* ... add new device drivers here */
}
/2.1.1// 分析它即可,其它的同理。顾名思义,即获取Multiple Devices相关的东西,也就是有关矩阵raid条带化的信息,因为mkfs.xfs命令未加-d选项,故而获取的是创建md设备时指定的条带信息。进入该函数可知,主要是对其参数进行赋值。
返回main主函数,调用libxfs_init函数进行xfs文件系统的初始化,主要关注一下函数:
1、radix_tree_init
基树初始化,主要用于内存管理,该树为典型的字典类型结构(有待研究)
2、libxfs_device_open
打开一个设备并且获取其设备号,即便不是真的设备亦返回一个伪设备号
3、cache_init
初始化缓存,返回cache结构体
4、manage_zones
manage_zones函数实现释放xfs分区或生成xfs分区。而生成启动xfs目录结构调用的是xfs_dir_startup函数,该函数定义在linux源码lib库中(可使得生成目录下”.”以及“..”文件)
回到main函数,进入判断force_overwrite标志位的分支结构,调用zero_old_xfs_structures函数,函数将置0初始化各个次要AG的sb超级块结构,通常128M至4T左右容量设的备,4个AG用于管理磁盘空间。当然若是raid阵列的话就另当别论了,相同容量需创建更多的AG。AG超级块结构参考:http://www.lenky.info/archives/2012/01/648
回到main函数,调用libxfs_mount —-/3/,该函数主要就是对结构体进行填充,不过却是非常重要的,不妨来看看:
/*
* Mount structure initialization, provides a filled-in xfs_mount_t
* such that the numerous XFS_* macros can be used.