普通文件系统安装流程
asmlinkage long sys_mount(char __user * dev_name, char __user * dir_name,
char __user * type, unsigned long flags, void __user * data);
参数说明:
1. 文件系统所在的设备文件的路径名,或者如果不需要则为NULL(如网络文件系统);
2. 文件系统被安装其上的某个目录的路径名,即安装点;
3. 文件系统类型,必须是已注册的文件系统;
4. 安装标志(如只读MS_RDONLY, 不允许程序执行MS_NOEXEC);
5. 指向一个与文件系统相关的数据结构的指针;
sysmount的工作:
1. 把参数的值拷贝到临时的内核缓冲区(copy_mount_option,申请页,拷贝数据);
retval = copy_mount_options(type, &type_page); //文件系统类型
dir_page = getname(dir_name); //安装点路径
retval = copy_mount_options(dev_name, &dev_page); //设备名
retval = copy_mount_options(data, &data_page); //其它相关的数据
2. 获取大内核锁,并调用do_mount;
lock_kernel();
retval = do_mount((char *)dev_page, dir_page, (char *)type_page, flags, (void *)data_page);
unlock_kernel();
+-----------------------------------------------------------------------------------------------------------------------------+
long do_mount(char *dev_name, char *dir_name, char *type_page,
unsigned long flags, void *data_page);
参数说明:
分别为设备名的地址,路径名地址,文件系统类型地址,挂载标志,额外数据;
do_mount的工作:
1. 将挂载标志转换为安装文件系统的标志,以MNT_开头的;
如:if (flags & MS_NOSUID)
mnt_flags |= MNT_NOSUID;
2. 调用path_lookup查找安装点的路径名,将结果存放在nameidata类型的局部变量中;
retval = path_lookup(dir_name, LOOKUP_FOLLOW, &nd);
3. 检查安装标志已决定做什么:
如MS_REMOUNT标志被指定,则执行do_remount;
如MS_MOVE标志指定,则要求改变已安装文件系统的安装点,执行do_move_mount;
……
调用do_new_mount安装新的文件系统,其先后调用do_kern_mount,do_add_mount;
其中do_add_mount将新安装文件系统插入到namespace链表中,不作详细分析。
if (flags & MS_REMOUNT)
retval = do_remount(&nd, flags & ~MS_REMOUNT, mnt_flags,
data_page);
else if (flags & MS_BIND)
retval = do_loopback(&nd, dev_name, flags & MS_REC);
else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
retval = do_change_type(&nd, flags);
else if (flags & MS_MOVE)
retval = do_move_mount(&nd, dev_name);
else
retval = do_new_mount(&nd, type_page, flags, mnt_flags,
dev_name, data_page);
+-----------------------------------------------------------------------------------------------------------------------------+
struct vfsmount *
do_kern_mount(const char *fstype, int flags, const char *name, void *data)
{
struct file_system_type *type = get_fs_type(fstype);
struct vfsmount *mnt;
if (!type)
return ERR_PTR(-ENODEV);
mnt = vfs_kern_mount(type, flags, name, data);
put_filesystem(type);
return mnt;
}
参数说明:
do_kern_mount接受文件系统类型,安装标志,设备名,额外数据等参数,其处理实际的安装操作并返回一个新安装文件系统描述符的地址;
do_kern_mount的工作:
1. 调用get_fs_type在文件系统类型链表中搜索,返回对应file_system_type描述符的地址;
struct file_system_type *type = get_fs_type(fstype);
2. 调用alloc_vfsmnt分配一个新的已安装文件系统的描述符,存放在局部变量mnt中;
mnt = alloc_vfsmnt(name);
3. 调用依赖于文件系统的type->get_sb函数分配,并初始化一个新的超级块;
error = type->get_sb(type, flags, name, data, mnt);
4. 初始化mnt的mnt_sb,mnt_root等字段;
mnt->mnt_mountpoint = mnt->mnt_root;
mnt->mnt_parent = mnt;
5. 返回mnt的地址;
+-----------------------------------------------------------------------------------------------------------------------------+
static int ext2_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
return get_sb_bdev(fs_type, flags, dev_name, data, ext2_fill_super, mnt);
}
get_sb_bdev函数分配并初始化一个新的适合于磁盘文件系统的超级块,它接受ext2_fill_super函数的地址,该函数从ext2磁盘分区读取磁盘超级块。
VFS还提供get_sb_pseudo(针对没有安装点的文件系统,如pipefs),get_sb_single(对于具有唯一安装点的函数,如sysfs),get_sb_nodev(对于可安装多次的特殊文件系统,如tmpfs)等函数以用于不同的文件系统。
get_sb_bdev的工作:
1.调用open_bdev_excl打开设备文件名为dev_name的块设备;
bdev = open_bdev_excl(dev_name, flags, fs_type);
2. 调用sget搜索文件系统的超级块链表(type->fs_supers)。如果找到一个与块设备相关的超级块,则返回它的地址;否则分配一个新的超级块,把它插入到文件系统链表和超级块全局链表,并返回其地址;
mutex_lock(&bdev->bd_mount_mutex);
s = sget(fs_type, test_bdev_super, set_bdev_super, bdev);
mutex_unlock(&bdev->bd_mount_mutex);
3.如果超级块已经存在,则直接返回;否则如果为新建的,则填充新超级块的s_flags,s_blocksize等信息;
s->s_flags = flags;
strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
sb_set_blocksize(s, block_size(bdev));
4.调用依赖具体文件系统的函数访问磁盘上的超级块信息,并填充超级块的其他信息,最后返回超级块对象的地址;
error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);