一、数据结构
文件系统建立了一个组织形式来对磁盘中的数据进行管理,如果我们需要对磁盘进行访问的话,首先当前内核系统应该支持该文件系统格式,然后将磁盘挂载到该系统的某个路径下。而挂载的过程是一个复杂的过程,因为挂载之后,就将挂载的目录项dentry与该磁盘文件系统的根目录项进行了关联,我们对该路径的访问就变成了对磁盘的访问(简单理解就是对这个路径下IO操作,底层是由磁盘内部的文件系统来决定了)。同一个路径,是可以挂载多次的,当前的文件系统由最后一次挂载磁盘的文件系统来决定;umount之后,由上一次挂载的磁盘文件系统来决定(也就是顺序的mount和umount)
- struct mountpoint结构
// fs/mount.h
struct mountpoint {
struct hlist_node m_hash; //散列链表节点成员,将mountpoint实例添加到全局散列表mountpoint_hashtable
struct dentry *m_dentry; // 指向挂载点 dentry 实例(根文件系统中目录项,不是挂载磁盘中的)
struct hlist_head m_list; // 挂载点挂载操作的Mount实例,链表头
int m_count; // 挂载点执行挂载操作的次数
};
- struct mount 一次挂载所需要涉及的结构数据(fs/mount.h)
- struct vfsmount 建立mount实例与挂载文件系统之间的关联(include/linux/mount.h)
struct vfsmount {
struct dentry *mnt_root; //指向挂载文件系统根目录项dentry实例
struct super_block *mnt_sb; //指向文件系统超级块实例
int mnt_flags; //内核内部使用的挂载标记
struct user_namespace *mnt_userns;
} __randomize_layout;
每一个挂载实例对应一个struct vfsmount,包含了于挂载磁盘文件系统的根路径和super_block的关联;而mount是对vfsmount的封装。
二、挂载流程
用户进程通过mount()系统调用挂载具体文件系统,内核mount函数入口为sys_mount(),实现在fs/namespace.c中。其中dev_name定义了块设备路径;di_name定义了挂载点目录;type定义了文件系统类型;flags挂载标志,data定义了一些挂载选项
SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,
char __user *, type, unsigned long, flags, void __user *, data)
{
int ret;
char *kernel_type;
char *kernel_dev;
void *options;
/* 拷贝文件系统类型名到内核空间 */
kernel_type = copy_mount_string(type);
ret = PTR_ERR(kernel_type);
if (IS_ERR(kernel_type))
goto out_type;
/* 拷贝块设备路径名到内核空间 */
kernel_dev = copy_mount_string(dev_name);
ret = PTR_ERR(kernel_dev);
if (IS_ERR(kernel_dev))
goto out_dev;
/* 拷贝挂载选项到内核空间 */
options = copy_mount_options(data);
ret = PTR_ERR(options);
if (IS_ERR(options))
goto out_data;
/* 挂载委托do_mount,最重要的接口实现 */
ret = do_mount(kernel_dev, dir_name, kernel_type, flags, options);
kfree(options);
out_data:
kfree(kernel_dev);
out_dev:
kfree(kernel_type);
out_type:
return ret;
}
内核系统调用流程
SYSCALL_DEFINE5(mount...) //namespace.c
do_mount()
user_path()
do_remount()
do_loopback()
do_change_type()
do_move_mount()
do_new_mount()
struct file_system_type *type
struct vfs_mount *mnt
mnt = vfs_kern_mount()
struct mount * mnt
mnt = alloc_vfsmnt()
root = mount_fs()
struct super_block *sb
root = type->mount() //回调file_system_type的mount方法
sb = root ->d_sb
security_sb_kern_mount()
up_write()
init mnt
list_add_tail(&mnt->mnt_instance, &root->d_sb->s_mounts)
do_add_mount(real_mount(mnt),path,mnt_flags)
ext4_mnt() //ext4
mount_bdev(...ext4_fill_super)
struct block_device *bdev
struct super_block *s
bdev = blkdev_get_by_path()
s = sget(...test_bdev_super,set_bdev_super...) //find or create a superblock
alloc_super()
kzalloc()
init_waitqueue_head()
s->s_bdi = &noop_backing_dev_info
...other initialization of s
set() //set_bdev_super()
s->s_bdev = data;
s->s_dev = s->s_bdev->bd_dev;
s->s_bdi = &bdev_get_queue(s->s_bdev)->backing_dev_info;
bdev->bd_disk->queue;
list_add_tail(...&super_blocks)
hlist_add_head()
get_filesystem()
__module_get()
sb_set_blocksize()
fill_super() //ext4_fill_super()
struct ext4_sb_info *sbi
sbi = kzalloc()
... init sbi...
ext4_msg()
setup_timer()
sb->s_op = &ext4_sops
sb->s_export_op = &ext4_export_ops
sb->s_xattr = ext4_xattr_handlers
sb->s_root = d_make_root()
ext4_setup_super()
ext4_ext_init()
ext4_mb_init()
sbi->s_kobj.kset = ext4_kset
init_completion()
kobject_init_and_add(&sbi->s_kobj, &ext4_ktype...)
s->s_flags|=MS_ACTIVE
bdev->bd_super = s
dget()
## 3 总结
对于内核的Mount流程,内核定义了一个Mountpoint结构体表示跟文件系统中的一个挂载点,挂载点对应跟文件系统中的一个dentry实例,用户通过mount系统调用实现文件系统的挂载,其主要流程为:
- 执行内核的挂载函数vfs_kern_mount:该函数主要是创建文件系统超级块super_block、根目录项dentry和inode结构体实例,并创建表示本次挂载操作的mount结构体实例,mount实例添加到超级块实例s_mounts成员链表中,并与挂载文件系统根目录项dentry建立关联

- 关联挂载点do_add_mount:创建挂载点mountpoint结构体实例,并添加到全局散列表,mountpoint实例关联到挂载点dentry实例(跟文件系统中目录项),并将挂载mount实例添加到Mountpoint实例链表和全局散列表中,建立mount实例与挂载断点dentry之间的关联,一个挂载点可以有多个挂载,因此Mountpoint实例包含一个挂载mount实例的链表

执行完这两步,通过mount实例建立了挂载点dentry实例和挂载文件系统根目录项dentry实例之间的联系。

当内核打开文件搜索路径到达挂载点时(挂载点dentry实例设置DCACHE_MOUNTED标记位),将调用函数lookup_mnt(path),在mount实例全局散列表中查找第一个关联到挂载点dentry实例的mount实例,搜索路径随后进入mount实例关联的挂载文件系统根目录项。
## 4 参考文档
[https://blog.51cto.com/u_15127540/3543420](https://blog.51cto.com/u_15127540/3543420)
linux内核解析
参考文档:
文件系统mount过程
版权声明:本文为weixin_43273308原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。