Warning

此文件的目的是爲讓中文讀者更容易閱讀和理解,而不是作爲一個分支。因此, 如果您對此文件有任何意見或改動,請先嘗試更新原始英文文件。如果要更改或 修正某處翻譯文件,請將意見或補丁發送給維護者(聯繫方式見下)。

Note

如果您發現本文檔與原始文件有任何不同或者有翻譯問題,請聯繫該文件的譯者, 或者發送電子郵件給胡皓文以獲取幫助:<src.res@email.cn>。

Original:

Documentation/process/2.Process.rst

Translator:

時奎亮 Alex Shi <alex.shi@linux.alibaba.com>

校譯:

吳想成 Wu XiangCheng <bobwxc@email.cn> 胡皓文 Hu Haowen <src.res@email.cn>

2. 開發流程如何進行

90年代早期的Linux內核開發是一件相當鬆散的事情,涉及的用戶和開發人員相對較少。 由於擁有數以百萬計的用戶羣,且每年有大約2000名開發人員參與進來,內核因此必須 發展出許多既定流程來保證開發的順利進行。要參與到流程中來,需要對此流程的進行 方式有一個紮實的理解。

2.1. 總覽

內核開發人員使用一個鬆散的基於時間的發布過程,每兩到三個月發布一次新的主要 內核版本。最近的發布歷史記錄如下:

5.0

2019年3月3日

5.1

2019年5月5日

5.2

2019年7月7日

5.3

2019年9月15日

5.4

2019年11月24日

5.5

2020年1月6日

每個5.x版本都是一個主要的內核版本,具有新特性、內部API更改等等。一個典型的5.x 版本包含大約13000個變更集,變更了幾十萬行代碼。因此,5.x是Linux內核開發的前 沿;內核使用滾動開發模型,不斷集成重大變化。

對於每個版本的補丁合併,遵循一個相對簡單的規則。在每個開發周期的開頭,「合併 窗口」被打開。這時,被認爲足夠穩定(並且被開發社區接受)的代碼被合併到主線內 核中。在這段時間內,新開發周期的大部分變更(以及所有主要變更)將以接近每天 1000次變更(「補丁」或「變更集」)的速度合併。

(順便說一句,值得注意的是,合併窗口期間集成的更改並不是憑空產生的;它們是經 提前收集、測試和分級的。稍後將詳細描述該過程的工作方式。)

合併窗口持續大約兩周。在這段時間結束時,LinusTorvalds將聲明窗口已關閉,並 釋放第一個「rc」內核。例如,對於目標爲5.6的內核,在合併窗口結束時發生的釋放 將被稱爲5.6-rc1。-rc1 版本是一個信號,表示合併新特性的時間已經過去,穩定下一 個內核的時間已經到來。

在接下來的6到10周內,只有修復問題的補丁才應該提交給主線。有時會允許更大的 更改,但這種情況很少發生;試圖在合併窗口外合併新功能的開發人員往往受不到 友好的接待。一般來說,如果您錯過了給定特性的合併窗口,最好的做法是等待下一 個開發周期。(偶爾會對未支持硬體的驅動程序進行例外;如果它們不改變已有代碼, 則不會導致回歸,應該可以隨時被安全地加入)。

隨著修復程序進入主線,補丁速度將隨著時間的推移而變慢。Linus大約每周發布一次 新的-rc內核;在內核被認爲足夠穩定並最終發布前,一般會達到-rc6到-rc9之間。 然後,整個過程又重新開始了。

例如,這裡是5.4的開發周期進行情況(2019年):

九月 15

5.3 穩定版發布

九月 30

5.4-rc1 合併窗口關閉

十月 6

5.4-rc2

十月 13

5.4-rc3

十月 20

5.4-rc4

十月 27

5.4-rc5

十一月 3

5.4-rc6

十一月 10

5.4-rc7

十一月 17

5.4-rc8

十一月 24

5.4 穩定版發布

開發人員如何決定何時結束開發周期並創建穩定版本?最重要的指標是以前版本的 回歸列表。不歡迎出現任何錯誤,但是那些破壞了以前能工作的系統的錯誤被認爲是 特別嚴重的。因此,導致回歸的補丁是不受歡迎的,很可能在穩定期內刪除。

