[文件系统]文件系统学习笔记(八)---mount系统调用(代码相关)

本文详细解析了Linux内核中mount系统调用的工作原理,包括参数检查、路径转换、不同flag参数的处理、文件系统类型的获取、超级块对象的创建与挂载过程,以及如何将挂载实例加入到mount树中。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一,mount系统调用--相关代码
源码位置:kernel/fs/Namespace.c文件的do_mount()函数,

long do_mount(char *dev_name,char*dir_name,char*type_page,unsigned long flags,void *data_page)

         if (!dir_name || !*dir_name || !memchr(dir_name, 0, PAGE_SIZE))
                 return -EINVAL;
dev_name指的是要挂载文件系统的名字,如tmpfs,
dir_name指的是文件系统要被挂载的目标目录
type_page指的是要挂载的文件系统的类型
flags指的是挂载选项,如MS_RDONLY等等
data_page指的是一些额外选项等,如wait关键字


1,do_mount()函数首先会做一些参数检查,dir_name不能为空并且大小不能超过一个PAGE大小,将data_page超过一个PAGE大小的部分截断。

if(!memchr(dir_name,0,PAGE_SIZE))

检查data_page的长度是否超过一个page,如果超过,则将超出的部分截断。

if (data_page)
((char *)data_page)[PAGE_SIZE - 1] = 0;


do_mount()函数首先调用kern_path()函数,将dir_name转换为struct path结构体,

 struct path{
  struct vfsmount *mnt;
  struct dentry *dentry;
 };


2,然后根据不同的flag参数去设置不同的mnt_flags临时变量,如果flag中没有包含MS_REMOUNT,MS_BIND,MS_MOVE,MS_SHARED,MS_PRIVATE,等,那么最后会调do_new_mount()函数。


3,do_new_mount()函数 

static int do_new_mount(struct path*path,char*type,int flags,int mnt_flags,char*name,void*data)


   path参数是dir_name经过kern_path()转换后的path结构体
   type参数指的是文件系统的类型
   flags参数指的是一些mount选项
   mnt_flags参数指的是一些monut选项
   name参数指的是要挂载文件系统的名字,如tmpfs
   data参数指的是一些额外选项等,如wait关键字


   do_new_mount()函数首先调用do_kern_mount(type,flags,name,data)函数,该函数的作用是建立一块新的安装块区域,获取一个vfsmount实例,获取源文件系统vfsmount结构,并通过特定文件系统的操作装载到系统系统中,返回装载点的根目录,然后调用do_add_mount(real_mount(mnt),path,mnt_flags)函数,该函数的作用是将mount实例挂载到mount树上去,将源文件系统增加到目的文件系统中。

1651 static int do_new_mount(struct path *path, char *type, int flags,
1652                         int mnt_flags, char *name, void *data)
1653 {
1654         struct vfsmount *mnt;
1655 
1656         if (!type)
1657                 return -EINVAL;
1658 
1659         /* we need capabilities... */
1660         if (!capable(CAP_SYS_ADMIN))
1661                 return -EPERM;
1662 
1663         lock_kernel();
1664         mnt = do_kern_mount(type, flags, name, data);
1665         unlock_kernel();
1666         if (IS_ERR(mnt))
1667                 return PTR_ERR(mnt);
1668 
1669         return do_add_mount(mnt, path, mnt_flags, NULL);
1670 }

   do_kern_mount()函数细节,do_kern_mount()首先调用get_fs_type()函数返回要挂载文件系统的file_system_type实例,file_system_type是在各个文件系统在系统启动的时候 注册进内核的,所有注册的文件系统形成一个单链表,然后do_kern_mount()调用vfs_kern_mount()函数,vfs_kern_mount()函数的作用是分配一个struct mount结构体,然后vfs_kern_mount()调用各个文件系统file_system_type结构的mount成员函数(如ext4则会调用ext4_mount函数),该函数的作用是创建该文件系统的超级快对象,返回该文件系统的根目录(root)的dentry实例,最后将创建的超级快对象赋值给新创建的vfsmount结构所指的超级快,同时vfsmount所指的mnt_root点赋值为超级快所指的根dentry.
   
   do_add_mount()函数细节,该函数作用是将当前mount实例加到mount树上,do_add_mount()函数的两个关键点,lock_mount()函数和graft_tree()函数,lock_mount()检查如果当前要挂载的目录之前已经挂载其它文件系统,则要进行文件系统切换动作,graft是嫁接的意思,是将将要mount的目录树与当前目录的文件系统的目录树连接起来,很像嫁接技术,而原来文件系统的目录树没损伤。

