特殊文件系統(tǒng)/proc:
作者 :noble;
寫(xiě)作時(shí)間:2002-9-4;
測(cè)試環(huán)境:Red Hat Linux 7.2
聯(lián)系方法:QQ:4440151
Email:noble_shi@21cn.com
1.對(duì)kern_mout()進(jìn)行解析:
(1)調(diào)用函數(shù)get_unnamed_dev()為文件系統(tǒng)/proc文件系統(tǒng)分配一個(gè)設(shè)備號(hào)。
(2)調(diào)用函數(shù)read_super對(duì)應(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ù)是一個(gè)proc_dir_entry結(jié)構(gòu)proc_root,這個(gè)結(jié)構(gòu)相當(dāng)于一般文件系統(tǒng)中硬盤(pán)上的(不是內(nèi)存中的inode或dentry結(jié)構(gòu))目錄項(xiàng)之類(lèi)的東西。
(3)調(diào)用add_vfsmnt()創(chuàng)建vfsmount結(jié)構(gòu),同時(shí)對(duì)其進(jìn)行設(shè)置(如和super_block的關(guān)系等)。并使得proc文件系統(tǒng)file_system_type數(shù)據(jù)結(jié)構(gòu)的kern_mnt指向這個(gè)vfsmount結(jié)構(gòu)。但是這并不意味著path_walk()就能順著路徑名“/proc”找到proc文件系統(tǒng)的根節(jié)點(diǎn),因?yàn)閜ath_walk()并不涉及file_system_type數(shù)據(jù)結(jié)構(gòu),而/proc的inode結(jié)構(gòu)和dentry結(jié)構(gòu)并沒(méi)有和新創(chuàng)建的這個(gè)vfsmount結(jié)構(gòu)聯(lián)系起來(lái)。
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,也就是說(shuō),把建立再“空設(shè)備”/dev/null上的proc文件系統(tǒng)安裝再節(jié)點(diǎn)/proc 上。
在mount()中,因?yàn)閒ile_system_type結(jié)構(gòu)中FS-SINGLE標(biāo)志位為1,所以要調(diào)用get_sb_single()來(lái)得到相應(yīng)的超級(jí)塊,其方法和別的不同(別的都是從設(shè)備上讀),代碼中通過(guò)file_system_type結(jié)構(gòu)中的指針kern_mnt取得文件系統(tǒng)vfsmount結(jié)構(gòu),從而取得其super_block結(jié)構(gòu),而這個(gè)關(guān)系正是在kern_mount()中設(shè)置好的。
Mount()中其他的操作就和普通的文件系統(tǒng)的安裝無(wú)異了。這樣就把proc文件系統(tǒng)安裝到了節(jié)點(diǎn)/proc上。
3.因?yàn)檎麄€(gè)proc文件系統(tǒng)都不存在于設(shè)備上,所以不光是它的根節(jié)點(diǎn)需要在內(nèi)存中創(chuàng)造出來(lái),自根節(jié)點(diǎn)以下的所以節(jié)點(diǎn)全都需要在運(yùn)行時(shí)加以創(chuàng)建,這是由內(nèi)核在初始化時(shí)調(diào)用proc_root_init()完成的。
(1)首先是直接在/proc下面的葉子節(jié)點(diǎn),即文件節(jié)點(diǎn),這是由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(),下面對(duì)函數(shù)create_proc_entry()進(jìn)行解析:
a)調(diào)用函數(shù)xlate_proc_name()返回父親節(jié)點(diǎn)的proc_dir_entry結(jié)構(gòu);
b)調(diào)用函數(shù)kmalloc()分配自己的proc_dir_entry結(jié)構(gòu);
c)對(duì)自己的proc_dir_entry結(jié)構(gòu)進(jìn)行初始化;
d)調(diào)用函數(shù)proc_register()對(duì)自己的proc_dir_entry結(jié)構(gòu)進(jìn)行注冊(cè)登記,即掛到父親節(jié)點(diǎn)的proc_dir_entry結(jié)構(gòu)內(nèi)的subdir隊(duì)列中;
(2)創(chuàng)建三個(gè)特殊的文件節(jié)點(diǎn),這三個(gè)文件是:kmsg、kcore、profile;這些文件的創(chuàng)建直接調(diào)用create_proc_entry();
(3)創(chuàng)建直接在/proc目錄中的子目錄,如:net,fs,dirver等;這些子目錄都是通過(guò)proc_mkdir()創(chuàng)建的。
(4)除了這些子目錄之外,就只有/proc/tty是特殊的,因?yàn)槠渌闹挥袃蓪幽夸?proc/dirname,只有/proc/tty是一顆子樹(shù),即下面還有目錄,所以要專(zhuān)門(mén)創(chuàng)建,調(diào)用的函數(shù)是:proc_tty_init();
(5)此外,如果系統(tǒng)不采用傳統(tǒng)的基于主設(shè)備號(hào)/次設(shè)備號(hào)的/dev設(shè)備(文件)目錄,而采用樹(shù)狀的設(shè)備目錄/device_tree,則還要在proc_root_init()中創(chuàng)建/device_tree子樹(shù)。這是由proc_device_init()完成的。
4./porc文件系統(tǒng)的目錄搜尋
注:/proc文件系統(tǒng)中,除了根節(jié)點(diǎn)外,其他節(jié)點(diǎn)只有proc_dir_entry 結(jié)構(gòu),沒(méi)有dentry結(jié)構(gòu)和inode結(jié)構(gòu)。
1)搜尋/proc/loadavg:
(1)調(diào)用path_walk(),到根節(jié)點(diǎn)后,要調(diào)用函數(shù)cached_lookup(),先在內(nèi)存搜索下一個(gè)節(jié)點(diǎn)的dentry結(jié)構(gòu),如果沒(méi)在內(nèi)存中找到,就從設(shè)備上讀取,對(duì)應(yīng)的函數(shù)是real_lookup();
(2)從設(shè)備上的讀操作具體依賴(lài)于其父親節(jié)點(diǎn)的inode結(jié)構(gòu)中的指針I(yè)_op指向那一個(gè)inode_operations數(shù)據(jù)結(jié)構(gòu)。對(duì)于節(jié)點(diǎn)/proc,它的I_op指針指向proc_root_inode_operations,這是在它的proc_dir_entry結(jié)構(gòu)proc_root中靜態(tài)定義好的。
(3)/proc文件系統(tǒng)對(duì)應(yīng)的讀inode節(jié)點(diǎn)的函數(shù)是proc_lookup(),這個(gè)函數(shù)根據(jù)要查找節(jié)點(diǎn)的proc_dir_dentry結(jié)構(gòu),填充一個(gè)dentry結(jié)構(gòu),創(chuàng)建一個(gè)inode結(jié)構(gòu),然后返回。
(4)以后的操作就和一般節(jié)點(diǎn)的path_walk()沒(méi)什么區(qū)別了。
(5)下面對(duì)其讀操作進(jìn)行解析:
(a)為讀文件提供的操作函數(shù)是proc_file_read(),這是一個(gè)為proc特殊文件通用的函數(shù)。
(b)從代碼中可以看出,具體的讀操作是通過(guò)該節(jié)點(diǎn)的proc_dir_entry結(jié)構(gòu)中的函數(shù)指針get_info或read_proc提供的。其中g(shù)et_info是為了與老一版本兼容而保留的,現(xiàn)在都已改用read_proc。
(c)對(duì)于/proc/loadavg來(lái)說(shuō),讀文件指針指向loadavg_read_proc();它的作用就是將數(shù)組avenrum[]中積累的在過(guò)去1分鐘、5分鐘以及15分鐘內(nèi)的系統(tǒng)平均CPU負(fù)荷等統(tǒng)計(jì)信息通過(guò)sprintf()“打印”到緩沖區(qū)頁(yè)面中。
(d)在函數(shù)proc_file_read()中,調(diào)用該節(jié)點(diǎn)讀函數(shù)讀完以后,將把讀的信息通過(guò)函數(shù)copy_to_user(),拷貝的用戶空間。
2)搜尋/proc/self/cwd;
(1)同上,調(diào)用proc_root_lookup()->proc_pid_lookup();
注:
a)對(duì)于有proc_dir_entry結(jié)構(gòu)的節(jié)點(diǎn),即向proc_root登記而掛入了其隊(duì)列中的節(jié)點(diǎn),也就是上一種情景,其查找目標(biāo)節(jié)點(diǎn)所調(diào)用的函數(shù)依次是:
path_walk()->real_lookup()->proc_root_lookup()->proc_lookup();
注意:在real_lookup()中分配dentry結(jié)構(gòu),proc_root_lookup()是根據(jù)inode節(jié)點(diǎn)中提供的操作,在proc_lookup()中分配inode結(jié)構(gòu)。
b)另一種情況是對(duì)應(yīng)于當(dāng)前系統(tǒng)中的各個(gè)進(jìn)程而并不存在proc_dir_entry結(jié)構(gòu)的節(jié)點(diǎn)。其查找目標(biāo)節(jié)點(diǎn)所調(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é)點(diǎn)是否為安裝點(diǎn);第二件就是它是否是一個(gè)鏈接點(diǎn)。這正是我們所關(guān)心的,因?yàn)?proc/self就是個(gè)鏈接點(diǎn)。
(3)對(duì)于鏈接點(diǎn),通過(guò)do_follow_link(),調(diào)用該inode結(jié)構(gòu)中的inode_operations結(jié)構(gòu)提供的follow_link函數(shù)指針,尋找目標(biāo)節(jié)點(diǎn)。
Follow_link指向函數(shù)proc_self_follow_link(),這個(gè)函數(shù)又調(diào)用vfs_follow_lnk();
(4)要指出的是,在vfs_follow_link()中,將會(huì)遞歸的調(diào)用path_walk()來(lái)尋找目標(biāo)節(jié)點(diǎn),所以又會(huì)調(diào)用其父親節(jié)點(diǎn)/proc的lookup函數(shù),即proc_root_lookup(),不同的是這次尋找的不是”self”,而是當(dāng)前進(jìn)程的pid字符串。這一次,在proc_root_lookup()中對(duì)proc_lookup()的調(diào)用同樣會(huì)因?yàn)樵趐roc_root的subdir隊(duì)列中找不到相應(yīng)的proc_dir_entry結(jié)構(gòu)而失敗,所以也要進(jìn)一步調(diào)用proc_pid_lookup()尋找??墒沁@一次的節(jié)點(diǎn)名不似乎“self”了,所以走的路線頁(yè)就不同了。
(5)這次調(diào)用proc_pid_lookup()所起的作用是將要找的函數(shù)名(當(dāng)前進(jìn)程號(hào)的字符串形式)轉(zhuǎn)換成一個(gè)無(wú)符號(hào)整數(shù),然后依此為pid從系統(tǒng)中尋找是否存在相應(yīng)的進(jìn)程。如果找到了相應(yīng)的進(jìn)程,就通過(guò)proc_pid_make_inode()為之創(chuàng)建一個(gè)inode結(jié)構(gòu),并初始化已經(jīng)分配的dentry結(jié)構(gòu)。
(6)這樣,從path_walk()->do_follow_link()返回以后,就繼續(xù)搜尋下一個(gè)節(jié)點(diǎn)“cwd”,這一次搜索的是最后一個(gè)節(jié)點(diǎn),所以跳到:las_component處。
(7)但是,同樣也要調(diào)用函數(shù)real_lookup(),從設(shè)備上讀取inode結(jié)構(gòu)(其實(shí)是重新創(chuàng)建一個(gè)inode結(jié)構(gòu))。在real_lookup()函數(shù)中要調(diào)用的函數(shù)是其父親節(jié)點(diǎn)的inode_operation結(jié)構(gòu)中的lookup函數(shù)指針指向的函數(shù),這個(gè)函數(shù)是proc_base_inode_operation()。
(8)在函數(shù)proc_base_inode_operation()中,創(chuàng)建inode結(jié)構(gòu),并根據(jù)不同的類(lèi)型進(jìn)行初始化。注意,inode結(jié)構(gòu)中的union被用作一個(gè)proc_inode_info結(jié)構(gòu)proc_I,這個(gè)結(jié)構(gòu)中的tast指針在函數(shù)proc_pid_make_inode()中被設(shè)定為該進(jìn)程的task_struct指針。
另外,還要設(shè)置的兩項(xiàng)是:
(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()時(shí),nameidata結(jié)構(gòu)中的指針dentry已經(jīng)指向這個(gè)特定“cwd”節(jié)點(diǎn)的dentry結(jié)構(gòu),但是接著同樣要受到對(duì)其inode結(jié)構(gòu)中的I_op指針以及相應(yīng)inode_operation結(jié)構(gòu)中的指針follow_link的檢查。因?yàn)閒ollow_link非0,在(8)被設(shè)置。這樣,就可以找到當(dāng)前工作目錄,其方法見(jiàn)(10);
(10)如前所述,節(jié)點(diǎn)的inode中的union用作一個(gè)proc_inode_info結(jié)構(gòu),其中的指針task指向相應(yīng)進(jìn)程的task_struct結(jié)構(gòu),進(jìn)而可以得到這個(gè)進(jìn)程的fs_struct結(jié)構(gòu),而這個(gè)數(shù)據(jù)結(jié)構(gòu)中的指針pwd即指向該進(jìn)程的”當(dāng)前工作目錄“的dentry結(jié)構(gòu),同時(shí)指針pwdmnt指向該目錄所在設(shè)備安裝時(shí)的vfsmount結(jié)構(gòu)。
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)
點(diǎn)擊舉報(bào)。