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