Linux内核文件系统挂载分析
本文将针对内核版本3.2.0中的mount系统调用实现过程进行简单说明。
1.数据结构
下面将对文件系统挂载过程中涉及到的两个主要数据结构vfsmount和path进行节本说明。
1.1 struct vfsmount
每个挂载在内核目录树中的文件系统都将对应一个vfsmount结构,下面将对该结构中的部分字段进行说明。假设设备/dev/sdc为ntfs文件系统,现需要将其挂载在文件系统为ext3的/home/edsionte/work下。因此,/home/edsionte/work可以被称为ntfs文件系统的挂载点,并且称ntfs文件系统与ext3文件系统形成父子文件文件系统关系。同时ntfs也可称为源文件系统,而ext3也可称为目的文件系统。
struct list_head mnt_hash;
内核将系统内所有已挂载的文件系统通过散列表的形式进行组织,每个vfsmount将处于其对应哈希值的冲突链表当中。mnt_hash字段则为具体冲突链表的元素。
struct list_head mnt_mounts;
如果当前文件系统下挂载了其他的子文件系统,那么这些子文件系统将通过自身vfsmount中的mnt_child字段组成一个链表,该链表头为父文件系统中的mnt_mounts字段。
struct list_head mnt_child;
当前文件系统将通过该字段与其他父文件系统下的子文件系统组成一个链表。
struct vfsmount *mnt_parent;
该字段指向父文件系统对应的vfsmount结构。即指向ext3文件系统对应的vfsmount结构。
struct dentry *mnt_mountpoint;
该字段表示源文件系统在目的文件系统中挂载点对应的dentry结构。/home/edsionte/work为挂载点,则该字段指向目录项work。
struct dentry *mnt_root;
指向当前文件系统的根目录项。对于源文件系统ntfs来说,根目录项相对为/,但在整个系统目录树中,根目录项为work。
struct super_block *mnt_sb;
每个文件系统都将对应一个super_block结构,该字段指向/dev/sdc设备上文件系统对应的超级块。
struct list_head mnt_list;
所有处于一个名字空间的文件系统通过mnt_list字段链接在一起,而该链表的表头为该名字空间结构中的list字段。
struct mnt_namespace *mnt_ns;
该字段表示当前vfsmount所对应的名字空间结构。
1.2 struct path
path结构由vfsmount结构和dentry结构组成。该结构在挂载文件系统时表示目的文件系统的vfsmount结构和挂载点dentry。
2.函数调用关系图
3.实现
3.1 mount系统调用服务例程
mount()系统调用服务例程为:
SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, char __user *, type, unsigned long, flags, void __user *, data)
其内部实现主要是将用户态的参数依次复制到内核态,接着调用内核函数do_mount()。
3.2 do_mount()
该函数内部首先通过kern_path()获取目的文件系统的path结构,即挂载点目录项以及目的文件系统的vfsmount结构;接着,通过检查flags对挂载操作进行不同目的的分发。这里我们只讨论最普通的情形,即将一个文件系统挂载在一个新的挂载点中,这种情况调用do_new_mount()。
3.3 do_new_mount()
这个函数描述的是挂载一个新文件系统最普遍的情形,主要包括以下几点:
1.文件系统类型、操纵权限检查等;
2.通过do_kern_mount()获取源文件系统的vfsmount结构;
3.通过do_add_mount()将源文件系统增加到目的文件系统中;
3.4 do_add_mount()
1.flags参数合法性检查;
2.检查指定的目的文件系统是否为当前文件系统。如果是,则失败;
3.检查源文件系统的根inode是否为链接文件。如果是,则失败;
4.通过graft_tree()将源文件系统装载到目的文件系统中。其内部graft又封装了attach_recursive_mnt();
3.5 attach_recursive_mnt()
该函数的主要作用是设置父子文件系统的映射关系。具体操作为:
1.通过mnt_set_mountpoint()将子vfsmount中的mnt_parent指向父vfsmount,将子vfsmount的mnt_mountpoint指向位于父文件系统中的挂载点dentry;
2.通过commit_tree()将子文件系统添加到内核的文件系统哈希表中,并将子文件系统添加到父文件系统对应的子文件系统链表中;
3.6 commit_tree()
1.将当前文件系统的名字空间设置为父名字空间,父vfsmount通过当前vfsmount中的mnt_parent获取;再将其连接到父名字空间链表中。
2.将当前vfsmount加入到对应哈希值的冲突链表当中,哈希值通过hash()计算。其中,mnt_hash作为链表元素。
3.将当前vfsmount加入到父vfsmount对应的子文件系统链表mnt_mounts中。其中,mnt_child作为链表元素。
从整个挂载的处理流程上看,挂载的本质就是将源文件系统的vfsmount结构连接到目的文件系统对应的vfsmount结构中,即具体涉及到两个vfsmount中字段的指向问题。两个vfsmount具体父子等级关系,这也对应着内核中目录树的父子等级关系。
参考资料:
1.深入理解Linux内核:http://book.douban.com/subject/2287506/;
2.深入Linux内核架构:http://book.douban.com/subject/4843567/;
3.Linux内核探秘:http://book.douban.com/subject/25817503/;
建议继续学习:
- Centos挂载新硬盘开机自动挂载 (阅读:7710)
- 从磁盘映像中挂载或提取指定的 LVM 逻辑卷 (阅读:3870)
- 将远程共享文件夹挂载到linux本地目录 (阅读:3595)
- linux磁盘管理学习笔记(下):linux分区、挂载 (阅读:3083)
- 从磁盘映像中挂载或提取指定分区 (阅读:2829)
- linux 挂载光驱 (阅读:2391)
- linux下挂载U盘过程 (阅读:2230)
扫一扫订阅我的微信号:IT技术博客大学习
- 作者:edsionte 来源: edsionte's TechBlog
- 标签: 挂载
- 发布时间:2014-11-28 12:47:03
- [67] Go Reflect 性能
- [67] Oracle MTS模式下 进程地址与会话信
- [67] 如何拿下简短的域名
- [61] IOS安全–浅谈关于IOS加固的几种方法
- [60] 图书馆的世界纪录
- [59] 【社会化设计】自我(self)部分――欢迎区
- [58] android 开发入门
- [56] 视觉调整-设计师 vs. 逻辑
- [49] 给自己的字体课(一)——英文字体基础
- [47] 界面设计速成