開發人員的目標是在穩定發布之前修復所有已知的回歸。在現實世界中,這種完美是 很難實現的;在這種規模的項目中,變數太多了。需要說明的是,延遲最終版本只會 使問題變得更糟;等待下一個合併窗口的更改將變多,導致下次出現更多的回歸錯誤。 因此,大多數5.x內核都有一些已知的回歸錯誤,不過,希望沒有一個是嚴重的。

一旦一個穩定的版本發布,它的持續維護工作就被移交給「穩定團隊」,目前由 Greg Kroah-Hartman領導。穩定團隊將使用5.x.y編號方案不定期地發布穩定版本的 更新。要合入更新版本,補丁必須(1)修復一個重要的缺陷,且(2)已經合併到 下一個開發版本主線中。內核通常會在其初始版本後的一個以上的開發周期內收到 穩定版更新。例如,5.2內核的歷史如下(2019年):

七月 7

5.2 穩定版發布

七月 13

5.2.1

七月 21

5.2.2

七月 26

5.2.3

七月 28

5.2.4

七月 31

5.2.5

十月 11

5.2.21

5.2.21是5.2版本的最終穩定更新。

有些內核被指定爲「長期」內核;它們將得到更長時間的支持。在本文中,當前的長期 內核及其維護者是:

3.16

Ben Hutchings

(長期穩定內核)

4.4

Greg Kroah-Hartman & Sasha Levin

(長期穩定內核)

4.9

Greg Kroah-Hartman & Sasha Levin

4.14

Greg Kroah-Hartman & Sasha Levin

4.19

Greg Kroah-Hartman & Sasha Levin

5.4

Greg Kroah-Hartman & Sasha Levin

長期支持內核的選擇純粹是維護人員是否有需求和時間來維護該版本的問題。 目前還沒有爲即將發布的任何特定版本提供長期支持的已知計劃。

2.2. 補丁的生命周期

補丁不會直接從開發人員的鍵盤進入主線內核。相反,有一個稍微複雜(如果有些非 正式)的過程,旨在確保對每個補丁進行質量審查,並確保每個補丁實現了一個在主線 中需要的更改。對於小的修復,這個過程可能會很快完成,,而對於較大或有爭議的 變更,可能會持續數年。許多開發人員的沮喪來自於對這個過程缺乏理解或者試圖繞過它。

爲了減少這種挫敗,本文將描述補丁如何進入內核。下面的介紹以一種較爲理想化的 方式描述了這個過程。更詳細的過程將在後面的章節中介紹。

補丁通常要經歷以下階段:

  • 設計。這就是補丁的真正需求——以及滿足這些需求的方式——所在。設計工作通常 是在不涉及社區的情況下完成的,但是如果可能的話,最好是在公開的情況下完成 這項工作;這樣可以節省很多稍後再重新設計的時間。

  • 早期評審。補丁被發布到相關的郵件列表中,列表中的開發人員會回復他們可能有 的任何評論。如果一切順利的話,這個過程應該會發現補丁的任何主要問題。

  • 更廣泛的評審。當補丁接近準備好納入主線時,它應該被相關的子系統維護人員 接受——儘管這種接受並不能保證補丁會一直延伸到主線。補丁將出現在維護人員的 子系統樹中,並進入 -next 樹(如下所述)。當流程進行時,此步驟將會對補丁 進行更廣泛的審查,並發現由於將此補丁與其他人所做的工作合併而導致的任何 問題。

  • 請注意,大多數維護人員也有日常工作,因此合併補丁可能不是他們的最優先工作。 如果您的補丁得到了需要更改的反饋,那麼您應該進行這些更改,或者解釋爲何 不應該進行這些更改。如果您的補丁沒有評審意見,也沒有被其相應的子系統或 驅動程序維護者接受,那麼您應該堅持不懈地將補丁更新到當前內核使其可被正常 應用,並不斷地發送它以供審查和合併。

  • 合併到主線。最終,一個成功的補丁將被合併到由LinusTorvalds管理的主線存儲庫 中。此時可能會出現更多的評論和/或問題;對開發人員來說應對這些問題並解決 出現的任何問題仍很重要。

  • 穩定版發布。大量用戶可能受此補丁影響,因此可能再次出現新的問題。

  • 長期維護。雖然開發人員在合併代碼後可能會忘記代碼,但這種行爲往往會給開發 社區留下不良印象。合併代碼消除了一些維護負擔,因爲其他人將修復由API更改 引起的問題。但是,如果代碼要長期保持可用,原始開發人員應該繼續爲代碼負責。