lock_mount()函数主要调用lookup_mnt()函数,该函数返回一个struct vfsmount的实例,lookup_mnt()函数调用__lookup_mnt()函数返回一个struct mount的实例,在同个父文件系统下的同个目录可以作为多个子文件系统的挂载点,所以如果真的挂载了多个子文件系统,那么这几个子文件系统通过散列函数肯定会被放在哈希表里的同一条链表上。__lookup_mnt()函数就是返回该目录下最后挂载的文件系统mount的实例。__lookup_mnt()函数如下所示:

414 struct vfsmount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry,
415                               int dir)
416 {
417         struct list_head *head = mount_hashtable + hash(mnt, dentry);
418         struct list_head *tmp = head;
419         struct vfsmount *p, *found = NULL;
420 
421         for (;;) {
422                 tmp = dir ? tmp->next : tmp->prev;
423                 p = NULL;
424                 if (tmp == head)
425                         break;
426                 p = list_entry(tmp, struct vfsmount, mnt_hash);
427                 if (p->mnt_parent == mnt && p->mnt_mountpoint == dentry) {
428                         found = p;
429                         break;
430                 }
431         }
432         return found;
433 }
   
   graft_tree()函数的实现细节,graft_tree()函数主要调用attach_recursive_mnt()函数,static int attach_recursive_mnt(struct mount*source_mnt,struct path*path,struct path*parent_path),attach_recursive_mnt()函数做的主要操作是1.通过mnt_set_mountpoint()将子vfsmount中的mnt_parent指向父vfsmount,将子vfsmount的mnt_mountpoint指向位于父文件系统中的挂载点dentry;2.通过commit_tree()将子文件系统添加到内核的文件系统哈希表中,并将子文件系统添加到父文件系统对应的子文件系统链表中;
   commit_tree()函数的作用是1.将当前文件系统的名字空间设置为父名字空间,父vfsmount通过当前vfsmount中的mnt_parent获取;再将其连接到父名字空间链表中。2.将当前vfsmount加入到对应哈希值的冲突链表当中,哈希值通过hash()计算。其中,mnt_hash作为链表元素。3.将当前vfsmount加入到父vfsmount对应的子文件系统链mnt_mounts中。其中,mnt_child作为链表元素。

f2fs文件系统调用主要涉及以下几个组件和函数: 1. 文件系统类型定义:在f2fs文件系统中,通过定义一个file_system_type结构体来表示文件系统类型。其中包括了文件系统的名称、挂载函数、卸载函数等信息。在f2fs中,文件系统类型定义如下: static struct file_system_type f2fs_fs_type = { .owner = THIS_MODULE, .name = "f2fs", .mount = f2fs_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; 2. 挂载函数:f2fs_mount函数是用来将块设备挂载成f2fs文件系统的函数。它是通过调用mount_bdev函数来实现的。具体的挂载过程包括了填充f2fs super block信息等操作。在f2fs中,挂载函数定义如下: static struct dentry *f2fs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { return mount_bdev(fs_type, flags, dev_name, data, f2fs_fill_super); } 3. 填充super block信息:f2fs_fill_super函数用来填充f2fs文件系统的super block信息。它会读取块设备上的super block数据,并将其解析为内存中的数据结构。在f2fs中,填充super block信息的函数定义如下: static int f2fs_fill_super(struct super_block *sb, void *data, int silent) { // 填充super block信息的具体实现 } 通过以上组件和函数,f2fs文件系统可以被调用和使用。当用户在用户空间执行mount操作时,会回调到文件系统类型中定义的mount函数,即f2fs_mount函数。在f2fs_mount函数中,会调用mount_bdev函数来实现具体的挂载过程,包括填充super block信息等操作。最终,f2fs文件系统就可以被成功挂载和使用。 #### 引用[.reference_title] - *1* [f2fs学习笔记 - 4. f2fs文件系统组件说明](https://blog.youkuaiyun.com/jasonactions/article/details/122417105)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [f2fs学习四: f2fs文件系统挂载](https://blog.youkuaiyun.com/guozhidixian/article/details/115498708)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值