一,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)
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作为链表元素。