內核開發人員(或他們的僱主)犯的最大錯誤之一是試圖將流程簡化爲一個「合併到 主線」步驟。這種方法總是會讓所有相關人員感到沮喪。

2.3. 補丁如何進入內核

只有一個人可以將補丁合併到主線內核存儲庫中:LinusTorvalds。但是,在進入 2.6.38內核的9500多個補丁中,只有112個(大約1.3%)是由Linus自己直接選擇的。 內核項目已經發展到一個沒有一個開發人員可以在沒有支持的情況下檢查和選擇每個 補丁的規模。內核開發人員處理這種增長的方式是使用圍繞信任鏈構建的助理系統。

內核代碼庫在邏輯上被分解爲一組子系統:網絡、特定體系結構支持、內存管理、視 頻設備等。大多數子系統都有一個指定的維護人員,其總體負責該子系統中的代碼。 這些子系統維護者(鬆散地)是他們所管理的內核部分的「守門員」;他們(通常) 會接受一個補丁以包含到主線內核中。

子系統維護人員每個人都管理著自己版本的內核原始碼樹,通常(並非總是)使用Git。 Git等工具(以及Quilt或Mercurial等相關工具)允許維護人員跟蹤補丁列表,包括作者 信息和其他元數據。在任何給定的時間,維護人員都可以確定他或她的存儲庫中的哪 些補丁在主線中找不到。

當合併窗口打開時,頂級維護人員將要求Linus從存儲庫中「拉出」他們爲合併選擇 的補丁。如果Linus同意,補丁流將流向他的存儲庫,成爲主線內核的一部分。 Linus對拉取中接收到的特定補丁的關注程度各不相同。很明顯,有時他看起來很 關注。但是一般來說,Linus相信子系統維護人員不會向上游發送壞補丁。

子系統維護人員反過來也可以從其他維護人員那裡獲取補丁。例如,網絡樹是由首先 在專用於網絡設備驅動程序、無線網絡等的樹中積累的補丁構建的。此存儲鏈可以 任意長,但很少超過兩個或三個連結。由於鏈中的每個維護者都信任那些管理較低 級別樹的維護者,所以這個過程稱爲「信任鏈」。

顯然,在這樣的系統中,獲取內核補丁取決於找到正確的維護者。直接向Linus發送 補丁通常不是正確的方法。

2.4. Next 樹

子系統樹鏈引導補丁流到內核,但它也提出了一個有趣的問題:如果有人想查看爲 下一個合併窗口準備的所有補丁怎麼辦?開發人員將感興趣的是,還有什麼其他的 更改有待解決,以了解是否存在需要擔心的衝突;例如,更改核心內核函數原型的 修補程序將與使用該函數舊形式的任何其他修補程序衝突。審查人員和測試人員希望 在所有這些變更到達主線內核之前,能夠訪問它們的集成形式的變更。您可以從所有 相關的子系統樹中提取更改,但這將是一項複雜且容易出錯的工作。

解決方案以-next樹的形式出現,在這裡子系統樹被收集以供測試和審查。這些樹中 由Andrew Morton維護的較老的一個,被稱爲「-mm」(用於內存管理,創建時爲此)。 -mm 樹集成了一長串子系統樹中的補丁;它還包含一些旨在幫助調試的補丁。

