linux文件系统初探--Day2(3)

大致搞清楚mount过程在内核中是怎样一个过程之后,今天来看看day2的super.c中都干了啥。

samplefs_fill_super

samplefs_fill_super在挂载时作为samplefs_mount->mount_nodev中的回调函数被调用,接下来看一下 mount_nodev:

mount_nodev

struct dentry *mount_nodev(struct file_system_type *fs_type,
	int flags, void *data,
	int (*fill_super)(struct super_block *, void *, int))
{
	int error;
	struct super_block *s = sget(fs_type, NULL, set_anon_super, flags, NULL);

	if (IS_ERR(s))
		return ERR_CAST(s);

	error = fill_super(s, data, flags & SB_SILENT ? 1 : 0);
	if (error) {
		deactivate_locked_super(s);
		return ERR_PTR(error);
	}
	s->s_flags |= SB_ACTIVE;
	return dget(s->s_root);
}

可见mount_nodev的逻辑如下:

  1. 根据fs_type创建一个super_block;
  2. 调用fill_super填充这个super_block;
  3. 返回super_block的root dentry。

所以fill_super的功能顾名思义,就是fill mount_nodev 创建的super_block:

static int samplefs_fill_super(struct super_block *sb, void *data, int silent)
{
	struct inode *inode;
	struct samplefs_sb_info *sfs_sb;

        /* 设置超级块中的部分成员 */
	sb->s_maxbytes = MAX_LFS_FILESIZE; /* NB: may be too large for mem */
	sb->s_blocksize = PAGE_CACHE_SIZE;
	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
	sb->s_magic = SAMPLEFS_MAGIC;
	sb->s_op = &samplefs_super_ops;
	sb->s_time_gran = 1; /* 1 nanosecond time granularity */

/* Eventually replace iget with:
	inode = samplefs_get_inode(sb, S_IFDIR | 0755, 0); */

        // 这里原来是iget,新内核中,iget被iget_locked代替
        // 根据super_block和inode ino找到相应的inode,如果找不到就新建一个。
        // 这个inode是特定文件系统的root inode
	inode = iget_locked(sb, SAMPLEFS_ROOT_I);

	if (!inode)
		return -ENOMEM;
        unlock_new_inode(inode);

        // 将内存中的super_block的s_fs_info设为samplefs_sb_info
	sb->s_fs_info = kzalloc(sizeof(struct samplefs_sb_info), GFP_KERNEL);
	sfs_sb = SFS_SB(sb);
	if (!sfs_sb) {
		iput(inode);
		return -ENOMEM;
	}

        // 根据root inode创建root dentry
	sb->s_root = d_make_root(inode);
	if (!sb->s_root) {
		iput(inode);
		kfree(sfs_sb);
		return -ENOMEM;
	}

        // 设置 negative language support,这是samplefs_sb_info自带的成员。
	/* below not needed for many fs - but an example of per fs sb data */
	sfs_sb->local_nls = load_nls_default();
	
        // samplefs 挂载时的多个选项,这部分在接下来详细讨论。
	samplefs_parse_mount_options(data, sfs_sb);
	
	/* FS-FILLIN your filesystem specific mount logic/checks here */

	return 0;
}

samplefs_parse_mount_options

这个函数主要是解析mount命令的options,options由mount系统调用(用户态)传给ksys_mount,在ksys_mount中将参数从用户态转换为内核态。解析得到的数据都存放在samplefs_sb_info中。

static void
samplefs_parse_mount_options(char *options, struct samplefs_sb_info *sfs_sb)
{
	char *value;
	char *data;
	int size;

	if (!options)
		return;

	while ((data = strsep(&options, ",")) != NULL) {
		if (!*data)
			continue;
		if ((value = strchr(data, '=')) != NULL)
			*value++ = '\0';

                // 这里strnicmp改为strncasecmp,一样的功能。
		if (strncasecmp(data, "rsize", 5) == 0) {
			if (value && *value) {
				size = simple_strtoul(value, &value, 0);
				if (size > 0)
					sfs_sb->rsize = size;
			}
		} else if (strncasecmp(data, "wsize", 5) == 0) {
			if (value && *value) {
				size = simple_strtoul(value, &value, 0);
				if (size > 0)
					sfs_sb->wsize = size;
			}
		} /* else unknown mount option */
	}
}

samplefs_put_super负责将super_block的私有信息(s_fs_info)从内存移除,我们看代码也确实是做了这样的操作。

现在,我们的samplefs可以执行mount过程了。

小结

其实day2的代码还是容易搞懂的,day2最难弄清楚的其实是mount的具体过程。


上图部分借鉴了这里

vfs_kern_mount负责完成mount过程中文件系统各种结构(mount、vfsmount、super_block、inode以及dentry)的创建与填写,do_add_mount负责将文件系统以及其root_dentry指向正确的父文件系统中dentry的位置。

参考资料

Linux File System - 3
iget_locked源码分析

posted @ 2021-01-20 16:10  xinze  阅读(281)  评论(0编辑  收藏  举报