歡迎您光臨本站 註冊首頁

史上最經典的Linux內核學習方法論

←手機掃碼閱讀     火星人 @ 2014-03-09 , reply:0

  Makefile不是Make Love

  從前在學校,混了四年,沒有學到任何東西,每天就是逃課,上網,玩遊戲,睡覺.畢業的時候,人家跟我說Makefile我完全不知,但是一說Make Love我就來勁了,現在想來依然覺得丟人.

  毫不誇張地說,Kconfig和Makefile是我們瀏覽內核代碼時最為依仗的兩個文件.基本上,Linux內核中每一個目錄下邊都會有一個Kconfig文件和一個Makefile文件.對於一個希望能夠在Linux內核的汪洋代碼里看到一絲曙光的人來說,將它們放在怎麼重要的地位都不過分.

  我們去香港,通過海關的時候,總會有免費的地圖和各種指南拿,有了它們在手裡我們才不至於無頭蒼蠅般迷惘的行走在陌生的街道上.即使在內地出去旅遊的時候一般來說也總是會首先找份地圖,當然了,這時就是要去買了,拿是拿不到的,不同的地方有不同的特色, 只不過有的特色是服務,有的特色是索取.

  Kconfig和Makefile就是Linux Kernel迷宮裡的地圖.地圖引導我們去認識一個城市,而Kconfig和Makefile則可以讓我們了解一個Kernel目錄下面的結構.我們每次瀏覽kernel尋找屬於自己的那一段代碼時,都應該首先看看目錄下的這兩個文件.

  利用Kconfig和Makefile尋找目標代碼

  就像利用地圖尋找目的地一樣,我們需要利用Kconfig和Makefile來尋找所要研究的目標代碼.比如我們打算研究U盤驅動的實現,U盤是一種storage設備,我們應該先進入到drivers/usb/storage/目錄.但是該目錄下的文件很多,那麼究竟哪些文件才是我們需要關注的?這時就有必要先去閱讀Kconfig和Makefile文件.

  對於Kconfig文件,我們可以看到下面的選項.

  顯然,這個選項和我們的目的沒有關係.首先它專門針對Datafab公司的產品,其次雖然CompactFlash reader是一種flash設備,但顯然不是U盤.drivers/usb/storage目錄下的代碼是針對usb mass storage這一類設備,而不是針對某一種特定的設備.U盤只是usb mass storage設備中的一種.再比如:

  很顯然這個選項是有關SanDisk產品的,並且針對的是SM卡,同樣不是U盤,我們也不需要去關注.

  事實上,很容易確定,只有選項CONFIG_USB_STORAGE才是我們真正需要關注的.

  接下來閱讀Makefile文件.

  前面通過Kconfig文件的分析,我們確定了只需要去關注CONFIG_USB_STORAGE選項.在Makefile文件里查找CONFIG_USB_STORAGE,從第9行得知,該選項對應的模塊為usbstorage.Kconfig文件里的其他選項我們都不需要關注,Makefile的11~22行可以忽略.第24行意味著我們只需要關注 scsiglue.c、protocol.c、transport.c、usb.c、initializers.c以及它們同名的.h頭文件.

  Kconfig和Makefile很好的幫助我們定位到了所要關注的目標,就像我們到一個陌生的地方要隨身攜帶地圖,當我們學習Linux內核時,也要謹記尋求Kconfig和Makefile的幫助.

  透過現象看本質,獸獸門無非就是一些人體藝術展示.同樣往本質里看過去,學習內核,就是學習內核的源代碼,任何內核有關的書籍都是基於內核,而又不高於內核的.

  既然要學習內核源碼,就要經常對內核代碼進行分析,而內核代碼千千萬,還前仆後繼的不斷往裡加,這就讓大部分人都有種霧裡看花花不見的無助感.不過 不要怕,孔老夫子早就留給我們了應對之策:敏於事而慎於言,就有道而正焉,可謂好學也已.這就是說,做事要踏實才是好學生好同志,要遵循嚴謹的態度,去理 解每一段代碼的實現,多問多想多記.如果抱著走馬觀花,得過且過的態度,結果極有可能就是一邊看一邊丟,沒有多大的收穫.

  假設全國房價上漲1.5%,假設80后局長是農民子弟??,既然我們的人生充滿了假設,那麼我在這裡假設你現在就迫不及待的希望研究內核中USB子系統的實現,應該沒有意見吧?那好,下面就以USB子系統的實現分析為標本看看分析內核源碼應該如何入手.

  分析README

  內核中USB子系統的代碼位於目錄drivers/usb,這個結論並不需要假設.於是我們進入到該目錄,執行命令ls,結果顯示如下:

  atm class core gadget host image misc mon serial storage Kconfig

  Makefile README usb-skeleton.c

  目錄drivers/usb共包含有10個子目錄和4個文件,usb-skeleton.c是一個簡單的USB driver的框架,感興趣的可以去看看,目前來說,它還吸引不了我們的眼球.那麼首先應該關注什麼?如果迎面走來一個ppmm,你會首先看臉、腳還是其 它?當然答案依據每個人的癖好會有所不同.不過這裡的問題應該只有一個答案,那就是Kconfig、Makefile、README.

  README里有關於這個目錄下內容的一般性描述,它不是關鍵,只是幫助你了解.再說了,面對「read我吧read我吧」這麼熱情奔放的呼喚,善良的我們是不可能無動於衷的,先來看看裡面都有些什麼內容.

  這個README文件描述了前邊使用ls命令列出的那10個文件夾的用途.那麼什麼是USB Core?

  Linux內核開發者們,專門寫了一些代碼,負責實現一些核心的功能,為別的設備驅動程序提供服務,比如申請內存,比如實現一些所有的設備都會 需要的公共的函數,並美其名曰USB Core.

  時代總在發展,當年胖楊貴妃照樣迷死唐明皇,而如今人們欣賞的則是林志玲這樣的魔鬼身材.同樣,早期的Linux內核,其結構並不是如今天這般有層 次感,遠不像今天這般錯落有致,那時候drivers/usb/這個目錄下邊放了很多很多文件,USB Core與其他各種設備的驅動程序的代碼都堆砌

  在這裡,後來,怎奈世間萬千的變幻,總愛把有情的人分兩端.於是在drivers/usb/目錄下面出來了 一個core目錄,就專門放一些核心的代碼,比如初始化整個USB系統,初始化Root Hub,初始化主機控制器的代碼,再後來甚至把主機控制器相關的代碼也單獨建了一個目錄,叫host目錄,這是USB主機控制器隨著時代的發展,也開 始有了好幾種,不再像剛開始那樣只有一種,呢,設計者們把一些主機控制器公共的代碼仍然留在core目錄下,而一些各主機控制器單獨的代碼則移到 host目錄下面讓負責各種主機控制器的人去維護.

  那麼USB gadget那?gadget白了說就是配件的意思,主要就是一些內部運行Linux的嵌入式設備,比如PDA,設備本身有USB設備控制器(USB Device Controller),可以將PC,也就是我們的主機作為master端,將這樣的設備作為slave端和主機通過USB進行通信.從主機的觀點來看, 主機系統的USB驅動程序控制插入其中的USB設備,而USB gadget的驅動程序控制外圍設備如何作為一個USB設備和主機通__________信.比如,我們的嵌入式板子上支持SD卡,如果我們希望在將板子通過USB連接到PC 之後,這個SD卡被模擬成U盤,那麼就要通過USB gadget架構的驅動.

  剩下的幾個目錄分門別類的放了各種USB設備的驅動,比如U盤的驅動在storage目錄下,觸摸屏和USB鍵盤滑鼠的驅動在input目錄下,等等.


  我們響應了README的熱情呼喚,它便給予了我們想要的,通過它我們了解了USB目錄里的那些文件夾都有著什麼樣的角色.到現在為止,就只剩下內核的地圖——Kconfig與Makefile兩個文件了.

  有地圖在手,對於在內核中遊盪的我們來說,是件很愉悅的事情,不過,我們的目的是研究內核對USB子系統的實現,而不是特定設備或host controller的驅動,這裡的定位很明顯,USB Core就是我們需要關注的對象,那麼接下來就是要對core目錄中的內容進行定位了.

  分析Kconfig和Makefile

  進入到drivers/usb/core目錄,執行命令ls,結果顯示如下:

  然後執行wc命令,如下所示.

  drivers/usb/core目錄共包括24個文件,16880行代碼.core不愧是core,為大家默默的做這麼多事.不過這麼多文件里不一定都是我們所需要關注的,先拿咱們的地圖來看看接下來該怎麼走.

  先看看Kconfig文件,可以看到下面的選項.

  選項USB_DEVICEFS與usbfs文件系統有關.usbfs文件系統掛載在/proc/bus/usb目錄,顯示了當前連接的所有USB 設 備及匯流排的各種信息,每個連接的USB設備在其中都會有一個對應的文件進行描述.比如文件/proc/bus/usb/xxx/yyy,xxx表示總__________線的 序號,yyy表示設備所在匯流排的地址.不過不能夠依賴它們來穩定地訪問設備,同一設備兩次連接對應的描述文件可能會不同,比如,第一次連接一個設備 時,它可能是002/027,一段時間后再次連接,它可能就已經改變為002/048.

  就好比好不容易你暗戀的mm今天見你的時候對你拋了個媚眼,你心花怒放,趕快去買了100塊彩票慶祝,到第二天再見到她的時候,她對你說你是誰啊,你悲痛欲絕的刮開那100塊彩票,上面清一色的謝謝你.

  usbfs文件系統並不屬於USB子系統實現的核心部分,與之相關的代碼我們可以不必關注.

  這一項是有關USB設備的掛起和恢復.開發USB的人都是節電節能的好孩子,協議里就規定了,所有的設備都必須支持掛起狀態,就是說為了達到節 電的目的,當設備在指定的時間內,如果沒有發生匯流排傳輸,就要進入掛起狀態.當它收到一個non-idle的信號時,就會被喚醒.節約用電從USB做起. 不過這個與主題也沒太大關係,相關代碼也可以不用關注了.

  剩下的還有幾項,不過似乎與咱們關係也不大,還是去看看Makefile.

  Makefile可比Kconfig簡略多了,看起來也更親切點,咱們總是拿的money越多越好,看的代碼越少越好.這裡之會出現 CONFIG_PCI,是通常USB的Root Hub包含在一個PCI設備中.hcd-pci和hcd顧名而思義就知道是說主機控制器的,它們實現了主機控制器公共部分,按

  協議里的說法它們就是 HCDI(HCD的公共介面),host目錄下則實現了各種不同的主機控制器.CONFIG_USB_DEVICEFS前面的Kconfig文件里也見到了,關於usbfs的,與咱們的主題無關,inode.c和devices.c兩個文件也可以不用管了.

  那麼我們可以得出結論,為了理解內核對USB子系統的實現,我們需要研究

  buffer.c、config.c、driver.c、 endpoint.c、file.c、generic.c、hcd.c

  hcd.h、hub.c、message.c、notify.c、otg_whitelist.h、quirks.c、sysfs.c、urb.c 和usb.c文件.

  這麼看來,好像大都需要關注的樣子,沒有減輕多少壓力,不過這裡本身就是USB Core部分,是要做很多的事為咱們分憂的,多點也是可以理解的.


  下面的分析,米盧教練說了,內容不重要,重要的是態度.就像韓局長對待日記的態度那樣,嚴謹而細緻.

  只要你使用這樣的態度開始分析內核,那麼無論你選擇內核的哪個部分作為切入點,比如USB,比如進程管理,在花費相對不算很多的時間之後,你就會發 現你對內核的理解會上升到另外一個高度,一個抱著情景分析,抱著0.1內核完全註釋,抱著各種各樣的內核書籍翻來覆去的看很多遍又忘很多遍都無法達到的高 度.請相信我!讓我們在Linux社區里發出號召:學習內核源碼,從學習韓局長開始!

  態度決定一切:從初始化函數開始

  任小強們說房價高漲從現在開始,股評家們說牛市從5000點開始.他們的開始需要我們的錢袋,我們的開始只需要一台電腦,最好再有一杯茶,伴著幾支小曲兒,不盯著錢總是會比較愜意的.生容易,活容易,生活不容易,總要盯著錢.

  有了地圖Kconfig和Makefile,我們可以在龐大複雜的內核代碼中定位以及縮小了目標代碼的範圍.那麼現在,為了研究內核對USB子系統的實現,我們還需要在目標代碼中找到一個突破口,這個突破口就是USB子系統的初始化代碼.

  針對某個子系統或某個驅動,內核使用subsys_initcall或module_init宏指定初始化函數.在drivers/usb/core/usb.c文件中,我們可以發現下面的代碼.

  940 subsys_initcall(usb_init);

  941 module_exit(usb_exit);

  我們看到一個subsys_initcall,它也是一個宏,我們可以把它理解為module_init,只不過這部分代碼比較核心,開發者們 把它看作一個子系統,而不僅僅是一個模塊.這也很好理解,usbcore這個模塊它代表的不是某一個設備,而是所有USB設備賴以生存的模塊,Linux 中,像這樣一個類別的設備驅動被歸結為一個子系統.比如PCI子系統,比如SCSI子系統,基本上,drivers/目錄下面第一層的每個目錄都算一個子 系統,它們代表了一類設備.

  subsys_initcall(usb_init)的意思就是告訴我們usb_init是USB子系統真正的初始化函數,而usb_exit() 將是整個USB子系統的結束時的清理函數.於是為了研究USB子系統在內核中的實現,

  我們需要從usb_init函數開始看起.

  (1)__init標記.

  關於usb_init,第一個問題是,第865行的__init標記具有什麼意義?

  寫過驅動的應該不會陌生,它對內核來說就是一種暗示,表明這個函數僅在初始化期間使用,在模塊被裝載之後,它佔用的資源就會釋放掉用作它處.它的暗 示你懂,可你的暗示,她卻不懂或者懂裝不懂,多麼讓人感傷.它在自己短暫的一生中一直從事繁重的工作,吃的是草吐出的是牛奶,留下的是整個USB子系統的 繁榮.

  受這種精神所感染,我覺得__________有必要為它說的更多些.__init的定義在include/linux/init.h文件里43 #define __init __attribute__ ((__section__ (".init.text")))

  好像這裡引出了更多的疑問,__attribute__是什麼?Linux內核代碼使用了大量的GNU C擴展,以至於GNU C成為能夠編譯內核的唯一編譯器,GNU C的這些擴展對代碼優化、目標代碼布局、安全檢查等方面也提供了很強的支持.而__attribute__就是這些擴展中的一個,它主要被用來聲明一些特殊的屬性,這些屬性主要被用來指示編譯器進行特定方面的優化和更仔細的代碼檢查.GNU C支持十幾個屬性,section是其中的一個,我們查看GCC的手冊可以看到下面的描述

  『section ("section-name")'

  Normally, the compiler places the code it generates in the `text' section. Sometimes, however, you need additional sections, or you need certain particular functions to appear in special sections.The `section' attribute specifies that a function lives in a particular section. For example, the declaration:extern void foobar (void) __attribute__ ((section ("bar")));puts the function 『foobar' in the 『bar' section.Some file formats do not support arbitrary sections so the 『section' attribute is not available on all platforms. If you need to map the entire contents of a module to a particular section, consider using the facilities of the linker instead.

  通常編譯器將函數放在.text節,變數放在.data或.bss節,使用section屬性,可以讓編譯器將函數或變數放在指定的節中.那麼前面 對__init的定義便表示將它修飾的代碼放在.init.text節.連接器可以把相同節的代碼或數據安排在一起,比如__init修飾的所有代碼都會 被放在.init.text節里,初始化結束后就可以釋放這部分內存.

  問題可以到此為止,也可以更深入,即內核又是如何調用到這些__init修飾的初始化函數?要回答這個問題,還需要回顧一下subsys_initcall宏,它也在include/linux/init.h里定義

  125 #define subsys_initcall(fn) __define_initcall("4",fn,4)

  這裡又出現了一個宏__define_initcall,它用於將指定的函數指針fn放到initcall.init節里 而對於具體的subsys_initcall宏,則是把fn放到.initcall.init的子節.initcall4.init里.要弄清楚.initcall.init、.init.text和.initcall4.init這樣的東東,我們還需要了解一點內核可執行文件相關的概念.

  內核可執行文件由許多鏈接在一起的對象文件組成.對象文件有許多節,如文本、數據、init數據、bass等等.這些對象文件都是__________由一個稱為鏈接器 腳本的文件鏈接並裝入的.這個鏈接器腳本的功能是將輸入對象文件的各節映射到輸出文件中;換句話說,它將所有輸入對象文件都鏈接到單一的可執行文件中,將 該可執行文件的各節裝入到指定地址處. vmlinux.lds是存在於arch// 目錄中的內核鏈接器腳本,它負責鏈接內核的各個節並將它們裝入內存中特定偏移量處.

  我可以負責任的告訴你,要看懂vmlinux.lds這個文件是需要一番功夫的,不過大家都是聰明人,聰明人做聰明事,你需要做的只是搜索initcall.init,然後便會看到似曾相識的內容

  這裡的__initcall_start指向.initcall.init節的開始,__initcall_end指向它的結尾.而.initcall.init節又被分為了7個子節,分別是

  我們的subsys_initcall宏便是將指定的函數指針放在了.initcall4.init子節.其它的比如core_initcall將函數指針放在.initcall1.init子節,device_initcall將函數指針放在了.initcall6.init子節等等,都可以從 include/linux/init.h文件找到它們的定義.各個位元組的順序是確定的,即先調用.initcall1.init中的函數指針再調 用.initcall2.init中的函數指針,等等.__init修飾的初始化函數在內核初始化過程中調用的順序和.initcall.init節里函 數指針的順序有關,不同的初始化函數被放在不同的子節中,因此也就決定了它們的調用順序.

  至於實際執行函數調用的地方,就在/init/main.c文件里,內核的初始化么,不在那裡還能在哪裡,裡面的do_initcalls函數會直接用到這裡的__initcall_start、__initcall_end來進行判斷.


  (2)模塊參數.

  關於usb_init函數,第二個問題是,第868行的nousb表示什麼?

  知道C語言的人都會知道nousb是一個標誌,只是不同的標誌有不一樣的精彩,這裡的nousb是用來讓我們在啟動內核的時候通過內核參數去掉 USB子系統的,Linux社會是一個很人性化的世界,它不會去逼迫我們接受USB,一切都只關乎我們自己的需要.不過我想我們一般來說是不會去指定nousb的吧.如果你真的指定了nousb,那它就只會幽怨的說一句「USB support disabled」,然後退出usb_init.

  nousb在drivers/usb/core/usb.c文件中定義為:

  static int nousb; /* Disable USB when built into kernel image */

  module_param_named(autosuspend, usb_autosuspend_delay, int, 0644);

  MODULE_Parm_DESC(autosuspend, "default autosuspend delay");

  從中可知nousb是個模塊參數.關於模塊參數,我們都知道可以在載入模塊的時候可以指定,但是如何在內核啟動的時候指定?

  打開系統的grub文件,然後找到kernel行,比如:

  kernel /boot/vmlinuz-2.6.18-kdb root=/dev/sda1 ro splash=silent vga=0x314

  其中的root,splash,vga等都表示內核參數.當某一模塊被編譯進內核的時候,它的模塊參數便需要在kernel行來指定,格式為「模塊名.參數=值」,比如:

  modprobe usbcore autosuspend=2

  對應到kernel行,即為 :

  usbcore.autosuspend=2

  通過命令「modinfo -p ${modulename}」可以得知一個模塊有哪些參數可以使用.同時,對於已經載入到內核里的模塊,它們的模塊參數會列舉在/sys/module /${modulename}/parameters/目錄下面,可以使用「echo -n ${value} > /sys/module/${modulename}/parameters/$

  {parm}」這樣的命令去修改.

  (3)可變參數宏.

  關於usb_init函數,第三個問題是,pr_info如何實現與使用?pr_info只是一個列印信息的可辨參數宏,printk的變體,在include/linux/kernel.h里定義:

  242 #define pr_info(fmt,arg...)

  243 printk(KERN_INFO fmt,##arg)

  99年的ISO C標準里規定了可變參數宏,和函數語法類似,比如

  #define debug(format, ...) fprintf (stderr, format, __VA_ARGS__)裡面的「…」就表示可變參數,調用時,它們就會替代宏體里的__VA_ARGS__.GCC總是會顯得特立獨行一些,它支持更複雜的形式,可以給可變參數取個名字,比如#define debug(format, args...) fprintf (stderr, format, args)

  有了名字總是會容易交流一些.是不是與pr_info比較接近了?除了『##』,它主要是針對空參數的情況.既然說是可變參數,那傳遞空參數也總是可以的,空即是多,多即是空,股市裡的哲理這裡同樣也是適合的.如果沒有『##』,傳遞空參數的時候,比如debug ("A message");展開后,裡面的字元串後面會多個多餘的逗號.這個逗號你應該不會喜歡,而『##』則會使預處理器去掉這個多餘的逗號.

  關於usb_init函數,上面的三個問題之外,餘下的代碼分別完成usb各部分的初始化,接下來就需要圍繞它們分別進行深入分析.這裡只是演示如何入手分析,展示的只是一種態度,具體的深入分析就免了吧.

  對於學習來說,無論是在學校的課堂學習,還是這裡說的內核學習,效果好或者壞,最主要取決於兩個方面——方法論和心理.注意,我無視了智商的差異,這玩意兒玄之又玄,岔開了說,屬於迷信的範疇.

  前面又是Kernel地圖,又是如何入手,說的都是方法論的問題,那麼這裡要面對的就主要是心理上的問題.

  而心理上的問題主要有兩個,一個是盲目,就是在能夠熟練適用Linux之前,對Linux為何物還說不出個道道來,就迫不及待的盲目的去研究內核的 源代碼.這一部分人會覺得既然是學習內核,那麼耗費時間在熟悉Linux的基本操作上純粹是浪費寶貴的時間和感情.不過這樣雖然很有韓峰同志的熱情和幹勁 兒,但明顯走入了一種心理誤區.重述Linus的那句話:要先會使用它.

  第二個就是恐懼.人類進化這麼多年,面對複雜的物體和事情還是總會有天生的懼怕感,體現在內核學習上面就是:那麼龐大複雜的內核代碼,讓人面對起來該情何以堪啊!

  有了這種恐懼無力感存在,心理上就會去排斥面對接觸內核源碼,寧願去抱著情景分析,搜集各種各樣五花八門的內核書籍放在那裡屯著,看了又忘,忘了又看,也不大情願去認真細緻得瀏覽源碼.

  這個時候,我們在心理上是脆弱得,我們忘記了芙蓉姐姐,工行女之紅起來,不是她們有多好,而是她們得心理足夠堅強.是的,除了向韓局長學習態度,我們還要向湧現出來的無數個芙蓉姐姐和工行女學習堅強的心理.

  有必要再強調一次,學習內核,就是學習內核的源代碼,任何內核有關的書籍都是基於內核,而又不高於內核的.內核源碼本身就是最好的參考資料,其他任何經典或非經典的書最多只是起到個輔助作用,不能也不應該取代內核代碼在我們學習過程中的主導地位.

  「世界上最缺的不是金錢,而是資源.」當我在一份報紙上看到這句大大標題時,我的第一反應是——作者一定是個自然環保主義者,然後我在羞愧得反省自身的同時油然生出一股對這樣的無產主義理想者無比崇敬的情緒來.於是,我繼續往下看,「因此在XXX還未正式面市之時,前來諮詢的客戶已經不少,這些有眼光的購房者明白,誰能在目前最好的購房機會下最大化地佔有絕版資 源,誰就掌控了未來財富流向.」(為了避免做廣告的嫌疑,請允許我使用XXX代替該樓盤的名字.)頓時,我悟道了!

  其實,韓峰同志已經在日記里告訴了我們資源的重要性,因此我們在學習韓峰同志嚴謹細緻的態度同時,還要領悟他對資源的靈活運用.只有在以內核源碼為中心,堅持各種學習資源的長期建設不動搖,才能達到韓局長那樣的高度,俯視Linux內核世界里的人生百態.

  注意,這個觀點與前面所說的學習效果主要取決於方法論和心理兩個方面並不矛盾,它們屬於不同層次上的問題.


  內核文檔

  內核代碼中包含有大量的文檔,這些文檔對於學習理解內核有著不可估量的價值,記住,在任何時候,它們在我們心目中的地位都應該高於那些各式的內核參考書.下面是一些內核新人所應該閱讀的文檔.

  README

  這個文件首先簡單介紹了Linux內核的背景,然後描述了如何配置和編譯內核,還告訴我們出現問題時應該怎麼辦.

  Documentation/Changes這個文件給出了用來編譯和使用內核所需要的最小軟體包列表.

  Documentation/CodingStyle這個文件描述了內核首選的編碼風格,所有代碼都應該遵守裡面定義的規範.

  Documentation/SubmittingPatches

  Documentation/SubmittingDrivers

  Documentation/SubmitChecklist

  這三個文件都是描述如何提交代碼的,其中SubmittingPatches給出創建和提交補丁的過程,

  SubmittingDrivers描述了如何將 設備驅動提交給2.4、2.6等不同版本的內核樹,SubmitChecklist則描述了提交代碼之前需要check自己的代碼應該遵守的某些事項.

  Documentation/stable_api_nonsense.txt這個文件解釋了為什麼內核沒有一個穩定的內部API(到用戶空間的介面——系統調用——是穩定的),它對於理解Linux的開發哲學至關重要,對於將開發平台從其他操作系統轉移到Linux的開發者來說也很重要.

  Documentation/stable_kernel_rules.txt解釋了穩定版內核(stable releases)發布的規則,以及如何將補丁提交給這些版本.

  Documentation/SecurityBugs

  內核開發者對安全性問題非常關注,如果你認為自己發現了這樣的問題,可以根據這個文件中給出的聯繫方式提交bug,以便能夠儘可能快的解決這個問題.

  Documentation/kernel-docs.txt這個文件列舉了很多內核相關的文檔和書籍,裡面不乏經典之作.

  Documentation/applying-patches.txt這個文件回答了如何為內核打補丁.

  Documentation/bug-hunting這個文件是有關尋找、提交、修正bug的.

  Documentation/HOWTO這個文件將指導你如何成為一名內核開發者,並且學會如何同內核開發社區合作.它儘可能不包括任何關於內核編程的技術細節,但會給你指引一條獲得這些知識的正確途徑.


  經典書籍

  待到山花爛漫時,還是那些經典在微笑.

  有關內核的書籍可以用汗牛充棟來形容,不過只有一些經典的神作經住了考驗.首先是5本久經考驗的神作(個人概括為「2 1 2」,第一個2是指2本全面講 解內核的書,中間的1指1本講解驅動開發的書,後面的2則指2本有關內核具體子系統的書,你是否想到了某某廣告里三個人突然站起單臂齊舉高呼「1比1 比 1」的場景?).

  《Linux內核設計與實現》

  簡稱LKD,從入門開始,介紹了諸如進程管理、系統調用、中斷和中斷處理程序、內核同步、時

  間管理、內存管理、地址空間、調試技術等方面,內容比較淺顯易懂,個人認為是內核新人首先必

  讀的書籍.新人得有此書,足矣!

  《深入理解Linux內核》

  簡稱ULK,相比於LKD的內容不夠深入、覆蓋面不廣,ULK要深入全面得多.

  前面這兩本,一本提綱挈領,一本全面深入.

  《Linux設備驅動程序》

  簡稱LDD,驅動開發者都要人手一本了.

  《深入理解Linux虛擬內存管理》

  簡稱LVMM,是一本介紹Linux虛擬內存管理機制的書.如果你希望深入的研究Linux的內存管理

  子系統,仔細的研讀這本書無疑是最好的選擇.

  《深入理解LINUX網路內幕》

  一本講解網路子系統實現的書,通過這本書,我們可以了解到Linux內核是如何實現複雜的網路功能的.(忘了聲明下,我這列出來的書名是中文的,但是並不代表我建議大家去看他們的中文版,其中有的翻譯的實在太??了,呵呵)

  這5本書各有側重,正如下面的圖所展示的那樣,恰好代表了個人一直主張的內核學習方法:首先通過LKD或ULK了解內核的設計實現特點,對內核有個整體全局的認識和理解,然後可分為兩個岔路,如果從事驅動開發,則鑽研LDD,如果希望對內核不是泛泛而談而是有更深入的理解,則可以選擇一個自己感興趣的子系統,仔細分析它的代碼,不懂的地方就通過社區、郵件列表或者直接發Email給maintainer請教等途徑弄懂,切勿得過且過,這樣分析下來,對同步、中斷等等內核的很多機制也同樣會非常了解,俗話說的一通則百通就是這個道理.當然,如果你選擇研究的是內存管理或者網路,則可以有上面的兩本書可以學習,如果是其他子系統可能就沒有這麼好的運氣了.

  內核社區

  最近幾年,社區網站非常的熱火,不過此社區非彼社區.

  Linux最大的一個優勢就是它有一個緊密團結了眾多使用者和開發者的社區,它的目標就是提供盡善盡美的內核.內核社區的中心是內核郵件列表(Linux Kernel Mailing List,LKML),我們可以在http://vger.kernel.org/vger-lists.html#linux-kernel上面看到訂閱這個郵件列表的細節.

  內核郵件列表的流量很大,每天都有幾百條消息,這裡是大牛們的戰場,小牛們的天堂,任何一個內核開發者都可以從中受益非淺.除了LKML,大多數子系統也有自己獨立的郵件列表來協調各自的開發工作,比如USB子系統的郵件列表可以在http://www.linux-usb.org/mailing.html 上面訂閱.

  其他網路資源

  除了內核郵件列表,還有很多其他的論壇或網站值得我們經常關注.我們要知道,網路上不僅有獸獸和鳳姐,也不僅有犀利哥和韓局長.http://www.kernel.org/ 可以通過這個網站上下載內核的源代碼和補丁、跟蹤內核bug等.http://kerneltrap.org Linux和BSD內核的技術新聞.如果沒時間跟蹤LKML,那麼經常瀏覽kerneltrap是個好主意.http://lwn.net/ Linux weekly news,創建於1997年底的一個Linux新聞站點.http://zh-kernel.org/mailman/listinfo/linux-kernel

這是內核開發的中文郵件列表,裡面活躍著很多內核開發領域的華人,比如Herbert Xu,、Mingming Cao、Bryan Wu等.


[火星人 ] 史上最經典的Linux內核學習方法論已經有972次圍觀

http://coctec.com/docs/linux/show-post-51239.html