如何進行 Linux 核心開發

這是關於此主題的終極文件。它包含如何成為 Linux 核心開發者以及如何學習與 Linux 核心開發社群合作的說明。它儘量不包含任何與核心程式設計技術方面相關的內容,但會幫助你指明正確的方向。

如果本文件中的任何內容過時,請將補丁傳送給此檔案的維護者,其資訊列在文件底部。

引言

那麼,你想學習如何成為一名 Linux 核心開發者嗎?或者你的經理曾告訴你:“去為這個裝置編寫一個 Linux 驅動程式。”本文件的目標是透過描述你需要經歷的過程以及如何與社群合作的提示,來教你實現這一目標所需的一切知識。它還將嘗試解釋社群為何如此運作的一些原因。

核心主要用 C 語言編寫,部分架構相關的部分用匯編語言編寫。核心開發需要對 C 語言有很好的理解。除非你計劃為特定架構進行底層開發,否則不需要組合語言(任何架構)。儘管以下書籍不能完全替代紮實的 C 語言教育和/或多年的經驗,但它們作為參考書是很好的選擇:

  • 《C 程式設計語言》(The C Programming Language),作者 Kernighan 和 Ritchie [Prentice Hall]

  • 《C 語言程式設計實踐》(Practical C Programming),作者 Steve Oualline [O’Reilly]

  • 《C:參考手冊》(C: A Reference Manual),作者 Harbison 和 Steele [Prentice Hall]

核心使用 GNU C 和 GNU 工具鏈編寫。雖然它遵循 ISO C11 標準,但使用了一些標準中沒有的擴充套件。核心是一個獨立的 C 環境,不依賴標準 C 庫,因此 C 標準的某些部分不受支援。不允許任意 long long 型別除法和浮點運算。有時很難理解核心對工具鏈及其所用擴充套件的假設,不幸的是,沒有關於它們的權威參考資料。請查閱 gcc 的資訊頁面 (info gcc) 以獲取相關資訊。

請記住,你正在學習如何與現有的開發社群合作。這是一個由多元化人群組成的群體,對編碼、風格和流程有著高標準。這些標準是隨著時間的推移,基於他們發現最適合如此龐大且地理上分散的團隊的工作方式而建立的。請儘量提前學習這些標準,因為它們有充分的文件記錄;不要期望人們適應你或你公司的工作方式。

文件

Linux 核心原始碼樹包含大量文件,這些文件對於學習如何與核心社群互動非常有價值。當向核心新增新功能時,建議也新增新的文件檔案來解釋如何使用該功能。當核心更改導致核心暴露給使用者空間的介面發生變化時,建議您將資訊或補丁傳送給手冊頁,向手冊頁維護者 alx@kernel.org 解釋此更改,並抄送列表 linux-api@vger.kernel.org

以下是核心原始碼樹中需要閱讀的檔案列表:

Documentation/admin-guide/README.rst

此檔案簡要介紹了 Linux 核心的背景,並描述了配置和構建核心所需的步驟。核心新手應從此處開始。

Documentation/process/changes.rst

此檔案列出了成功構建和執行核心所需的各種軟體包的最低版本。

Documentation/process/coding-style.rst

這描述了 Linux 核心的編碼風格,以及其背後的一些基本原理。所有新程式碼都應遵循此文件中的指南。大多數維護者只會在遵循這些規則的情況下接受補丁,並且許多人也只會在程式碼風格正確的情況下進行審查。

Documentation/process/submitting-patches.rst

此檔案詳細描述瞭如何成功建立和傳送補丁,包括(但不限於):

  • 郵件內容

  • 郵件格式

  • 傳送給誰

遵循這些規則不能保證成功(因為所有補丁都會受到內容和風格的嚴格審查),但不遵循它們幾乎總是會阻礙成功。

其他關於如何正確建立補丁的優秀描述有:

《完美的補丁》(The Perfect Patch)

https://www.ozlabs.org/~akpm/stuff/tpp.txt

《Linux 核心補丁提交格式》(Linux kernel patch submission format)

https://web.archive.org/web/20180829112450/http://linux.yyz.us/patch-format.html