除此之外,-mm 還包含大量由Andrew直接選擇的補丁。這些補丁可能已經發布在郵件 列表上,或者它們可能應用於內核中未指定子系統樹的部分。同時,-mm 作爲最後 手段的子系統樹;如果沒有其他明顯的路徑可以讓補丁進入主線,那麼它很可能最 終選擇-mm 樹。累積在-mm 中的各種補丁最終將被轉發到適當的子系統樹,或者直接 發送到Linus。在典型的開發周期中,大約5-10%的補丁通過-mm 進入主線。

當前-mm 補丁可在「mmotm」(-mm of the moment)目錄中找到:

然而,使用MMOTM樹可能會十分令人頭疼;它甚至可能無法編譯。

下一個周期補丁合併的主要樹是linux-next,由Stephen Rothwell 維護。根據設計 linux-next 是下一個合併窗口關閉後主線的快照。linux-next樹在Linux-kernel 和 Linux-next 郵件列表中發布,可從以下位置下載:

Linux-next 已經成爲內核開發過程中不可或缺的一部分;在一個給定的合併窗口中合併 的所有補丁都應該在合併窗口打開之前的一段時間內找到進入Linux-next 的方法。

2.5. Staging 樹

內核原始碼樹包含drivers/staging/目錄,其中有許多驅動程序或文件系統的子目錄 正在被添加到內核樹中。它們在仍然需要更多的修正的時候可以保留在driver/staging/ 目錄中;一旦完成,就可以將它們移到內核中。這是一種跟蹤不符合Linux內核編碼或 質量標準的驅動程序的方法,人們可能希望使用它們並跟蹤開發。

Greg Kroah Hartman 目前負責維護staging 樹。仍需要修正的驅動程序將發送給他, 每個驅動程序在drivers/staging/中都有自己的子目錄。除了驅動程序源文件之外, 目錄中還應該有一個TODO文件。TODO文件列出了驅動程序需要接受的暫停的工作, 以及驅動程序的任何補丁都應該抄送的人員列表。當前的規則要求,staging的驅動 程序必須至少正確編譯。

Staging 是一種讓新的驅動程序進入主線的相對容易的方法,它們會幸運地引起其他 開發人員的注意,並迅速改進。然而,進入staging並不是故事的結尾;staging中 沒有看到常規進展的代碼最終將被刪除。經銷商也傾向於相對不願意使用staging驅動 程序。因此,在成爲一個合適的主線驅動的路上,staging 僅是一個中轉站。

2.6. 工具

從上面的文本可以看出,內核開發過程在很大程度上依賴於在不同方向上聚集補丁的 能力。如果沒有適當強大的工具,整個系統將無法在任何地方正常工作。關於如何使用 這些工具的教程遠遠超出了本文檔的範圍,但還是用一點篇幅介紹一些關鍵點。

到目前爲止,內核社區使用的主要原始碼管理系統是git。Git是在自由軟體社區中開發 的許多分布式版本控制系統之一。它非常適合內核開發,因爲它在處理大型存儲庫和 大量補丁時性能非常好。它也以難以學習和使用而著稱,儘管隨著時間的推移它變得 更好了。對於內核開發人員來說,對Git的某種熟悉幾乎是一種要求;即使他們不將它 用於自己的工作,他們也需要Git來跟上其他開發人員(以及主線)正在做的事情。

現在幾乎所有的Linux發行版都打包了Git。Git主頁位於:

此頁面包含了文檔和教程的連結。

在不使用git的內核開發人員中,最流行的選擇幾乎肯定是Mercurial:

Mercurial與Git共享許多特性,但它提供了一個界面,許多人覺得它更易於使用。

另一個值得了解的工具是Quilt:

Quilt 是一個補丁管理系統,而不是原始碼管理系統。它不會隨著時間的推移跟蹤歷史; 相反,它面向根據不斷發展的代碼庫跟蹤一組特定的更改。一些主要的子系統維護人員 使用Quilt來管理打算向上游移動的補丁。對於某些樹的管理(例如-mm),quilt 是 最好的工具。

2.7. 郵件列表

大量的Linux內核開發工作是通過郵件列表完成的。如果不加入至少一個某個列表, 就很難成爲社區中的一個「全功能」成員。但是,Linux郵件列表對開發人員來說也是 一個潛在的危險,他們可能會被一堆電子郵件淹沒、違反Linux列表上使用的約定, 或者兩者兼而有之。

