歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux綜合 >> Linux資訊 >> 更多Linux >> 特殊文件系統proc

特殊文件系統proc

日期:2017/2/27 14:18:54   编辑:更多Linux
  1. 對kern_mout()進行解析: (1) 調用函數get_unnamed_dev()為文件系統/proc文件系統分配一個設備號。 (2) 調用函數read_super對應的函數proc_read_super()分配super_block,inode,dentry;(a)其中super_block是在函數read_super中新生成的; (b)inode是調用函數proc_get_inde()新生成的; (c)dentry由函數d_alloc_root()創建的; 注:根目錄的inode和dentry創建的依據是一個proc_dir_entry結構proc_root,這個結構相當於一般文件系統中硬盤上的(不是內存中的inode或dentry結構)目錄項之類的東西。 (3) 調用add_vfsmnt()創建vfsmount結構,同時對其進行設置(如和super_block的關系等)。並使得proc文件系統file_system_type數據結構的kern_mnt指向這個vfsmount結構。但是這並不意味著path_walk()就能順著路徑名“/proc”找到proc文件系統的根節點,因為path_walk()並不涉及file_system_type數據結構,而/proc的inode結構和dentry結構並沒有和新創建的這個vfsmount結構聯系起來。 2. 所以,光調用kern_mount()還不夠,還得由系統調用的初始化進程從內核外部調用系統調用mount(),再安裝一次,通常的命令行為:mount –nvt proc/dev/null /proc,也就是說,把建立再“空設備”/dev/null上的proc文件系統安裝再節點/proc 上。 在mount()中,因為file_system_type結構中FS-SINGLE標志位為1,所以要調用get_sb_single()來得到相應的超級塊,其方法和別的不同(別的都是從設備上讀),代碼中通過file_system_type結構中的指針kern_mnt取得文件系統vfsmount結構,從而取得其super_block結構,而這個關系正是在kern_mount()中設置好的。 Mount()中其他的操作就和普通的文件系統的安裝無異了。這樣就把proc文件系統安裝到了節點/proc上。 3. 因為整個proc文件系統都不存在於設備上,所以不光是它的根節點需要在內存中創造出來,自根節點以下的所以節點全都需要在運行時加以創建,這是由內核在初始化時調用proc_root_init()完成的。 (1) 首先是直接在/proc下面的葉子節點,即文件節點,這是由proc_misc_init()創建的。 函數proc_misc_init()調用函數create_proc_read_entry()進行分配結構,而create_proc_read_entry()則調用函數create_proc_entry(),下面對函數create_proc_entry()進行解析: a) 調用函數xlate_proc_name()返回父親節點的proc_dir_entry結構; b) 調用函數kmalloc()分配自己的proc_dir_entry結構; c) 對自己的proc_dir_entry結構進行初始化; d) 調用函數proc_register()對自己的proc_dir_entry結構進行注冊登記,即掛到父親節點的proc_dir_entry結構內的subdir隊列中; (2) 創建三個特殊的文件節點,這三個文件是:kmsg、kcore、profile;這些文件的創建直接調用create_proc_entry(); (3) 創建直接在/proc目錄中的子目錄,如:net,fs,dirver等;這些子目錄都是通過proc_mkdir()創建的。 (4) 除了這些子目錄之外,就只有/proc/tty是特殊的,因為其他的只有兩層目錄/proc/dirname,只有/proc/tty是一顆子樹,即下面還有目錄,所以要專門創建,調用的函數是:proc_tty_init(); (5) 此外,如果系統不采用傳統的基於主設備號/次設備號的/dev設備(文件)目錄,而采用樹狀的設備目錄/device_tree,則還要在proc_root_init()中創建/device_tree子樹。這是由proc_device_init()完成的。 4./porc文件系統的目錄搜尋 注:/proc文件系統中,除了根節點外,其他節點只有proc_dir_entry 結構,沒有dentry結構和inode結構。 1)搜尋/proc/loadavg: (1) 調用path_walk(),到根節點後,要調用函數cached_lookup(),先在內存搜索下一個節點的dentry結構,如果沒在內存中找到,就從設備上讀取,對應的函數是real_lookup(); (2) 從設備上的讀操作具體依賴於其父親節點的inode結構中的指針I_op指向那一個inode_operations數據結構。對於節點/proc,它的I_op指針指向proc_root_inode_operations,這是在它的proc_dir_entry結構proc_root中靜態定義好的。 (3) /proc文件系統對應的讀inode節點的函數是proc_lookup(),這個函數根據要查找節點的proc_dir_dentry結構,填充一個dentry結構,創建一個inode結構,然後返回。 (4) 以後的操作就和一般節點的path_walk()沒什麼區別了。 (5) 下面對其讀操作進行解析: (a) 為讀文件提供的操作函數是proc_file_read(),這是一個為proc特殊文件通用的函數。 (b) 從代碼中可以看出,具體的讀操作是通過該節點的proc_dir_entry結構中的函數指針get_info或read_proc提供的。其中get_info是為了與老一版本兼容而保留的,現在都已改用read_proc。