Documentation/process/stable-api-nonsense.rst

此檔案描述了核心中刻意不提供穩定 API 的理由,包括以下幾點:

  • 子系統墊片層(用於相容性?)

  • 驅動程式在作業系統之間的可移植性。

  • 緩解核心原始碼樹內的快速變化(或阻止快速變化)

本文件對於理解 Linux 開發哲學至關重要,對於從其他作業系統開發轉向 Linux 的人來說也非常重要。

Documentation/process/security-bugs.rst

如果您認為在 Linux 核心中發現了安全問題,請遵循本文件中的步驟通知核心開發者,並幫助解決問題。

Documentation/process/management-style.rst

本文件描述了 Linux 核心維護者的運作方式以及其方法論背後的共同精神。對於任何核心開發新手(或任何僅僅對此好奇的人)來說,這都是一篇重要的閱讀材料,因為它解決了許多關於核心維護者獨特行為的常見誤解和困惑。

Documentation/process/stable-kernel-rules.rst

此檔案描述了穩定版核心釋出的規則,以及如果您想將更改納入這些釋出版本之一時該怎麼做。

Documentation/process/kernel-docs.rst

一份與核心開發相關的外部文件列表。如果您未在核心文件中找到所需內容,請查閱此列表。

Documentation/process/applying-patches.rst

一篇很好的介紹,準確描述了補丁是什麼以及如何將其應用於核心的不同開發分支。

核心還擁有大量可以從原始碼本身或從 ReStructuredText 標記(ReST)自動生成的文件,就像本篇一樣。這包括核心 API 的完整描述,以及如何正確處理鎖機制的規則。

所有此類文件都可以透過在核心主原始碼目錄中分別執行以下命令生成為 PDF 或 HTML:

make pdfdocs
make htmldocs

make htmldocs

使用 ReST 標記的文件將在 Documentation/output 生成。它們也可以透過以下命令生成為 LaTeX 和 ePub 格式:

make latexdocs
make epubdocs

make latexpdfdocs

成為核心開發者

https://kernelnewbies.org

它有一個有用的郵件列表,您可以在其中提出幾乎任何型別的基本核心開發問題(提問前請務必先搜尋存檔,以避免重複已回答的問題)。它還有一個 IRC 頻道,您可以用來即時提問,以及大量有用的文件,這些文件對於學習 Linux 核心開發很有幫助。

該網站提供了關於程式碼組織、子系統和當前專案(包括樹內和樹外)的基本資訊。它還描述了一些基本的後勤資訊,例如如何編譯核心和應用補丁。

https://kernelnewbies.org/KernelJanitors

這是一個很好的起點。它描述了 Linux 核心原始碼樹中需要清理和修復的一些相對簡單的問題列表。透過與負責此專案的開發者合作,你將學習如何將補丁提交到 Linux 核心樹的基本知識,如果你還沒有想法,也可能會被指明接下來可以從事的方向。

https://elixir.bootlin.com/

開發流程

  • Linux 核心開發過程目前包含幾個不同的主要核心“分支”以及許多不同的子系統特定核心分支。這些不同的分支是:

  • Linus 的主線樹

  • 帶有多個主版本號的各種穩定樹

  • 子系統特定樹

linux-next 整合測試樹

