標籤:style blog http io color ar 使用 sp strong
本文只討論執行"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
Linux Hugetlbfs核心源碼簡析-----(二)Hugetlbfs掛載