(c) 對於/proc/loadavg來說,讀文件指針指向loadavg_read_proc();它的作用就是將數組avenrum[]中積累的在過去1分鐘、5分鐘以及15分鐘內的系統平均CPU負荷等統計信息通過sprintf()“打印”到緩沖區頁面中。 (d) 在函數proc_file_read()中,調用該節點讀函數讀完以後,將把讀的信息通過函數copy_to_user(),拷貝的用戶空間。 2)搜尋/proc/self/cwd; (1) 同上,調用proc_root_lookup()->proc_pid_lookup(); 注: a)對於有proc_dir_entry結構的節點,即向proc_root登記而掛入了其隊列中的節點,也就是上一種情景,其查找目標節點所調用的函數依次是: path_walk()->real_lookup()->proc_root_lookup()->proc_lookup(); 注意:在real_lookup()中分配dentry結構,proc_root_lookup()是根據inode節點中提供的操作,在proc_lookup()中分配inode結構。 b)另一種情況是對應於當前系統中的各個進程而並不存在proc_dir_entry結構的節點。其查找目標節點所調用的函數依次是: path_walk()->real_lookup()->proc_root_lookup()->proc_pid_lookup(); 注意:proc_lookup()和proc_pid_lookup()都在函數proc_root_lookup()中。 (2)從proc_root_lookup()返回到path_walk()中以後,接著要檢查和處理兩件事,第一件事新找到的節點是否為安裝點;第二件就是它是否是一個鏈接點。這正是我們所關心的,因為/proc/self就是個鏈接點。 (3)對於鏈接點,通過do_follow_link(),調用該inode結構中的inode_operations結構提供的follow_link函數指針,尋找目標節點。 Follow_link指向函數proc_self_follow_link(),這個函數又調用vfs_follow_lnk(); (4)要指出的是,在vfs_follow_link()中,將會遞歸的調用path_walk()來尋找目標節點,所以又會調用其父親節點/proc的lookup函數,即proc_root_lookup(),不同的是這次尋找的不是”self”,而是當前進程的pid字符串。這一次,在proc_root_lookup()中對proc_lookup()的調用同樣會因為在proc_root的subdir隊列中找不到相應的proc_dir_entry結構而失敗,所以也要進一步調用proc_pid_lookup()尋找。可是這一次的節點名不似乎“self”了,所以走的路線頁就不同了。 (5)這次調用proc_pid_lookup()所起的作用是將要找的函數名(當前進程號的字符串形式)轉換成一個無符號整數,然後依此為pid從系統中尋找是否存在相應的進程。如果找到了相應的進程,就通過proc_pid_make_inode()為之創建一個inode結構,並初始化已經分配的dentry結構。 (6)這樣,從path_walk()->do_follow_link()返回以後,就繼續搜尋下一個節點“cwd”,這一次搜索的是最後一個節點,所以跳到:las_component處。 (7)但是,同樣也要調用函數real_lookup(),從設備上讀取inode結構(其實是重新創建一個inode結構)。在real_lookup()函數中要調用的函數是其父親節點的inode_operation結構中的lookup函數指針指向的函數,這個函數是proc_base_inode_operation()。 (8)在函數proc_base_inode_operation()中,創建inode結構,並根據不同的類型進行初始化。注意,inode 結構中的union被用作一個proc_inode_info結構proc_I,這個結構中的tast指針在函數proc_pid_make_inode()中被設定為該進程的task_strUCt指針。 另外,還要設置的兩項是: (a) 將inode結構中的指針I_op設置成指向proc_pid_link_inode_operation數據結構。 (b) 將inode結構中替換union的proc_inode_info結構中的函數指針proc_get_link設置為指向函數proc_cwd_link(); (9)這樣,從proc_base_inode_operation()返回到(7):real_lookup(),進而返回到path_walk()時,nameidata結構中的指針dentry已經指向這個特定“cwd”節點的dentry結構,但是接著同樣要受到對其inode結構中的I_op指針以及相應inode_operation結構中的指針follow_link的檢查。因為follow_link非0,在(8)被設置。這樣,就可以找到當前工作目錄,其方法見(10); (10)如前所述,節點的inode中的union用作一個proc_inode_info結構,其中的指針task指向相應進程的task_struct結構,進而可以得到這個進程的fs_struct結構,而這個數據結構中的指針pwd即指向該進程的”當前工作目錄“的dentry結構,同時指針pwdmnt指向該目錄所在設備安裝時的vfsmount結構。



另外,還要設置的兩項是: (a) 將inode結構中的指針I_op設置成指向proc_pid_link_inode_operation數據結構。 (b) 將inode結構中替換union的proc_inode_info結構中的函數指針proc_get_link設置為指向函數proc_cwd_link(); (9)這樣,從proc_base_inode_operation()返回到(7):real_lookup(),進而返回到path_walk()時,nameidata結構中的指針dentry已經指向這個特定“cwd”節點的dentry結構,但是接著同樣要受到對其inode結構中的I_op指針以及相應inode_operation結構中的指針follow_link的檢查。因為follow_link非0,在(8)被設置。這樣,就可以找到當前工作目錄,其方法見(10); (10)如前所述,節點的inode中的union用作一個proc_inode_info結構,其中的指針task指向相應進程的task_struct結構,進而可以得到這個進程的fs_struct結構,而這個數據結構中的指針pwd即指向該進程的”當前工作目錄“的dentry結構,同時指針pwdmnt指向該目錄所在設備安裝時的vfsmount結構。



Copyright © Linux教程網 All Rights Reserved