大多數內核郵件列表都在vger.kernel.org上運行;主列表位於:

不過,也有一些列表託管在別處;其中一些列表位於 redhat.com/mailman/listinfo。

當然,內核開發的核心郵件列表是linux-kernel。這個列表是一個令人生畏的地方: 每天的信息量可以達到500條,噪音很高,談話技術性很強,且參與者並不總是表現出 高度的禮貌。但是,沒有其他地方可以讓內核開發社區作爲一個整體聚集在一起; 不使用此列表的開發人員將錯過重要信息。

以下一些提示可以幫助在linux-kernel生存:

  • 將郵件轉移到單獨的文件夾,而不是主郵箱文件夾。我們必須能夠持續地忽略洪流。

  • 不要試圖跟上每一次談話——沒人會這樣。重要的是要篩選感興趣的主題(但請注意 長時間的對話可能會偏離原來的主題,儘管未改變電子郵件的主題)和參與的人。

  • 不要回復挑事的人。如果有人試圖激起憤怒,請忽略他們。

  • 當回復Linux內核電子郵件(或其他列表上的電子郵件)時,請爲所有相關人員保留 Cc: 抄送頭。如果沒有確實的理由(如明確的請求),則不應刪除收件人。一定要 確保你要回復的人在抄送列表中。這個慣例也使你不必在回覆郵件時明確要求被抄送。

  • 在提出問題之前,搜索列表存檔(和整個網絡)。有些開發人員可能會對那些顯然 沒有完成家庭作業的人感到不耐煩。

  • 避免頂部回復(把你的答案放在你要回復的引文上面的做法)。這會讓你的回答更難 理解,印象也很差。

  • 在正確的郵件列表發問。linux-kernel 可能是通用的討論場所,但它不是尋找所有 子系統開發人員的最佳場所。

最後一點——找到正確的郵件列表——是開發人員常出錯的地方。在linux-kernel上 提出與網絡相關的問題的人幾乎肯定會收到一個禮貌的建議,轉到netdev列表上提出, 因爲這是大多數網絡開發人員經常出現的列表。還有其他列表可用於scsi、video4linux、 ide、filesystem等子系統。查找郵件列表的最佳位置是與內核原始碼一起打包的 MAINTAINERS文件。

2.8. 開始內核開發

關於如何開始內核開發過程的問題很常見——個人和公司皆然。同樣常見的是失誤,這 使得關係的開始比本應的更困難。

公司通常希望聘請知名的開發人員來啓動開發團隊。實際上,這是一種有效的技術。 但它也往往是昂貴的,而且對增加有經驗的內核開發人員的數量沒有多大幫助。考 慮到時間投入,可以讓內部開發人員加快Linux內核的開發速度。利用這段時間可以 讓僱主擁有一批既了解內核又了解公司的開發人員,還可以幫助培訓其他人。從中期 來看,這通常是更有利可圖的方法。

可以理解的是,單個開發人員往往對起步感到茫然。從一個大型項目開始可能會很 嚇人;人們往往想先用一些較小的東西來試試水。由此,一些開發人員開始創建修補 拼寫錯誤或輕微編碼風格問題的補丁。不幸的是,這樣的補丁會產生一定程度的噪音, 這會分散整個開發社區的注意力,因此,它們越來越被人不看重。希望向社區介紹 自己的新開發人員將無法通過這些方式獲得他們期待的反響。

Andrew Morton 爲有抱負的內核開發人員提供了如下建議

所有內核開發者的第一個項目肯定應該是「確保內核在您可以操作的所有
機器上始終完美運行」。通常的方法是和其他人一起解決問題(這可能需
要堅持!),但就是如此——這是內核開發的一部分。

(http://lwn.net/articles/283982/)

在沒有明顯問題需要解決的情況下,通常建議開發人員查看當前的回歸和開放缺陷 列表。從來都不缺少需要解決的問題;通過解決這些問題,開發人員將從該過程獲得 經驗,同時與開發社區的其他成員建立相互尊重。