1. VFS层安装普通文件系统分析
之所以称之为普通安装是因为接下来讨论的是将一个文件系统安装在一个已安装文件系统之上的情形。使用 mount() 系统调用来安装一个普通文件系统,将会调用它的服务例程 sys_mount() 函数。
1.1 sys_mount()
/**
* @dev_name: 文件系统所在的设备文件的路径名
* @dir_name: 安装点路径名
* @type: 文件系统类型
* @flags: 安装标志
* @data: 指向一个与文件系统相关的数据结构的指针(可能为NULL)
*/
asmlinkage long sys_mount(char __user * dev_name, char __user * dir_name,
char __user * type, unsigned long flags, void __user * data)
/* 把参数值拷贝到内核缓冲区 */
copy_mount_options(type, &type_page);
getname(dir_name);
copy_mount_options(dev_name, &dev_page);
copy_mount_options(data, &data_page);
/* 调用domount()处理安装操作 */
do_mount((char *)dev_page, dir_page, (char *)type_page, flags, (void *)data_page);
struct nameidata nd;
int mnt_flags = 0;
/* 根据系统调用传入的标志设置安装标志mnt_flags */
/* 1. 查找安装点 */
path_lookup(dir_name, LOOKUP_FOLLOW, &nd);
/* 2. 检查安装标识,决定做什么 */
if (flags & MS_REMOUNT)
/* 省略其他操作 */
else
do_new_mount(&nd, type_page, flags, mnt_flags, dev_name, data_page);
struct vfsmount *mnt;
/* 安装操作的核心函数,返回一个已安装文件系统描述符,参考1.2 */
mnt = do_kern_mount(type, flags, name, data);
/* 把已安装文件描述符对象插入到相应链表中,参考1.3 */
do_add_mount(mnt, nd, mnt_flags, NULL);
path_release(&nd);
- 调用path_lookup()函数搜索安装点路径,将最后一个分量的信息保存在 nameidata 类型的局部变量 nd 中,nd 中包括安装点的目录项和已安装文件描述符等重要信息。
- 根据安装标志可以进行不同的操作,例如更改已安装文件系统的安装点等。我们讨论的是用户要安装一个特殊文件系统或存放在磁盘分区中的普通文件系统的情况所以调用 do_new_mount() 函数。
1.2 do_kern_mount()
/**
* @fstype: 文件系统类型
* @flags: 安装点路径名
* @name: 存放文件系统的块设备路径名或特殊问及那系统类型名
* @data:
*/
struct vfsmount *
do_kern_mount(const char *fstype, int flags, const char *name, void *data)
/* 1. 根据文件系统类型搜索文件系统类型链表 */
struct file_system_type *type = get_fs_type(fstype);
struct vfsmount *mnt;
mnt = vfs_kern_mount(type, flags, name, data);
struct vfsmount *mnt;
/* 分配一个新的已安装文件系统描述符 */
mnt = alloc_vfsmnt(name);
struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);
mnt->mnt_devname = newname;
/* 读取并填充超级块对象 */
type->get_sb(type, flags, name, data, mnt);
/* 2. 后面这两个值会重新指向正确的对象 */
mnt->mnt_mountpoint = mnt->mnt_root;
mnt->mnt_parent = mnt;
- 在注册的文件系统类型链表中搜索将要挂载的文件系统的名字,结果保存在局部变量中。后续需要调用文件系统对象中的 get_sb() 方法获取并填充超级块对象。
- 这里进行了初始化,后面在 mnt_set_mountpoint() 中会重新指向正确的对象。
1.3 do_add_mount()
/**
* @newmnt: 已安装文件系统描述符
* @nd: 执行搜索安装点的结果
* @mnt_flags: 安装标志
* @fslist:
*/
int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd,
int mnt_flags, struct list_head *fslist)
/* 1. 当前进程有可能休眠,另一个进程可能在相同的安装点上安装文件系统 */
while (d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry));
/* 最近安装的文件系统是否指向当前的命名空间,如果不是,返回错误 */
if (!check_mnt(nd->mnt));
return mnt->mnt_ns == current->nsproxy->mnt_ns;
/* 2. 要安装的文件系统已被安装到此安装点上,返回错误 */
<