Linux Hugetlbfs內核源碼簡析-----(二)Hugetlbfs掛載


本文只討論執行"mount none /mnt/huge -t hugetlbfs"命令后,mount系統調用的執行過程(基於Linux-3.4.51),不涉及進程相關的細節。

 mount系統調用的內核實現:

 1 SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,
 2         char __user *, type, unsigned long, flags, void __user *, data)
 3 {
 4     int ret;
 5     char *kernel_type;
 6     char *kernel_dir;
 7     char *kernel_dev;
 8     unsigned long data_page;
 9 
10     /* 從用戶空間copy文件系統類型,文件系統類型字符串長度不能大於PAGE_SIZE,即,不能大與4K。
11      * kernel_type = "hugetlbfs"
12      */
13     ret = copy_mount_string(type, &kernel_type);
14     if (ret < 0)
15         goto out_type;
16 
17     /* 從用戶空間獲取掛載點, kerne_dir = "/mnt/huge" */
18     kernel_dir = getname(dir_name);
19     if (IS_ERR(kernel_dir)) {
20         ret = PTR_ERR(kernel_dir);
21         goto out_dir;
22     }
23     
24     /*從用戶空間獲取掛載設備,kernel_dev = "none"*/
25     ret = copy_mount_string(dev_name, &kernel_dev);
26     if (ret < 0)
27         goto out_dev;
28 
29     /*獲取mount命令的其它參數*/
30     ret = copy_mount_options(data, &data_page);
31     if (ret < 0)
32         goto out_data;
33 
34     /*處理具體的mount細節*/
35     ret = do_mount(kernel_dev, kernel_dir, kernel_type, flags,
36         (void *) data_page);
37 
38     free_page(data_page);
39 out_data:
40     kfree(kernel_dev);
41 out_dev:
42     putname(kernel_dir);
43 out_dir:
44     kfree(kernel_type);
45 out_type:
46     return ret;
47 }

相關參數處理完之后,具體的Mount操作由do_mount()函數實現,do_mount()主要分為兩部分來實現,一是找到裝載點的dentry項,二是創建hugetlbfs的super_block、vfsmount、已經掛載點dentry等相關數據結構之間的關聯。

一、kern_path()查找掛載點

 

path_init():查找掛載點路徑名(即,/mnt/huge)的搜索起點的根目錄,保存在數據結構struct nameidata中。

  nd->root = current->fs->root;
  nd->path = nd->root;
  nd->inode = nd->path.dentry->d_inode;

link_path_walk():該函數由一個大循環組成,逐分量處理文件名或路徑名。名稱在循環內分為各個分量(各分量通過一個或多個“/”分割)。每個分量表示一個目錄名,最后一個分量是文件名。在每一個循環周期中,直至指定的文件名或目錄名處理完畢並找到匹配的inode。

  

  具體如下:

  1、逐字符掃描路徑名,斜線“/”會被跳過。

  2、may_lookup()判斷當前inode是否定義了permission方法,來采用不同的方法判斷當前進程是否允許進入該目錄。

  3、判斷當前分量是"."或者“..”,如果是“..”,則設置標志LAST_DOTDOT,最后調用walk_component()--->handle_dots()--->follow_dotdot()處理。如果是".",則設置標志LAST_DOT。

  4、如果是普通分量,則調用walk_component()--->do_lookup()處理。do_lookup()處理實際的查找工作,查找分量對應的dentry。首先從上一級目錄的dentry中查找inode,並調用d_revalidate()檢查該緩存項是否有效(即,是否和實際文件系統的中的數據一致),如果有效,則返回;如果無效,則調用__lookup_hash()繼續查找,首先調用lookup_dcache()查找緩存中是否存在,如果不存在,繼續調用lookup_real(),調用具體的文件系統的lookup函數查找。

  do_lookup()也處理跟蹤掛載點的工作,也需要判斷下級目錄是否也掛載文件系統,__follow_mount_rcu()負責具體處理,在這里不做討論。

  5、nested_symlink()判斷分量是否是符號鏈接。只有用於表示符號鏈接的inode,其inode_operations中的lookup函數指針才有具體的值,否則為NULL。

complete_walk():該函數做一些相關檢查,確認是否需再次調用d_revalidate()判斷緩存項是否有效。

 

二、do_new_mount()裝載文件系統


do_new_mount()分為兩個部分:do_kern_mount()和do_add_mount()。

do_kern_mount():首先調用get_fs_type()獲取對應的已注冊的文件系統類型。對於hugetlbfs來說,對應的內核文件系統類型是hugetlbfs_fs_type。獲取對應的文件系統類型后,首先調用alloc_vfsmnt()分配並初始化mount數據結構,再調用mount_fs(),進一步調用hugetlbfs_mount(),分配掛載點的super_block、dentry、inode並建立相關映射。最后建立mount、super_block、dentry之間的映射。具體的映射關系如http://www.cnblogs.com/MerlinJ/p/4053689.html文中最后的圖表所示。

  hugetlbfs_mount()做了如下工作:

  1、申請並初始化一個super_block。

  2、調用set_anon_super(),獲得一個未使用的此設備號dev,然后用主設備號0和次設備號dev設置新超級塊的s_dev字段。

  3、將該super_block掛到全局super_blocks鏈表中,同時掛到hugetlbfs_fs_type->fs_supers鏈表中。

  4、調用hugetlbfs_fill_super(),創建dentry、inode,並建立dentry、inode、super_block之間的映射。

do_add_mount():首先判斷文件系統是否重復裝載,相同文件系統不能掛載到相同掛載點。再調用attach_recursive_mnt(),將掛載點加入到全局目錄樹,即,將do_kern_mount()創建的mount數據結構,掛到全局mount_hashtable鏈表中,掛到命名空間的mnt_list鏈表中,同時掛到父掛載點的mnt_mounts鏈表中。

 

只是大體走了一下流程,很多具體細節並沒有涉及到,還有待補充。

 

參考:

http://blog.csdn.net/chenjin_zhong/article/details/8448862

http://blog.csdn.net/dndxhej/article/details/7434521


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM