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

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

[cpp]  view plain copy 在CODE上查看代码片 派生到个人代码片
 
  1. 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关键字spa


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

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

 

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

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

 

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

[cpp]  view plain copy 在CODE上查看代码片 派生到个人代码片
 
  1. struct path{  
  2.  struct vfsmount *mnt;  
  3.  struct dentry *dentry;  
  4. };  


2,而后根据不一样的flag参数去设置不一样的mnt_flags临时变量,若是flag中没有包含MS_REMOUNT,MS_BIND,MS_MOVE,MS_SHARED,MS_PRIVATE,等,那么最后会调用
  do_new_mount()函数。get


3,do_new_mount()函数 源码

[cpp]  view plain copy 在CODE上查看代码片 派生到个人代码片
 
  1. 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关键字hash


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

 

[cpp]  view plain copy 在CODE上查看代码片 派生到个人代码片
 
  1. 1651 static int do_new_mount(struct path *path, char *type, int flags,  
  2. 1652                         int mnt_flags, char *name, void *data)  
  3. 1653 {  
  4. 1654         struct vfsmount *mnt;  
  5. 1655   
  6. 1656         if (!type)  
  7. 1657                 return -EINVAL;  
  8. 1658   
  9. 1659         /* we need capabilities... */  
  10. 1660         if (!capable(CAP_SYS_ADMIN))  
  11. 1661                 return -EPERM;  
  12. 1662   
  13. 1663         lock_kernel();  
  14. 1664         mnt = do_kern_mount(type, flags, name, data);  
  15. 1665         unlock_kernel();  
  16. 1666         if (IS_ERR(mnt))  
  17. 1667                 return PTR_ERR(mnt);  
  18. 1668   
  19. 1669         return do_add_mount(mnt, path, mnt_flags, NULL);  
  20. 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()函数以下所示:

[cpp]  view plain copy 在CODE上查看代码片 派生到个人代码片
 
  1. 414 struct vfsmount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry,  
  2. 415                               int dir)  
  3. 416 {  
  4. 417         struct list_head *head = mount_hashtable + hash(mnt, dentry);  
  5. 418         struct list_head *tmp = head;  
  6. 419         struct vfsmount *p, *found = NULL;  
  7. 420   
  8. 421         for (;;) {  
  9. 422                 tmp = dir ? tmp->next : tmp->prev;  
  10. 423                 p = NULL;  
  11. 424                 if (tmp == head)  
  12. 425                         break;  
  13. 426                 p = list_entry(tmp, struct vfsmount, mnt_hash);  
  14. 427                 if (p->mnt_parent == mnt && p->mnt_mountpoint == dentry) {  
  15. 428                         found = p;  
  16. 429                         break;  
  17. 430                 }  
  18. 431         }  
  19. 432         return found;  
  20. 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做为链表元素。

相关文章
相关标签/搜索