摘 要: Linux內(nèi)核龐大并且可定制性非常高,而且目前市場上并沒有學(xué)習(xí)內(nèi)核的指導(dǎo)軟件。針對(duì)Linux內(nèi)核學(xué)習(xí)難、配置難等問題,對(duì)Linux內(nèi)核模塊進(jìn)行了重新的邏輯劃分,提出了“虛目錄”的概念,并在此基礎(chǔ)上,圍繞Linux內(nèi)核的編譯選項(xiàng)設(shè)計(jì)并開發(fā)了一款學(xué)習(xí)指導(dǎo)軟件。該軟件為一套內(nèi)核編譯配置的輔助工具,虛目錄的劃分清晰地展示了內(nèi)核功能模塊的邏輯劃分,展開虛目錄后,會(huì)顯示與此虛目錄功能配置相關(guān)的所有編譯配置選項(xiàng),使用戶了解到該目錄項(xiàng)的功能是通過哪些編譯選項(xiàng)來配置的。編譯配置選項(xiàng)之間存在著編譯依賴關(guān)系,本軟件可以從源碼的層次(如函數(shù)調(diào)用、變量引用等)來解釋編譯依賴關(guān)系的具體實(shí)現(xiàn)。
關(guān)鍵詞: Linux內(nèi)核;虛目錄;編譯選項(xiàng);交互式圖解軟件
0 引言
Linux操作系統(tǒng)以其開源源碼、高性能和高可靠性等諸多優(yōu)勢(shì)在商業(yè)服務(wù)器和個(gè)人桌面系統(tǒng)中得到日益廣泛的應(yīng)用。近年來,隨著Linux內(nèi)核的不斷發(fā)展和完善,內(nèi)核變得日趨龐大,想深入了解其模塊的劃分以及各個(gè)模塊的功能機(jī)制,也變得相對(duì)困難。在對(duì)Linux體系結(jié)構(gòu)及內(nèi)核功能模塊間關(guān)系分析的基礎(chǔ)上,對(duì)Linux內(nèi)核進(jìn)行了重新的邏輯架構(gòu)劃分,形成“虛目錄”,并且將所有內(nèi)核源碼分配到相應(yīng)的虛目錄下。同時(shí),Linux內(nèi)核的可定制性也是非常高的,它有著數(shù)以萬計(jì)的編譯配置選項(xiàng),針對(duì)不同的需求可以進(jìn)行相應(yīng)的配置。但是,如此大數(shù)目的編譯配置選項(xiàng)也正是問題的所在,不管是初學(xué)者,還是內(nèi)核的精通者,都無法保證能了解到每個(gè)編譯配置選項(xiàng)處于內(nèi)核的哪個(gè)大模塊中,以及編譯選項(xiàng)配置所涉及的文件,等等。通過對(duì)內(nèi)核Kconfig文件的語法分析,識(shí)別出所有的編譯選項(xiàng);通過對(duì)Makefile文件的語法分析,解析出每個(gè)編譯所需要的源碼文件;根據(jù)之前劃分好的虛目錄,以源碼文件作為中介,將編譯選項(xiàng)劃分到相應(yīng)的虛目錄中。這樣就可以很清楚地知道內(nèi)核的哪些功能(虛目錄)需要哪些配置選項(xiàng)去配置,以及每個(gè)配置選項(xiàng)配置需要涉及哪些文件。為了深入到最底層來了解每個(gè)功能以及配置的實(shí)現(xiàn),對(duì)文件進(jìn)行解析,提取出具體函數(shù)以及變量的調(diào)用關(guān)系。虛目錄與編譯選項(xiàng)的關(guān)系,通過逐層細(xì)化,可以很清晰地體現(xiàn)到底層的函數(shù)與變量的關(guān)系上,對(duì)各個(gè)模塊功能的具體實(shí)現(xiàn)進(jìn)行了很好的展示。
使用本交互式圖解軟件可以從細(xì)節(jié)上理清Linux的代碼,從宏觀上的邏輯模塊(虛目錄)層層細(xì)化到小模塊、編譯選項(xiàng)、文件、函數(shù)來快速地認(rèn)識(shí)Linux內(nèi)核以及內(nèi)核各個(gè)模塊間的關(guān)系。
1 虛目錄
1.1 虛目錄概念
本軟件是對(duì)于Linux內(nèi)核架構(gòu)、編譯選項(xiàng)以及各層次關(guān)系的詳細(xì)展示。Linux內(nèi)核架構(gòu)也是整個(gè)軟件依托的基礎(chǔ)。但是Linux內(nèi)核源碼的固有架構(gòu)(目錄劃分)是相對(duì)工程化的,不便于用戶的理解,比如:(1)/kernel文件夾意義不明確,包括多個(gè)功能模塊中的內(nèi)容;(2)對(duì)于arch文件夾,實(shí)際運(yùn)行的Linux內(nèi)核只對(duì)應(yīng)一個(gè)架構(gòu),并且arch文件夾下的內(nèi)容與許多其他功能模塊緊密相關(guān);(3)/mm、/virt/kvm等目錄需要繼續(xù)細(xì)化。
于是本文提出了虛目錄的思想,虛目錄是與實(shí)目錄(即內(nèi)核源碼的相對(duì)路徑)相對(duì)應(yīng)的說法。本文將內(nèi)核源代碼根據(jù)其功能及邏輯關(guān)系進(jìn)行了重新劃分。與實(shí)目錄相比,虛目錄體現(xiàn)了內(nèi)核的邏輯結(jié)構(gòu),虛目錄按照內(nèi)核的功能對(duì)源碼進(jìn)行了重新的組織,更人性化,更體現(xiàn)了源碼的相關(guān)性和功能性。
1.2 虛目錄劃分
對(duì)于虛目錄的劃分,主要是從以下4個(gè)方面來綜合考慮的:
?。?)重點(diǎn)閱讀了Linux內(nèi)核源碼[1-6]。眾所周知,功能相關(guān)聯(lián)或者類似的內(nèi)核代碼大多都在相同目錄下(比如ext4和btrfs都在fs目錄下),因此Linux內(nèi)核源碼的組織方式可以作為模塊劃分的一個(gè)重要參考;
(2)參考關(guān)于內(nèi)核的經(jīng)典書籍(如:《Understanding the Linux Kernel》[1]、《Professional Linux Kernel Architecture》[2]、《Linux內(nèi)核源代碼情景分析》[3]、《Linux操作系統(tǒng)內(nèi)核分析》[4]、《Linux內(nèi)核分析及高級(jí)編程》[5]、《Linux內(nèi)核完全注釋》[6]等),這些書籍的各個(gè)章節(jié)(比如進(jìn)程、內(nèi)存管理、虛擬文件系統(tǒng))既可作為各個(gè)子模塊來進(jìn)行單獨(dú)分析,同時(shí)排版上相鄰的章節(jié)(比如進(jìn)程、中斷等)關(guān)聯(lián)比較緊密,可以考慮劃分到大的模塊中來進(jìn)行分析;
?。?)參考現(xiàn)有的一些模塊劃分手段,比如主流的五大子系統(tǒng)的劃分:內(nèi)存管理、進(jìn)程調(diào)度、進(jìn)程間通信、虛擬文件系統(tǒng)、網(wǎng)絡(luò)子系統(tǒng),以及kernel map圖;
?。?)查看了Linux內(nèi)核的維護(hù)者列表,由相同人員來維護(hù)的內(nèi)容,往往是同一個(gè)子模塊,或者是同一模塊的不同子模塊,這可以作為模塊劃分輔助手段,來幫助確定各個(gè)模塊的劃分;
?。?)與紅帽、阿里等內(nèi)核小組負(fù)責(zé)人進(jìn)行交流,對(duì)于存在疑問、分歧的劃分點(diǎn)進(jìn)行討論,以保證劃分的合理性。
虛目錄相對(duì)于實(shí)目錄,最大的改變?cè)谟谝韵聨c(diǎn):
?。?)/kernel文件夾:實(shí)目錄中,此文件夾的意義并不是很明確,所包含的文件功能涉及很多模塊,需要將其劃分到多個(gè)模塊中;
?。?)/arch文件夾:實(shí)際運(yùn)行的Linux系統(tǒng)中只有一種體系架構(gòu),任一體系結(jié)構(gòu)中包含的文件也是涉及內(nèi)核中的各個(gè)大模塊的,為了保證其他各個(gè)模塊功能的完整性,需要將/arch文件夾下的各個(gè)體系架構(gòu)所包含的文件細(xì)分到其他各大模塊中,剩余的common文件應(yīng)該隸屬于系統(tǒng)管理;
(3)/mm、/virt/kvm等目錄:內(nèi)核中有一些這樣的模塊,從它的機(jī)制來理解,它應(yīng)該是架構(gòu)分層的,但是在實(shí)際的源碼中卻并非如此,它將包含的所有文件平級(jí)地放在了一個(gè)大文件夾下,對(duì)于這樣的模塊,本文按照架構(gòu)和功能對(duì)其重新做了劃分;
?。?)將Linux內(nèi)核分成以下8大模塊:進(jìn)程管理、內(nèi)存管理、系統(tǒng)運(yùn)行、文件系統(tǒng)、網(wǎng)絡(luò)模塊、安全模塊、設(shè)備管理和虛擬化(各個(gè)模塊具體內(nèi)容可以參看下面的模塊圖);同時(shí),由于各個(gè)大模塊的功能和復(fù)雜程度各不相同,為了較好地對(duì)各模塊進(jìn)行分析,并沒有拘泥于嚴(yán)格的模塊分層,而是針對(duì)每個(gè)特定的模塊進(jìn)行了適當(dāng)?shù)姆謱?,從而更好地完成?duì)各個(gè)模塊的分析。
圖1為Linux內(nèi)核虛目錄。
2 軟件架構(gòu)設(shè)計(jì)
本軟件采用B/S架構(gòu),系統(tǒng)架構(gòu)圖如圖2所示。
根據(jù)上面的架構(gòu)設(shè)計(jì),可以把系統(tǒng)分為圖3所示的幾個(gè)模塊。
各模塊設(shè)計(jì)如下:
展示模塊:負(fù)責(zé)前臺(tái)數(shù)據(jù)的展示,可以分為如下兩個(gè)子模塊:
(1)布局模塊:用來計(jì)算各個(gè)矢量圖的坐標(biāo)位置布局,以及拖拽、放大、縮小等之后的布局。
?。?)渲染模塊:將布局模塊計(jì)算好之后的坐標(biāo),使用Raphael的庫來渲染到界面上。
數(shù)據(jù)交互模塊:
?。?)數(shù)據(jù)獲取模塊:從MySQL數(shù)據(jù)庫中獲取數(shù)據(jù),經(jīng)過格式化之后,轉(zhuǎn)換成json格式。
(2)數(shù)據(jù)持久化模塊:提供數(shù)據(jù)持久化接口,可以將數(shù)據(jù)持久化到數(shù)據(jù)庫中。
數(shù)據(jù)爬取模塊:
?。?)數(shù)據(jù)實(shí)體(虛目錄、模塊、文件、函數(shù)、變量)爬?。孩倥廊√撃夸?、模塊以及文件并存儲(chǔ)到數(shù)據(jù)庫之中;②爬取文件中函數(shù)及變量的數(shù)據(jù),并存儲(chǔ)到數(shù)據(jù)庫中。
(2)關(guān)系爬?。号廊。?)中的元素之間的關(guān)系,并存儲(chǔ)到數(shù)據(jù)庫中。
2.1 展示模塊
前端采用Jquery和Raphael在Web界面上畫出所需要的矢量圖,用來表示模塊及模塊之間的關(guān)系,以及函數(shù)/變量之間的關(guān)系。
2.2 數(shù)據(jù)交互模塊
交互式圖解軟件中,使用PHP作為中間層,連接前端界面與后端數(shù)據(jù)庫,前端使用的JavaScript繪圖引擎會(huì)向PHP發(fā)出getJSON請(qǐng)求,PHP解析參數(shù),完成指定類型的數(shù)據(jù)查詢工作,最后形成與前端統(tǒng)一標(biāo)準(zhǔn)json結(jié)構(gòu),利用回調(diào)函數(shù)的形式返回給前端繪圖引擎。其整個(gè)過程如圖4所示。
2.3 數(shù)據(jù)爬取模塊
數(shù)據(jù)爬取模塊主要負(fù)責(zé)數(shù)據(jù)實(shí)體(虛目錄、模塊、文件、函數(shù)、變量)爬取以及這些實(shí)體之間關(guān)系的爬取。爬取模塊邏輯如圖5所示。
整體思想:
(1)根據(jù)Linux內(nèi)核文檔kconfig-language.txt的說明,了解Kconfig語法規(guī)則。在此基礎(chǔ)上,對(duì)Linux內(nèi)核的Kconfig文件做語法分析,爬取出Linux定義的編譯選項(xiàng)及其之間的關(guān)系。
?。?)根據(jù)Linux內(nèi)核文檔makefile.txt和modules.txt的說明,了解Makefile文件中,定義編譯選項(xiàng)對(duì)應(yīng)文件的規(guī)則。在此規(guī)則基礎(chǔ)上,對(duì)Linux內(nèi)核的Makefile文件進(jìn)行語法分析,爬取出編譯選項(xiàng)與文件關(guān)系。
(3)函數(shù)與文件關(guān)系的數(shù)據(jù)爬取方面,可用的現(xiàn)成開源工具較多,經(jīng)過調(diào)研,可以使用到的工具主要有:Clang編譯器、ctags、cscope、eclipse CDT插件、pycparser等?;パa(bǔ)的運(yùn)用這些工具,對(duì)Linux內(nèi)核源碼文件進(jìn)行AST或者符號(hào)標(biāo)記的生成并輸出為中間文件,然后對(duì)這些文件進(jìn)行讀取,可以解析獲得變量、函數(shù)、宏的定義與它們之間的調(diào)用關(guān)系。
在爬取完上述關(guān)系之后,存在一個(gè)比較大的疑問,即虛目錄如何與編譯選項(xiàng)對(duì)應(yīng)虛目錄與編譯選項(xiàng)的對(duì)應(yīng),可以通過文件巧妙的連接起來。對(duì)于劃分好的虛目錄的爬取,得到了虛目錄與文件的層次結(jié)構(gòu);對(duì)于Makefile的爬取,得到了編譯選項(xiàng)與文件的對(duì)應(yīng)關(guān)系。從而,通過一個(gè)編譯選項(xiàng)包含了哪些文件,這些文件位于哪些虛目錄下,就可以確定編譯選項(xiàng)位于哪些虛目錄下了。
3 軟件展示
3.1 實(shí)例場景
內(nèi)核的輸入和輸出都屬于設(shè)備驅(qū)動(dòng)的范疇。在進(jìn)行虛目錄劃分時(shí),將其劃分為設(shè)備驅(qū)動(dòng)下輸入子系統(tǒng)。內(nèi)核的輸入子系統(tǒng)是對(duì)分散、多種不同類別的輸入設(shè)備(如鍵盤、鼠標(biāo)、操縱桿、觸摸屏、加速計(jì)和手寫板)進(jìn)行統(tǒng)一處理的驅(qū)動(dòng)程序。
內(nèi)核輸入子系統(tǒng)的頂層核心編譯選項(xiàng)配置是CONFIG_INPUT,Kconfig中說明如圖6所示。
可以看出,此編譯選項(xiàng)默認(rèn)為打開狀態(tài),任何輸入設(shè)備(mouse、keyboard…)需要連接到系統(tǒng),必須保證其為打開狀態(tài),不然輸入設(shè)備是無法加載驅(qū)動(dòng)的。
相應(yīng)Makefile的定義如圖7所示。
可以看出,配置該選項(xiàng)后,將編譯input.c、input-compat.c、input-mt.c、ff-core.c,通過實(shí)際分析文件可以了解到,這些文件中實(shí)現(xiàn)了諸如input_register_handler(),input_unregister_handler()等INPUT子系統(tǒng)的核心函數(shù)。
而mosue dev很顯然屬于輸入設(shè)備中的一部分。既然CONFIG_INPUT是輸入子系統(tǒng)的頂層核心編譯選項(xiàng),那么實(shí)際的輸入設(shè)備的配置必然是依賴于它的,從Kconfig的定義中發(fā)現(xiàn)/drivers/input/Kconfig片段如圖8所示。
INPUT_MOUSEDEV編譯選項(xiàng)確實(shí)處于INPUT配置的IF條件中(為了方便截圖,用省略號(hào)省去了其他配置說明)。
從相應(yīng)的Makefile的定義(如圖9所示)中可以看出,配置該選項(xiàng)后,將編譯mousedev.c文件,通過實(shí)際分析文件可以了解到,文件中實(shí)現(xiàn)了諸如mousedev_init()、mousedev_exit()等與mouse dev相關(guān)的核心函數(shù)。
實(shí)際分析文件中的函數(shù)如圖10所示。
mousedev_init()在進(jìn)行鼠標(biāo)設(shè)備初始化時(shí),需要調(diào)用input.c的函數(shù)input_register_handler()注冊(cè)一個(gè)鼠標(biāo)類型的Handler,這里的Handler是鼠標(biāo)類設(shè)備的統(tǒng)一處理接口,如圖11所示。
同樣,mousedev_exit()在進(jìn)行鼠標(biāo)設(shè)備的退出時(shí),需要調(diào)用文件input.c的函數(shù)input_unregister_handler()來注銷初始化時(shí)注冊(cè)的鼠標(biāo)Handler。從最低層的函數(shù)調(diào)用中體現(xiàn)出了INPUT_MOUSEDEV對(duì)于INPUT編譯選項(xiàng)的依賴性。
3.2 實(shí)際演示
圖解軟件首頁如圖12所示。
對(duì)上述機(jī)制進(jìn)行說明,當(dāng)進(jìn)行虛目錄劃分時(shí),INPUT子系統(tǒng)被劃分到了設(shè)備驅(qū)動(dòng)中,并且由于input.c和mousedev.c中實(shí)現(xiàn)的函數(shù)都是輸入輸出中通用的機(jī)制,因此二者都被劃分到了虛目錄input-common中,由于虛目錄和編譯選項(xiàng)的包含關(guān)系是通過文件聯(lián)系的,從而包含文件input.c和mousedev.c的編譯選項(xiàng)INPUT和INPUT_MOUSEDEV會(huì)出現(xiàn)在虛目錄input-common中。接下來通過圖解軟件進(jìn)行展示(具體編譯選項(xiàng)位置:設(shè)備驅(qū)動(dòng)->iput->input-common),展開后可以看到(注:以下展示過程中,為了使得所展示的模塊間關(guān)系突出,均使用過濾操作濾除了其他不相關(guān)線條):
(1)INPUT_MOSUEDEV到INPUT編譯選項(xiàng)的依賴關(guān)系如圖13所示。
(2)展開編譯選項(xiàng)INPUT,可以看到INPUT_ MOUSEDEV對(duì)于INPUT編譯選項(xiàng)包含的文件drivers/input/input.c的依賴關(guān)系,如圖14所示。
?。?)展開INPUT_MOUSEDEV編譯選項(xiàng),可以看到,INPUT_MOUSEDE編譯選項(xiàng)包含的文件drivers/input/mousedev.c對(duì)于INPUT編譯選項(xiàng)包含的文件drivers/input/input.c的依賴關(guān)系,如圖15所示。
?。?)展開文件drivers/input/mousedev.c,可以看到drivers/ input/mousedev.c包含的函數(shù)mouse_init和mouse_exit對(duì)于文件drivers/input/input.c的依賴關(guān)系,如圖16所示。
?。?)展開文件drivers/input/input.c,可以看到drivers/input/mousedev.c包含的函數(shù)mouse_init和mouse_exit對(duì)于文件drivers/input/input.c包含的函數(shù)input_register_handler和input_unregister_handler的依賴關(guān)系,如圖17所示。
4 結(jié)論
本文在虛目錄的基礎(chǔ)上,圍繞著編譯選項(xiàng)提出了一套完整的開發(fā)交互式圖解軟件的設(shè)計(jì)方案。一方面,此交互式圖解軟件為Linux學(xué)習(xí)者提供了準(zhǔn)確而便捷的途徑,同時(shí)也為高級(jí)用戶提供了深入探討Linux內(nèi)核的平臺(tái);另一方面,此軟件可以與“在線源碼協(xié)同分析平臺(tái)”和社區(qū)進(jìn)行集成,將Linux體系構(gòu)架的分析成果作為軟件中的編譯選項(xiàng)、文件以及函數(shù)和變量的注釋說明來在線展示,有著非常廣泛的應(yīng)用前景。
參考文獻(xiàn)
[1] DANIEL P B, MARCO C. Understanding the Linux Kernel(3rd Edition)[M]. O′Reilly,2005.
[2] MAUERER W. Professional Linux Kernel Architecture[M]. Wiley, 2008.
[3] 胡希明,毛德操. Linux內(nèi)核源代碼情景分析[M].杭州:浙江大學(xué)出版社,2001.
[4] 陳莉君.Linux 操作系統(tǒng)內(nèi)核分析[M].北京:人民郵電出版社,2000.
[5] 吳國偉,李張,任廣臣.Linux內(nèi)核分析及高級(jí)編程[M].北京:電子工業(yè)出版社,2008.
[6] 趙炯.Linux內(nèi)核完全注釋[M].北京:機(jī)械工業(yè)出版社,2004.