主線樹

  • 主線樹由 Linus Torvalds 維護,可在 https://kernel.linux.club.tw 或儲存庫中找到。其開發流程如下:

  • 新核心釋出後,將開放一個兩週的視窗期,在此期間維護者可以向 Linus 提交大型差異補丁,通常是那些已經在 linux-next 中包含了幾周的補丁。提交大型更改的首選方式是使用 git(核心的原始碼管理工具,更多資訊可在 https://git-scm.tw/ 找到),但普通補丁也完全可以接受。

  • 兩週後,-rc1 核心釋出,重點是讓新核心儘可能地穩固。此時的大多數補丁都應修復迴歸問題。一直存在的錯誤不是迴歸問題,因此只有在重要的情況下才推動這類修復。請注意,一個全新的驅動程式(或檔案系統)可能會在 -rc1 釋出後被接受,因為只要更改是自包含的且不影響所新增程式碼之外的區域,就不會有引起迴歸的風險。在 -rc1 釋出後,可以使用 git 向 Linus 傳送補丁,但補丁也需要傳送到公共郵件列表進行審查。

  • 每當 Linus 認為當前的 git 樹處於合理且適合測試的狀態時,就會發佈一個新的 -rc 版本。目標是每週釋出一個新的 -rc 核心。

此過程持續到核心被認為“準備就緒”,整個過程大約持續 6 周。

值得一提的是 Andrew Morton 在 linux-kernel 郵件列表中關於核心釋出所寫的內容:

“沒有人知道核心何時釋出,因為它根據已知的錯誤狀態釋出,而不是根據預設的時間表釋出。”

帶有多個主版本號的各種穩定樹

版本號由三部分組成的核心是 -stable 核心。它們包含針對在特定主線版本中發現的安全問題或重大回歸的相對較小且關鍵的修復。穩定系列中的每個版本都會增加版本號的第三部分,同時保持前兩部分不變。

這是為那些想要最新穩定版核心且對幫助測試開發/實驗版本不感興趣的使用者推薦的分支。

穩定樹由“穩定”團隊 <stable@vger.kernel.org> 維護,並根據需要釋出。正常的釋出週期約為兩週,但在沒有緊急問題時可能會更長。而安全相關問題則可能導致釋出幾乎立即進行。

核心樹中的檔案 Documentation/process/stable-kernel-rules.rst 記錄了哪些型別的更改可以接受用於 -stable 樹,以及釋出過程是如何進行的。

子系統特定樹

各個核心子系統的維護者——以及許多核心子系統開發者——都在原始碼倉庫中公開他們的當前開發狀態。這樣,其他人就可以看到核心不同領域正在發生的事情。在開發進展迅速的領域,開發者可能會被要求將他們的提交基於某個子系統核心樹,以便避擴音交與正在進行的其他工作之間的衝突。

這些倉庫大多數是 git 樹,但也使用其他 SCM(原始碼管理系統),或者以 quilt 系列的形式釋出補丁佇列。這些子系統倉庫的地址列在 MAINTAINERS 檔案中。其中許多可以在 https://git.kernel.org/ 瀏覽。

在擬議的補丁被提交到子系統樹之前,它會經過審查,審查主要發生在郵件列表上(請參見下面的相關部分)。對於一些核心子系統,此審查過程透過 patchwork 工具進行跟蹤。Patchwork 提供了一個網頁介面,顯示補丁釋出、對補丁的任何評論或修訂,維護者可以將補丁標記為正在審查、已接受或已拒絕。這些 patchwork 站點大部分列在 https://patchwork.kernel.org/

linux-next 整合測試樹

https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git

透過這種方式,linux-next 概述了下一個合併週期中預計會進入主線核心的內容。歡迎有冒險精神的測試人員對 linux-next 進行執行時測試。

錯誤報告

核心主原始碼目錄中的檔案‘報告問題’描述瞭如何報告可能的核心錯誤,並詳細說明了核心開發者追蹤問題所需的資訊。

管理錯誤報告

將你的 Hacking 技能付諸實踐的最佳方法之一是修復他人報告的錯誤。這不僅有助於使核心更加穩定,你還將學會解決實際問題並提高技能,其他開發者也會注意到你的存在。修復錯誤是獲得其他開發者認可的最佳方式之一,因為沒有多少人喜歡浪費時間修復他人的錯誤。

要處理已報告的錯誤,請找到你感興趣的子系統。檢視 MAINTAINERS 檔案,瞭解該子系統錯誤報告的接收方;通常是郵件列表,很少是錯誤追蹤器。搜尋該位置的存檔以查詢最近的報告,並在你認為合適的地方提供幫助。你可能還想檢視 https://bugzilla.kernel.org 獲取錯誤報告;只有少數核心子系統積極將其用於報告或跟蹤,但整個核心的錯誤都會在那裡歸檔。

郵件列表

https://subspace.kernel.org/subscribing.html

https://lore.kernel.org/linux-kernel/

強烈建議您在向列表釋出您想提出的主題之前,先搜尋存檔。許多已詳細討論過的事項僅記錄在郵件列表存檔中。

大多數單獨的核心子系統也有它們自己的獨立郵件列表,用於進行開發工作。請參閱 MAINTAINERS 檔案,獲取這些列表用於不同組的清單。

https://subspace.kernel.org

https://subspace.kernel.org/etiquette.html

如果多人回覆您的郵件,收件人抄送(CC:)列表可能會變得相當大。沒有充分理由,請不要從抄送列表中刪除任何人,也不要只回複列表地址。請習慣收到兩封郵件,一封來自發件人,一封來自列表,並且不要嘗試透過新增花哨的郵件頭來調整,人們不會喜歡那樣做。

請記住保持回覆的上下文和歸屬完整,將“John Kernelhacker wrote ...:”等行保留在回覆的頂部,並在引用的各個部分之間新增您的陳述,而不是在郵件頂部撰寫。

如果您在郵件中新增補丁,請確保它們是純文字格式且可讀,如 Documentation/process/submitting-patches.rst 中所述。核心開發者不希望處理附件或壓縮補丁;他們可能希望對您補丁的單行進行評論,只有這樣才能實現。請確保您使用的郵件程式不會破壞空格和製表符。一個很好的初步測試是將郵件傳送給自己,然後嘗試自行應用您的補丁。如果不行,請修復您的郵件程式或更換它直到可以正常工作。

最重要的是,請記住尊重其他訂閱者。

與社群合作

  • 核心社群的目標是提供最好的核心。當您提交補丁以供接受時,它將僅根據其技術優點進行審查。那麼,您應該期待什麼呢?

  • 批評

  • 評論

  • 變更請求

  • 解釋說明請求

沉默

請記住,這是將您的補丁納入核心的一部分。您必須能夠接受對補丁的批評和評論,從技術層面評估它們,並重新制作您的補丁,或者提供清晰簡潔的理由說明為什麼不應進行這些更改。如果您的帖子沒有回應,請等待幾天再試一次,有時資訊會在大量郵件中丟失。

  • 你不應該做什麼?

  • 期望你的補丁被毫無疑問地接受

  • 變得防備

  • 忽略評論

在未進行任何請求的更改的情況下重新提交補丁

在一個尋求最佳技術解決方案的社群中,對於補丁的益處總是會有不同的意見。你必須樂於合作,並願意調整你的想法以適應核心。或者至少願意證明你的想法是值得的。請記住,犯錯是可以接受的,只要你願意努力走向正確的解決方案。

您的第一個補丁得到的回覆可能只是一個列出您應該糾正的十幾個問題的列表,這是正常的。這並意味著您的補丁不會被接受,也是針對您個人的。只需糾正針對您的補丁提出的所有問題並重新發送即可。

核心社群與企業結構之間的差異

核心社群的運作方式與大多數傳統的企業開發環境不同。以下是您可以嘗試做的一些事情,以避免問題:

  • 關於你提議的修改,可以說的好話

  • “這解決了多個問題。”

  • “這刪除了 2000 行程式碼。”

  • “這是一個解釋我試圖描述內容的補丁。”

  • “我在 5 種不同的架構上測試過……”

  • “這是一系列小補丁,它們……”

“這提高了典型機器的效能……”

  • 你應該避免說的壞話

  • “我們在 AIX/ptx/Solaris 中就是這樣做的,所以它一定很好……”

  • “我做這個已經 20 年了,所以……”

  • “這對於我們公司賺錢是必需的”

  • “這是為我們的企業產品線準備的。”

  • “這是我描述我想法的 1000 頁設計文件”

  • “我為此工作了 6 個月……”

  • “這是一個 5000 行的補丁,它……”

  • “我重寫了目前所有的混亂,成果在這裡……”

“我有一個截止日期,這個補丁現在需要被應用。”

核心社群與大多數傳統軟體工程工作環境不同的另一個方面是互動的無面性。使用電子郵件和 IRC 作為主要溝通形式的一個好處是,不會因性別或種族而產生歧視。Linux 核心工作環境接受女性和少數族裔,因為你所呈現的只是一個電子郵件地址。國際化方面也有助於創造公平的競爭環境,因為你無法根據一個人的名字來猜測性別。一個男人可能叫 Andrea,一個女人可能叫 Pat。大多數在 Linux 核心中工作並表達過意見的女性都有積極的經歷。

語言障礙可能會給一些不適應英語的人帶來問題。為了在郵件列表中正確表達想法,可能需要良好掌握英語,因此建議您在傳送電子郵件之前檢查它們是否用英語表達清晰。

拆分你的修改

Linux 核心社群不樂於一次性接受大量程式碼。更改需要適當引入、討論,並拆分為微小的獨立部分。這與公司通常的做法幾乎完全相反。您的提案也應在開發過程的早期引入,以便您可以收到關於您正在做的事情的反饋。這也讓社群覺得您正在與他們合作,而不僅僅是將他們用作您功能的垃圾場。然而,不要一次性向郵件列表傳送 50 封郵件,您的補丁系列在絕大多數情況下都應該比這小。

  1. 拆分修改的原因如下:

    小補丁增加了您的補丁被應用的可能性,因為它們不需要花費太多時間或精力來驗證正確性。一個 5 行的補丁,維護者幾乎不用多看一眼就能應用。然而,一個 500 行的補丁可能需要數小時來審查其正確性(所需時間與補丁大小呈指數級比例關係,或者類似的關係)。

  2. 小補丁還使得在出現問題時除錯變得非常容易。逐個回滾補丁比在一個非常大的補丁應用後(並導致問題)進行剖析要容易得多。

不僅要傳送小補丁,而且在提交之前重寫和簡化(或僅僅重新排序)補丁也很重要。

以下是核心開發者 Al Viro 的一個類比:

“想象一位老師批改數學學生的作業。老師不想看到學生在得出解決方案之前的嘗試和錯誤。他們想看到最清晰、最優雅的答案。一個好學生知道這一點,絕不會在最終解決方案出來之前提交她的中間作品。

核心開發也是如此。維護者和審查者不想看到解決問題背後的思考過程。他們想看到一個簡單而優雅的解決方案。”

在提出優雅的解決方案、與社群合作並討論未完成的工作之間保持平衡可能具有挑戰性。因此,儘早參與流程以獲取反饋來改進您的工作是好的,但也要將您的更改保持在小塊中,以便它們即使在您的整個任務尚未準備好包含時也可能被接受。

還要認識到,提交未完成的補丁並聲稱“稍後修復”是不可接受的。

證明你的修改的合理性

在拆分補丁的同時,讓 Linux 社群知道為什麼要新增這項更改也非常重要。新功能必須證明其必要性和實用性。

記錄你的修改

  • 在傳送補丁時,請特別注意您在電子郵件正文中撰寫的內容。這些資訊將成為補丁的變更日誌資訊,並永久保留供所有人查閱。它應該完整地描述補丁,包括:

  • 為什麼需要此更改

  • 補丁的整體設計方法

  • 實現細節

測試結果

《完美的補丁》(The Perfect Patch)

https://www.ozlabs.org/~akpm/stuff/tpp.txt

有關所有這些內容的更多詳細資訊,請參閱文件的變更日誌(ChangeLog)部分


所有這些事情有時都非常難以做到。可能需要數年才能完善這些實踐(如果能完善的話)。這是一個持續改進的過程,需要大量的耐心和決心。但不要放棄,這是可能實現的。許多人以前都做到過,每個人都必須從你現在的位置開始。

感謝 Paolo Ciarrocchi 允許“開發流程”(https://lwn.net/Articles/94386/)部分基於他所撰寫的文字,並感謝 Randy Dunlap 和 Gerrit Huizenga 提供了部分關於應該和不應該說什麼的列表。同時感謝 Pat Mochel、Hanna Linder、Randy Dunlap、Kay Sievers、Vojtech Pavlik、Jan Kara、Josh Boyer、Kees Cook、Andrew Morton、Andi Kleen、Vadim Lobanov、Jesper Juhl、Adrian Bunk、Keri Harris、Frans Pop、David A. Wheeler、Junio Hamano、Michael Kerrisk 和 Alex Shepard 的審查、評論和貢獻。沒有他們的幫助,這份文件將無法完成。