服务器proc文件,特殊文件系统proc
1. 對kern_mout()進(jìn)行解析:
(1) 調(diào)用函數(shù)get_unnamed_dev()為文件系統(tǒng)/proc文件系統(tǒng)分配一個設(shè)備號。
(2) 調(diào)用函數(shù)read_super對應(yīng)的函數(shù)proc_read_super()分配super_block,inode,dentry;(a)其中super_block是在函數(shù)read_super中新生成的;
(b)inode是調(diào)用函數(shù)proc_get_inde()新生成的;
(c)dentry由函數(shù)d_alloc_root()創(chuàng)建的;
注:根目錄的inode和dentry創(chuàng)建的依據(jù)是一個proc_dir_entry結(jié)構(gòu)proc_root,這個結(jié)構(gòu)相當(dāng)于一般文件系統(tǒng)中硬盤上的(不是內(nèi)存中的inode或dentry結(jié)構(gòu))目錄項之類的東西。
(3) 調(diào)用add_vfsmnt()創(chuàng)建vfsmount結(jié)構(gòu),同時對其進(jìn)行設(shè)置(如和super_block的關(guān)系等)。并使得proc文件系統(tǒng)file_system_type數(shù)據(jù)結(jié)構(gòu)的kern_mnt指向這個vfsmount結(jié)構(gòu)。但是這并不意味著path_walk()就能順著路徑名“/proc”找到proc文件系統(tǒng)的根節(jié)點,因為path_walk()并不涉及file_system_type數(shù)據(jù)結(jié)構(gòu),而/proc的inode結(jié)構(gòu)和dentry結(jié)構(gòu)并沒有和新創(chuàng)建的這個vfsmount結(jié)構(gòu)聯(lián)系起來。
2. 所以,光調(diào)用kern_mount()還不夠,還得由系統(tǒng)調(diào)用的初始化進(jìn)程從內(nèi)核外部調(diào)用系統(tǒng)調(diào)用mount(),再安裝一次,通常的命令行為:mount –nvt proc/dev/null /proc,也就是說,把建立再“空設(shè)備”/dev/null上的proc文件系統(tǒng)安裝再節(jié)點/proc 上。
在mount()中,因為file_system_type結(jié)構(gòu)中FS-SINGLE標(biāo)志位為1,所以要調(diào)用get_sb_single()來得到相應(yīng)的超級塊,其方法和別的不同(別的都是從設(shè)備上讀),代碼中通過file_system_type結(jié)構(gòu)中的指針kern_mnt取得文件系統(tǒng)vfsmount結(jié)構(gòu),從而取得其super_block結(jié)構(gòu),而這個關(guān)系正是在kern_mount()中設(shè)置好的。
Mount()中其他的操作就和普通的文件系統(tǒng)的安裝無異了。這樣就把proc文件系統(tǒng)安裝到了節(jié)點/proc上。
3. 因為整個proc文件系統(tǒng)都不存在于設(shè)備上,所以不光是它的根節(jié)點需要在內(nèi)存中創(chuàng)造出來,自根節(jié)點以下的所以節(jié)點全都需要在運行時加以創(chuàng)建,這是由內(nèi)核在初始化時調(diào)用proc_root_init()完成的。
(1) 首先是直接在/proc下面的葉子節(jié)點,即文件節(jié)點,這是由proc_misc_init()創(chuàng)建的。
函數(shù)proc_misc_init()調(diào)用函數(shù)create_proc_read_entry()進(jìn)行分配結(jié)構(gòu),而create_proc_read_entry()則調(diào)用函數(shù)create_proc_entry(),下面對函數(shù)create_proc_entry()進(jìn)行解析:
a) 調(diào)用函數(shù)xlate_proc_name()返回父親節(jié)點的proc_dir_entry結(jié)構(gòu);
b) 調(diào)用函數(shù)kmalloc()分配自己的proc_dir_entry結(jié)構(gòu);
c) 對自己的proc_dir_entry結(jié)構(gòu)進(jìn)行初始化;
d) 調(diào)用函數(shù)proc_register()對自己的proc_dir_entry結(jié)構(gòu)進(jìn)行注冊登記,即掛到父親節(jié)點的proc_dir_entry結(jié)構(gòu)內(nèi)的subdir隊列中;
(2) 創(chuàng)建三個特殊的文件節(jié)點,這三個文件是:kmsg、kcore、profile;這些文件的創(chuàng)建直接調(diào)用create_proc_entry();
(3) 創(chuàng)建直接在/proc目錄中的子目錄,如:net,fs,dirver等;這些子目錄都是通過proc_mkdir()創(chuàng)建的。
(4) 除了這些子目錄之外,就只有/proc/tty是特殊的,因為其他的只有兩層目錄/proc/dirname,只有/proc/tty是一顆子樹,即下面還有目錄,所以要專門創(chuàng)建,調(diào)用的函數(shù)是:proc_tty_init();
(5) 此外,如果系統(tǒng)不采用傳統(tǒng)的基于主設(shè)備號/次設(shè)備號的/dev設(shè)備(文件)目錄,而采用樹狀的設(shè)備目錄/device_tree,則還要在proc_root_init()中創(chuàng)建/device_tree子樹。這是由proc_device_init()完成的。
4./porc文件系統(tǒng)的目錄搜尋
注:/proc文件系統(tǒng)中,除了根節(jié)點外,其他節(jié)點只有proc_dir_entry 結(jié)構(gòu),沒有dentry結(jié)構(gòu)和inode結(jié)構(gòu)。
1)搜尋/proc/loadavg:
(1) 調(diào)用path_walk(),到根節(jié)點后,要調(diào)用函數(shù)cached_lookup(),先在內(nèi)存搜索下一個節(jié)點的dentry結(jié)構(gòu),如果沒在內(nèi)存中找到,就從設(shè)備上讀取,對應(yīng)的函數(shù)是real_lookup();
(2) 從設(shè)備上的讀操作具體依賴于其父親節(jié)點的inode結(jié)構(gòu)中的指針I(yè)_op指向那一個inode_operations數(shù)據(jù)結(jié)構(gòu)。對于節(jié)點/proc,它的I_op指針指向proc_root_inode_operations,這是在它的proc_dir_entry結(jié)構(gòu)proc_root中靜態(tài)定義好的。
(3) /proc文件系統(tǒng)對應(yīng)的讀inode節(jié)點的函數(shù)是proc_lookup(),這個函數(shù)根據(jù)要查找節(jié)點的proc_dir_dentry結(jié)構(gòu),填充一個dentry結(jié)構(gòu),創(chuàng)建一個inode結(jié)構(gòu),然后返回。
(4) 以后的操作就和一般節(jié)點的path_walk()沒什么區(qū)別了。
(5) 下面對其讀操作進(jìn)行解析:
(a) 為讀文件提供的操作函數(shù)是proc_file_read(),這是一個為proc特殊文件通用的函數(shù)。
(b) 從代碼中可以看出,具體的讀操作是通過該節(jié)點的proc_dir_entry結(jié)構(gòu)中的函數(shù)指針get_info或read_proc提供的。其中g(shù)et_info是為了與老一版本兼容而保留的,現(xiàn)在都已改用read_proc。
(c) 對于/proc/loadavg來說,讀文件指針指向loadavg_read_proc();它的作用就是將數(shù)組avenrum[]中積累的在過去1分鐘、5分鐘以及15分鐘內(nèi)的系統(tǒng)平均CPU負(fù)荷等統(tǒng)計信息通過sprintf()“打印”到緩沖區(qū)頁面中。
(d) 在函數(shù)proc_file_read()中,調(diào)用該節(jié)點讀函數(shù)讀完以后,將把讀的信息通過函數(shù)copy_to_user(),拷貝的用戶空間。
2)搜尋/proc/self/cwd;
(1) 同上,調(diào)用proc_root_lookup()->proc_pid_lookup();
注:
a)對于有proc_dir_entry結(jié)構(gòu)的節(jié)點,即向proc_root登記而掛入了其隊列中的節(jié)點,也就是上一種情景,其查找目標(biāo)節(jié)點所調(diào)用的函數(shù)依次是:
path_walk()->real_lookup()->proc_root_lookup()->proc_lookup();
注意:在real_lookup()中分配dentry結(jié)構(gòu),proc_root_lookup()是根據(jù)inode節(jié)點中提供的操作,在proc_lookup()中分配inode結(jié)構(gòu)。
b)另一種情況是對應(yīng)于當(dāng)前系統(tǒng)中的各個進(jìn)程而并不存在proc_dir_entry結(jié)構(gòu)的節(jié)點。其查找目標(biāo)節(jié)點所調(diào)用的函數(shù)依次是:
path_walk()->real_lookup()->proc_root_lookup()->proc_pid_lookup();
注意:proc_lookup()和proc_pid_lookup()都在函數(shù)proc_root_lookup()中。
(2)從proc_root_lookup()返回到path_walk()中以后,接著要檢查和處理兩件事,第一件事新找到的節(jié)點是否為安裝點;第二件就是它是否是一個鏈接點。這正是我們所關(guān)心的,因為/proc/self就是個鏈接點。
(3)對于鏈接點,通過do_follow_link(),調(diào)用該inode結(jié)構(gòu)中的inode_operations結(jié)構(gòu)提供的follow_link函數(shù)指針,尋找目標(biāo)節(jié)點。
Follow_link指向函數(shù)proc_self_follow_link(),這個函數(shù)又調(diào)用vfs_follow_lnk();
(4)要指出的是,在vfs_follow_link()中,將會遞歸的調(diào)用path_walk()來尋找目標(biāo)節(jié)點,所以又會調(diào)用其父親節(jié)點/proc的lookup函數(shù),即proc_root_lookup(),不同的是這次尋找的不是”self”,而是當(dāng)前進(jìn)程的pid字符串。這一次,在proc_root_lookup()中對proc_lookup()的調(diào)用同樣會因為在proc_root的subdir隊列中找不到相應(yīng)的proc_dir_entry結(jié)構(gòu)而失敗,所以也要進(jìn)一步調(diào)用proc_pid_lookup()尋找。可是這一次的節(jié)點名不似乎“self”了,所以走的路線頁就不同了。
(5)這次調(diào)用proc_pid_lookup()所起的作用是將要找的函數(shù)名(當(dāng)前進(jìn)程號的字符串形式)轉(zhuǎn)換成一個無符號整數(shù),然后依此為pid從系統(tǒng)中尋找是否存在相應(yīng)的進(jìn)程。如果找到了相應(yīng)的進(jìn)程,就通過proc_pid_make_inode()為之創(chuàng)建一個inode結(jié)構(gòu),并初始化已經(jīng)分配的dentry結(jié)構(gòu)。
(6)這樣,從path_walk()->do_follow_link()返回以后,就繼續(xù)搜尋下一個節(jié)點“cwd”,這一次搜索的是最后一個節(jié)點,所以跳到:las_component處。
(7)但是,同樣也要調(diào)用函數(shù)real_lookup(),從設(shè)備上讀取inode結(jié)構(gòu)(其實是重新創(chuàng)建一個inode結(jié)構(gòu))。在real_lookup()函數(shù)中要調(diào)用的函數(shù)是其父親節(jié)點的inode_operation結(jié)構(gòu)中的lookup函數(shù)指針指向的函數(shù),這個函數(shù)是proc_base_inode_operation()。
(8)在函數(shù)proc_base_inode_operation()中,創(chuàng)建inode結(jié)構(gòu),并根據(jù)不同的類型進(jìn)行初始化。注意,inode 結(jié)構(gòu)中的union被用作一個proc_inode_info結(jié)構(gòu)proc_I,這個結(jié)構(gòu)中的tast指針在函數(shù)proc_pid_make_inode()中被設(shè)定為該進(jìn)程的task_struct指針。
另外,還要設(shè)置的兩項是:
(a) 將inode結(jié)構(gòu)中的指針I(yè)_op設(shè)置成指向proc_pid_link_inode_operation數(shù)據(jù)結(jié)構(gòu)。
(b) 將inode結(jié)構(gòu)中替換union的proc_inode_info結(jié)構(gòu)中的函數(shù)指針proc_get_link設(shè)置為指向函數(shù)proc_cwd_link();
(9)這樣,從proc_base_inode_operation()返回到(7):real_lookup(),進(jìn)而返回到path_walk()時,nameidata結(jié)構(gòu)中的指針dentry已經(jīng)指向這個特定“cwd”節(jié)點的dentry結(jié)構(gòu),但是接著同樣要受到對其inode結(jié)構(gòu)中的I_op指針以及相應(yīng)inode_operation結(jié)構(gòu)中的指針follow_link的檢查。因為follow_link非0,在(8)被設(shè)置。這樣,就可以找到當(dāng)前工作目錄,其方法見(10);
(10)如前所述,節(jié)點的inode中的union用作一個proc_inode_info結(jié)構(gòu),其中的指針task指向相應(yīng)進(jìn)程的task_struct結(jié)構(gòu),進(jìn)而可以得到這個進(jìn)程的fs_struct結(jié)構(gòu),而這個數(shù)據(jù)結(jié)構(gòu)中的指針pwd即指向該進(jìn)程的”當(dāng)前工作目錄“的dentry結(jié)構(gòu),同時指針pwdmnt指向該目錄所在設(shè)備安裝時的vfsmount結(jié)構(gòu)。
總結(jié)
以上是生活随笔為你收集整理的服务器proc文件,特殊文件系统proc的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux 脚本调用企业微信_shell
- 下一篇: mysql order by按照汉字拼音