code:
.. SPDX-License-Identifier: GPL-2.0

.. include:: ../disclaimer-zh_TW.rst

:Original: :ref:`Documentation/process/2.Process.rst <development_process>`

:Translator:

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

:校譯:

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

.. _tw_development_process:

開發流程如何進行
================

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

總覽
----

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

	======  =================
	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
	======  ================================	================

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

補丁的生命周期
--------------

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

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

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

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

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

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

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

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

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

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

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

補丁如何進入內核
----------------

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

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

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

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

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

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

Next 樹
-------

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

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

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

當前-mm 補丁可在「mmotm」（-mm of the moment）目錄中找到：

        https://www.ozlabs.org/~akpm/mmotm/

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

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

        https://www.kernel.org/pub/linux/kernel/next/

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

Staging 樹
----------

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

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

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

工具
----

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

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

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

        https://git-scm.com/

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

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

        http://www.seleric.com/mercurial/

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

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

        https://savannah.nongnu.org/projects/quilt

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

郵件列表
--------

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

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

        http://vger.kernel.org/vger-lists.html

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

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

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

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

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

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

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

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

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

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

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

開始內核開發
------------

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

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

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

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

::

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

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

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


code:
.. SPDX-License-Identifier: GPL-2.0

.. include:: ../disclaimer-zh_TW.rst

:Original: :ref:`Documentation/process/3.Early-stage.rst <development_early_stage>`

:Translator:

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

:校譯:

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

.. _tw_development_early_stage:

早期規劃
========

當考慮一個Linux內核開發項目時，很可能會直接跳進去開始編碼。然而，與任何重要
的項目一樣，許多成功的基礎最好是在第一行代碼編寫之前就打下。在早期計劃和
溝通中花費一些時間可以在之後節省更多的時間。

搞清問題
--------

與任何工程項目一樣，成功的內核改善從清晰描述要解決的問題開始。在某些情況
下，這個步驟很容易：例如當某個特定硬體需要驅動程序時。不過，在其他情況下，
很容易將實際問題與建議的解決方案混在一起，這可能會導致麻煩。

舉個例子：幾年前，Linux音頻的開發人員尋求一種方法來運行應用程式，而不會因
系統延遲過大而導致退出或其他問題。他們得到的解決方案是一個連接到Linux安全
模塊（LSM）框架中的內核模塊；這個模塊可以配置爲允許特定的應用程式訪問實時
調度程序。這個模塊被實現並發到linux-kernel郵件列表，在那裡它立即遇到了麻煩。

對於音頻開發人員來說，這個安全模塊足以解決他們當前的問題。但是，對於更廣泛的
內核社區來說，這被視爲對LSM框架的濫用（LSM框架並不打算授予他們原本不具備的
進程特權），並對系統穩定性造成風險。他們首選的解決方案包括短期的通過rlimit
機制進行實時調度訪問，以及長期的減少延遲的工作。

然而，音頻社區無法超越他們實施的特定解決方案來看問題；他們不願意接受替代方案。
由此產生的分歧使這些開發人員對整個內核開發過程感到失望；其中一個開發人員返回
到audio列表並發布了以下內容：

	有很多非常好的Linux內核開發人員，但他們往往會被一羣傲慢的傻瓜所壓倒。
	試圖向這些人傳達用戶需求是浪費時間。他們太「聰明」了，根本聽不到少數
	人的話。

（http://lwn.net/articles/131776/）

實際情況卻是不同的；與特定模塊相比，內核開發人員更關心系統穩定性、長期維護
以及找到問題的正確解決方案。這個故事的寓意是把重點放在問題上——而不是具體的
解決方案上——並在開始編寫代碼之前與開發社區討論這個問題。

因此，在考慮一個內核開發項目時，我們應該得到一組簡短問題的答案：

 - 需要解決的問題究竟是什麼？

 - 受此問題影響的用戶有哪些？解決方案應該解決哪些使用案例？

 - 內核現在爲何沒能解決這個問題？

只有這樣，才能開始考慮可能的解決方案。

早期討論
--------

在計劃內核開發項目時，在開始實施之前與社區進行討論是很有意義的。早期溝通可以
通過多種方式節省時間和麻煩：

 - 很可能問題是由內核以您不理解的方式解決的。Linux內核很大，具有許多不明顯
   的特性和功能。並不是所有的內核功能都像人們所希望的那樣有文檔記錄，而且很
   容易遺漏一些東西。某作者發布了一個完整的驅動程序，重複了一個其不
   知道的現有驅動程序。重新發明現有輪子的代碼不僅浪費，而且不會被接受到主線
   內核中。

 - 建議的解決方案中可能有一些要素不適合併入主線。在編寫代碼之前，最好先了解
   這樣的問題。

 - 其他開發人員完全有可能考慮過這個問題；他們可能有更好的解決方案的想法，並且
   可能願意幫助創建這個解決方案。

在內核開發社區的多年經驗給了我們一個明確的教訓：閉門設計和開發的內核代碼總是
有一些問題，這些問題只有在代碼發布到社區中時才會被發現。有時這些問題很嚴重，
需要數月或數年的努力才能使代碼達到內核社區的標準。例如：

 - 設計並實現了單處理器系統的DeviceScape網絡棧。只有使其適合於多處理器系統，
   才能將其合併到主線中。在代碼中修改鎖等等是一項困難的任務；因此，這段代碼
   （現在稱爲mac80211）的合併被推遲了一年多。

 - Reiser4文件系統包含許多功能，核心內核開發人員認爲這些功能應該在虛擬文件
   系統層中實現。它還包括一些特性，這些特性在不將系統暴露於用戶引起的死鎖的
   情況下是不容易實現的。這些問題過遲發現——以及拒絕處理其中一些問題——已經
   導致Reiser4置身主線內核之外。

 - Apparmor安全模塊以被認爲不安全和不可靠的方式使用內部虛擬文件系統數據結構。
   這種擔心（包括其他）使Apparmor多年來無法進入主線。

在這些情況下，與內核開發人員的早期討論，可以避免大量的痛苦和額外的工作。

找誰交流？
----------

當開發人員決定公開他們的計劃時，下一個問題是：我們從哪裡開始？答案是找到正確
的郵件列表和正確的維護者。對於郵件列表，最好的方法是在維護者(MAINTAINERS)文件
中查找要發布的相關位置。如果有一個合適的子系統列表，那麼其上發布通常比在
linux-kernel上發布更可取；您更有可能接觸到在相關子系統中具有專業知識的開發
人員，並且環境可能具支持性。

找到維護人員可能會有點困難。同樣，維護者文件是開始的地方。但是，該文件往往不
是最新的，並且並非所有子系統都在那裡顯示。實際上，維護者文件中列出的人員可能
不是當前實際擔任該角色的人員。因此，當對聯繫誰有疑問時，一個有用的技巧是使用
git（尤其是「git-log」）查看感興趣的子系統中當前活動的用戶。看看誰在寫補丁、
誰會在這些補丁上加上Signed-off-by行簽名（如有）。這些人將是幫助新開發項目的
最佳人選。

找到合適的維護者有時是非常具有挑戰性的，以至於內核開發人員添加了一個腳本來
簡化這個過程：

::

	.../scripts/get_maintainer.pl

當給定「-f」選項時，此腳本將返回指定文件或目錄的當前維護者。如果在命令行上
給出了一個補丁，它將列出可能接收補丁副本的維護人員。有許多選項可以調節
get_maintainer.pl搜索維護者的嚴格程度；請小心使用更激進的選項，因爲最終結果
可能會包括對您正在修改的代碼沒有真正興趣的開發人員。

如果所有其他方法都失敗了，那麼與Andrew Morton交流是跟蹤特定代碼段維護人員
的一種有效方法。

何時郵寄？
----------

如果可能的話，在早期階段發布你的計劃只會更有幫助。描述正在解決的問題以及已經
制定的關於如何實施的任何計劃。您可以提供的任何信息都可以幫助開發社區爲項目
提供有用的輸入。

在這個階段可能發生的一件令人沮喪的事情不是得到反對意見，而是很少或根本沒有
反饋。令人傷心的事實是：（1）內核開發人員往往很忙；（2）不缺少有宏偉計劃但
代碼（甚至代碼設想）很少的人去支持他們；（3）沒有人有義務審查或評論別人發表
的想法。除此之外，高層級的設計常常隱藏著一些問題，這些問題只有在有人真正嘗試
實現這些設計時才會被發現；因此，內核開發人員寧願看到代碼。

如果發布請求評論（RFC）並沒得到什麼有用的評論，不要以爲這意味著無人對此項目
有興趣，同時你也不能假設你的想法沒有問題。在這種情況下，最好的做法是繼續進
行，把你的進展隨時通知社區。

獲得官方認可
-----------------------

如果您的工作是在公司環境中完成的，就像大多數Linux內核工作一樣；顯然，在您將
公司的計劃或代碼發布到公共郵件列表之前，必須獲得有適當權利經理的許可。發布
不確定是否兼容GPL的代碼尤其會帶來問題；公司的管理層和法律人員越早能夠就發布
內核開發項目達成一致，對參與的每個人都越好。

一些讀者可能會認爲他們的核心工作是爲了支持還沒有正式承認存在的產品。將僱主
的計劃公布在公共郵件列表上可能不是一個可行的選擇。在這種情況下，有必要考慮
保密是否真的是必要的；通常不需要把開發計劃關在門內。

的確，有些情況下一家公司在開發過程的早期無法合法地披露其計劃。擁有經驗豐富
的內核開發人員的公司可能選擇以開環的方式進行開發，前提是他們以後能夠避免
嚴重的集成問題。對於沒有這種內部專業知識的公司，最好的選擇往往是聘請外部
開發者根據保密協議審查計劃。Linux基金會運行了一個NDA程序，旨在幫助解決這種
情況；更多信息參見：

    http://www.linuxfoundation.org/nda/

這種審查通常足以避免以後出現嚴重問題，而無需公開披露項目。

repo_name: angery/linux


code:
.. SPDX-License-Identifier: GPL-2.0

.. include:: ../disclaimer-zh_TW.rst

:Original: :ref:`Documentation/process/4.Coding.rst <development_coding>`

:Translator:

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

:校譯:

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

.. _tw_development_coding:

使代碼正確
======================

雖然一個堅實的、面向社區的設計過程有很多值得說道的，但是任何內核開發項目工作
的證明都反映在代碼中。它是將由其他開發人員檢查併合並（或不合併）到主線樹中
的代碼。所以這段代碼的質量決定了項目的最終成功。

本節將檢查編碼過程。我們將從內核開發人員常犯的幾種錯誤開始。然後重點將轉移
到正確的做法和相關有用的工具上。

陷阱
----

代碼風格
********

內核長期以來都有其標準的代碼風格，如
:ref:`Documentation/translations/zh_TW/process/coding-style.rst <tw_codingstyle>`
中所述。在多數時候，該文檔中描述的準則至多被認爲是建議性的。因此，內核中存在
大量不符合代碼風格準則的代碼。這種代碼的存在會給內核開發人員帶來兩方面的危害。

首先，相信內核代碼標準並不重要，也不強制執行。但事實上，如果沒有按照標準
編寫代碼，那麼新代碼將很難加入到內核中；許多開發人員甚至會在審查代碼之前要求
對代碼進行重新格式化。一個像內核這麼大的代碼庫需要一些統一格式的代碼，以使
開發人員能夠快速理解其中的任何部分。所以再也經不起奇怪格式的代碼的折騰了。

內核的代碼風格偶爾會與僱主的強制風格發生衝突。在這種情況下，必須在代碼合併
之前遵從內核代碼風格。將代碼放入內核意味著以多種方式放棄一定程度的控制權——
包括控制代碼樣式。

另一個危害是認爲已經在內核中的代碼迫切需要修復代碼樣式。開發者可能會開始編寫
重新格式化補丁，作爲熟悉開發過程的一種方式，或者作爲將其名字寫入內核變更日誌
的一種方式，或者兩者兼而有之。但是純代碼風格的修復被開發社區視爲噪音，它們往
往受到冷遇。因此，最好避免編寫這種類型的補丁。在由於其他原因處理一段代碼的
同時順帶修復其樣式是很自然的，但是不應該僅爲了更改代碼樣式而更改之。

代碼風格文檔也不應該被視爲絕對不可違反的規則。如果有一個足夠的理由反對這種
樣式（例如爲了80列限制拆分行會導致可讀性大大降低），那麼就這樣做吧。

注意您還可以使用 ``clang-format`` 工具來幫助您處理這些規則，快速自動重新格式
化部分代碼，和審閱完整的文件以發現代碼樣式錯誤、拼寫錯誤和可能的改進。它還
可以方便地排序 ``#includes`` 、對齊變量/宏、重排文本和其他類似任務。有關詳細
信息，請參閱文檔 :ref:`Documentation/process/clang-format.rst <clangformat>`

抽象層
******

計算機科學教授教學生以靈活性和信息隱藏的名義廣泛使用抽象層。當然，內核廣泛
地使用了抽象；任何涉及數百萬行代碼的項目都必須做到這一點以存續下來。但經驗
表明，過度或過早的抽象可能和過早的優化一樣有害。抽象應用在適當層級，
不要過度。

簡單點，先考慮一個調用時始終只有一個參數且總爲零的函數。我們可以保留這個參數，
以在需要使用它時提供的額外靈活性。不過，在那時實現了這個額外參數的代碼很有
可能以某種從未被注意到的微妙方式被破壞——因爲它從未被使用過。或者當需要額外
的靈活性時，它並未以符合程式設計師當初期望的方式來實現。內核開發人員通常會提交
補丁來刪除未使用的參數；一般來說，一開始就不應該添加這些參數。

隱藏硬體訪問的抽象層——通常爲了允許大量的驅動程序兼容多個作業系統——尤其不受
歡迎。這樣的層使代碼變得模糊，可能會造成性能損失；它們不屬於Linux內核。

另一方面，如果您發現自己從另一個內核子系統複製了大量的代碼，那麼是時候
了解一下：是否需要將這些代碼中的部分提取到單獨的庫中，或者在更高的層次上
實現這些功能。在整個內核中複製相同的代碼沒有價值。

#ifdef 和預處理
***************

C預處理器似乎給一些C程式設計師帶來了強大的誘惑，他們認爲它是一種將大量靈活性加入
原始碼中的方法。但是預處理器不是C，大量使用它會導致代碼對其他人來說更難閱讀，
對編譯器來說更難檢查正確性。使用了大量預處理器幾乎總是代碼需要一些
清理工作的標誌。

使用#ifdef的條件編譯實際上是一個強大的功能，它在內核中使用。但是很少有人希望
看到代碼被鋪滿#ifdef塊。一般規定，ifdef的使用應儘可能限制在頭文件中。條件
編譯代碼可以限制函數，如果代碼不存在，這些函數就直接變成空的。然後編譯器將
悄悄地優化對空函數的調用。使得代碼更加清晰，更容易理解。

C預處理器宏存在許多危險性，包括可能對具有副作用且沒有類型安全的表達式進行多
重評估。如果您試圖定義宏，請考慮創建一個內聯函數替代。結果相同的代碼，內聯
函數更容易閱讀，不會多次計算其參數，並且允許編譯器對參數和返回值執行類型檢查。

內聯函數
********

不過，內聯函數本身也存在風險。程式設計師可以傾心於避免函數調用和用內聯函數填充源
文件所固有的效率。然而，這些功能實際上會降低性能。因爲它們的代碼在每個調用站
點都被複製一遍，所以最終會增加編譯內核的大小。此外，這也對處理器的內存緩存
造成壓力，從而大大降低執行速度。通常內聯函數應該非常小，而且相對較少。畢竟
函數調用的成本並不高；大量創建內聯函數是過早優化的典型例子。

一般來說，內核程式設計師會自冒風險忽略緩存效果。在數據結構課程開頭中的經典
時間/空間權衡通常不適用於當代硬體。空間 *就是* 時間，因爲一個大的程序比一個
更緊湊的程序運行得慢。

較新的編譯器越來越激進地決定一個給定函數是否應該內聯。因此，隨意放置使用
「inline」關鍵字可能不僅僅是過度的，也可能是無用的。

鎖
**

2006年5月，「deviceescape」網絡堆棧在前呼後擁下以GPL發布，並被納入主線內核。
這是一個受歡迎的消息；Linux中對無線網絡的支持充其量被認爲是不合格的，而
Deviceescape堆棧承諾修復這種情況。然而直到2007年6月（2.6.22），這段代碼才真
正進入主線。發生了什麼？

這段代碼出現了許多閉門造車的跡象。但一個大麻煩是，它並不是爲多處理器系統而
設計。在合併這個網絡堆棧（現在稱爲mac80211）之前，需要對其進行一個鎖方案的
改造。

曾經，Linux內核代碼可以在不考慮多處理器系統所帶來的並發性問題的情況下進行
開發。然而現在，這個文檔就是在雙核筆記本電腦上寫的。即使在單處理器系統上，
爲提高響應能力所做的工作也會提高內核內的並發性水平。編寫內核代碼而不考慮鎖
的日子早已遠去。

可以由多個線程並發訪問的任何資源（數據結構、硬體寄存器等）必須由鎖保護。新
的代碼應該謹記這一要求；事後修改鎖是一項相當困難的任務。內核開發人員應該花
時間充分了解可用的鎖原語，以便爲工作選擇正確的工具。對並發性缺乏關注的代碼
很難進入主線。

回歸
****

最後一個值得一提的危險是回歸：它可能會引起導致現有用戶的某些東西中斷的改變
（這也可能會帶來很大的改進）。這種變化被稱爲「回歸」，回歸已經成爲主線內核
最不受歡迎的問題。除了少數例外情況，如果回歸不能及時修正，會導致回歸的修改
將被取消。最好首先避免回歸發生。

人們常常爭論，如果回歸帶來的功能遠超過產生的問題，那麼回歸是否爲可接受的。
如果它破壞了一個系統卻爲十個系統帶來新的功能，爲何不改改態度呢？2007年7月，
Linus對這個問題給出了最佳答案:

::

	所以我們不會通過引入新問題來修復錯誤。這種方式是靠不住的，沒人知道
	是否真的有進展。是前進兩步、後退一步，還是前進一步、後退兩步？

（http://lwn.net/articles/243460/）

特別不受歡迎的一種回歸類型是用戶空間ABI的任何變化。一旦接口被導出到用戶空間，
就必須無限期地支持它。這一事實使得用戶空間接口的創建特別具有挑戰性：因爲它們
不能以不兼容的方式進行更改，所以必須一次就對。因此，用戶空間接口總是需要大量
的思考、清晰的文檔和廣泛的審查。

代碼檢查工具
------------

至少目前，編寫無錯誤代碼仍然是我們中很少人能達到的理想狀態。不過，我們希望做
的是，在代碼進入主線內核之前，儘可能多地捕獲並修復這些錯誤。爲此，內核開發人
員已經提供了一系列令人印象深刻的工具，可以自動捕獲各種各樣的隱藏問題。計算機
發現的任何問題都是一個以後不會困擾用戶的問題，因此，只要有可能，就應該使用
自動化工具。

第一步是注意編譯器產生的警告。當前版本的GCC可以檢測（並警告）大量潛在錯誤。
通常，這些警告都指向真正的問題。提交以供審閱的代碼一般不會產生任何編譯器警告。
在消除警告時，注意了解真正的原因，並儘量避免僅「修復」使警告消失而不解決其原因。

請注意，並非所有編譯器警告都默認啓用。使用「make KCFLAGS=-W」構建內核以
獲得完整集合。

內核提供了幾個配置選項，可以打開調試功能；大多數配置選項位於「kernel hacking」
子菜單中。對於任何用於開發或測試目的的內核，都應該啓用其中幾個選項。特別是，
您應該打開：

 - FRAME_WARN 獲取大於給定數量的堆棧幀的警告。
   這些警告生成的輸出可能比較冗長，但您不必擔心來自內核其他部分的警告。

 - DEBUG_OBJECTS 將添加代碼以跟蹤內核創建的各種對象的生命周期，並在出現問題
   時發出警告。如果你要添加創建（和導出）關於其自己的複雜對象的子系統，請
   考慮打開對象調試基礎結構的支持。

 - DEBUG_SLAB 可以發現各種內存分配和使用錯誤；它應該用於大多數開發內核。

 - DEBUG_SPINLOCK, DEBUG_ATOMIC_SLEEP 和 DEBUG_MUTEXES 會發現許多常見的
   鎖錯誤。

還有很多其他調試選項，其中一些將在下面討論。其中一些有顯著的性能影響，不應
一直使用。在學習可用選項上花費一些時間，可能會在短期內得到許多回報。

其中一個較重的調試工具是鎖檢查器或「lockdep」。該工具將跟蹤系統中每個鎖
（spinlock或mutex）的獲取和釋放、獲取鎖的相對順序、當前中斷環境等等。然後，
它可以確保總是以相同的順序獲取鎖，相同的中斷假設適用於所有情況等等。換句話
說，lockdep可以找到許多導致系統死鎖的場景。在部署的系統中，這種問題可能會
很痛苦（對於開發人員和用戶而言）；LockDep允許提前以自動方式發現問題。具有
任何類型的非普通鎖的代碼在提交合併前應在啓用lockdep的情況下運行測試。

作爲一個勤奮的內核程式設計師，毫無疑問，您將檢查任何可能失敗的操作（如內存分配）
的返回狀態。然而，事實上，最終的故障復現路徑可能完全沒有經過測試。未測試的
代碼往往會出問題；如果所有這些錯誤處理路徑都被執行了幾次，那麼您可能對代碼
更有信心。

內核提供了一個可以做到這一點的錯誤注入框架，特別是在涉及內存分配的情況下。
啓用故障注入後，內存分配的可配置失敗的百分比；這些失敗可以限定在特定的代碼
範圍內。在啓用了故障注入的情況下運行，程式設計師可以看到當情況惡化時代碼如何響
應。有關如何使用此工具的詳細信息，請參閱
Documentation/fault-injection/fault-injection.rst。

「sparse」靜態分析工具可以發現其他類型的錯誤。sparse可以警告程式設計師用戶空間
和內核空間地址之間的混淆、大端序與小端序的混淆、在需要一組位標誌的地方傳遞
整數值等等。sparse必須單獨安裝(如果您的分發伺服器沒有將其打包，
可以在 https://sparse.wiki.kernel.org/index.php/Main_page 找到）,
然後可以通過在make命令中添加「C=1」在代碼上運行它。

「Coccinelle」工具 :ref:`http://coccinelle.lip6.fr/ <devtools_coccinelle>`
能夠發現各種潛在的編碼問題；它還可以爲這些問題提出修複方案。在
scripts/coccinelle目錄下已經打包了相當多的內核「語義補丁」；運行
「make coccicheck」將運行這些語義補丁並報告發現的任何問題。有關詳細信息，請參閱
:ref:`Documentation/dev-tools/coccinelle.rst <devtools_coccinelle>`

其他類型的可移植性錯誤最好通過爲其他體系結構編譯代碼來發現。如果沒有S/390系統
或Blackfin開發板，您仍然可以執行編譯步驟。可以在以下位置找到一大堆用於x86系統的
交叉編譯器：

        https://www.kernel.org/pub/tools/crosstool/

花一些時間安裝和使用這些編譯器將有助於避免以後的尷尬。

文檔
----

文檔通常比內核開發規則更爲例外。即便如此，足夠的文檔將有助於簡化將新代碼合併
到內核中的過程，使其他開發人員的生活更輕鬆，並對您的用戶有所幫助。在許多情況
下，添加文檔已基本上是強制性的。

任何補丁的第一個文檔是其關聯的變更日誌。日誌條目應該描述正在解決的問題、解決
方案的形式、處理補丁的人員、對性能的任何相關影響，以及理解補丁可能需要的任何
其他內容。確保變更日誌說明了*爲什麼*補丁值得應用；大量開發者未能提供這些信息。

任何添加新用戶空間接口的代碼——包括新的sysfs或/proc文件——都應該包含該接口
的文檔，該文檔使用戶空間開發人員能夠知道他們在使用什麼。請參閱
Documentation/ABI/README，了解如何此文檔格式以及需要提供哪些信息。

文檔 :ref:`Documentation/admin-guide/kernel-parameters.rst <kernelparameters>`
描述了內核的所有引導時間參數。任何添加新參數的補丁都應該向該文檔添加適當的
條目。

任何新的配置選項都必須附有幫助文本，幫助文本需清楚地解釋這些選項以及用戶可能
希望何時使用它們。

許多子系統的內部API信息通過專門格式化的注釋進行記錄；這些注釋可以通過
「kernel-doc」腳本以多種方式提取和格式化。如果您在具有kerneldoc注釋的子系統中
工作，則應該維護它們，並根據需要爲外部可用的功能添加它們。即使在沒有如此記錄
的領域中，爲將來添加kerneldoc注釋也沒有壞處；實際上，這對於剛開始開發內核的人
來說是一個有用的活動。這些注釋的格式以及如何創建kerneldoc模板的一些信息可以在
:ref:`Documentation/doc-guide/ <doc_guide>` 上找到。

任何閱讀大量現有內核代碼的人都會注意到，注釋的缺失往往是最值得注意的。同時，
對新代碼的要求比過去更高；合併未注釋的代碼將更加困難。這就是說，人們並不期望
詳細注釋的代碼。代碼本身應該是自解釋的，注釋闡釋了更微妙的方面。

某些事情應該總是被注釋。使用內存屏障時，應附上一行文字，解釋爲什麼需要設置內存
屏障。數據結構的鎖規則通常需要在某個地方解釋。一般來說，主要數據結構需要全面
的文檔。應該指出代碼中分立的位之間不明顯的依賴性。任何可能誘使代碼管理人進行
錯誤的「清理」的事情都需要一個注釋來說明爲什麼要這樣做。等等。

內部API更改
-----------

內核提供給用戶空間的二進位接口不能被破壞，除非逼不得已。而內核的內部編程接口
是高度流動的，當需要時可以更改。如果你發現自己不得不處理一個內核API，或者僅
僅因爲它不滿足你的需求導致無法使用特定的功能，這可能是API需要改變的一個標誌。
作爲內核開發人員，您有權進行此類更改。

的確可以進行API更改，但更改必須是合理的。因此任何進行內部API更改的補丁都應該
附帶關於更改內容和必要原因的描述。這種變化也應該拆分成一個單獨的補丁，而不是
埋在一個更大的補丁中。

另一個要點是，更改內部API的開發人員通常要負責修復內核樹中被更改破壞的任何代碼。
對於一個廣泛使用的函數，這個責任可以導致成百上千的變化，其中許多變化可能與其他
開發人員正在做的工作相衝突。不用說，這可能是一項大工程，所以最好確保理由是
可靠的。請注意，coccinelle工具可以幫助進行廣泛的API更改。

在進行不兼容的API更改時，應儘可能確保編譯器捕獲未更新的代碼。這將幫助您確保找
到該接口的樹內用處。它還將警告開發人員樹外代碼存在他們需要響應的更改。支持樹外
代碼不是內核開發人員需要擔心的事情，但是我們也不必使樹外開發人員的生活有不必要
的困難。


code:
.. SPDX-License-Identifier: GPL-2.0

.. include:: ../disclaimer-zh_TW.rst

:Original: :ref:`Documentation/process/5.Posting.rst <development_posting>`

:Translator:

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

:校譯:

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

.. _tw_development_posting:

發布補丁
========

您的工作遲早會準備好提交給社區進行審查，並最終包含到主線內核中。毫不稀奇，
內核開發社區已經發展出一套用於發布補丁的約定和過程；遵循這些約定和過程將使
參與其中的每個人的生活更加輕鬆。本文檔試圖描述這些約定的部分細節；更多信息
也可在以下文檔中找到
:ref:`Documentation/translations/zh_TW/process/submitting-patches.rst <tw_submittingpatches>`
和 :ref:`Documentation/translations/zh_TW/process/submit-checklist.rst <tw_submitchecklist>`。

何時郵寄
--------

在補丁完全「準備好」之前，避免發布補丁是一種持續的誘惑。對於簡單的補丁，這
不是問題。但是如果正在完成的工作很複雜，那麼在工作完成之前從社區獲得反饋就
可以獲得很多好處。因此，您應該考慮發布正在進行的工作，甚至維護一個可用的Git
樹，以便感興趣的開發人員可以隨時趕上您的工作。

當發布中有尚未準備好被包含的代碼，最好在發布中說明。還應提及任何有待完成的
主要工作和任何已知問題。很少有人會願意看那些被認爲是半生不熟的補丁，但是
那些願意的人會帶著他們的點子來一起幫助你把工作推向正確的方向。

創建補丁之前
------------

在考慮將補丁發送到開發社區之前，有許多事情應該做。包括：

 - 儘可能地測試代碼。利用內核的調試工具，確保內核使用了所有可能的配置選項組合
   進行構建，使用交叉編譯器爲不同的體系結構進行構建等。

 - 確保您的代碼符合內核代碼風格指南。

 - 您的更改是否具有性能影響？如果是這樣，您應該運行基準測試來顯示您的變更的
   影響（或好處）；結果的摘要應該包含在補丁中。

 - 確保您有權發布代碼。如果這項工作是爲僱主完成的，僱主對這項工作具有所有權，
   並且必須同意根據GPL對其進行發布。

一般來說，在發布代碼之前進行一些額外的思考，幾乎總是能在短時間內得到回報。

補丁準備
--------

準備補丁發布的工作量可能很驚人，但在此嘗試節省時間通常是不明智的，即使在短期
內亦然。

必須針對內核的特定版本準備補丁。一般來說，補丁應該基於Linus的Git樹中的當前
主線。當以主線爲基礎時，請從一個衆所周知的發布點開始——如穩定版本或 -rc
版本發布點——而不是在一個任意的主線分支點。

也可能需要針對-mm、linux-next或子系統樹生成版本，以便於更廣泛的測試和審查。
根據補丁的區域以及其他地方的情況，針對其他樹建立的補丁可能需要大量的工作來
解決衝突和處理API更改。

只有最簡單的更改才應格式化爲單個補丁；其他所有更改都應作爲一系列邏輯更改進行。
分割補丁是一門藝術；一些開發人員花了很長時間來弄清楚如何按照社區期望的方式來
分割。不過，這些經驗法則也許有幫助：

 - 您發布的補丁系列幾乎肯定不會是開發過程中版本控制系統中的一系列更改。相反，
   需要對您所做更改的最終形式加以考慮，然後以有意義的方式進行拆分。開發人員對
   離散的、自包含的更改感興趣，而不是您創造這些更改的原始路徑。

 - 每個邏輯上獨立的變更都應該格式化爲單獨的補丁。這些更改可以是小的（如「向
   此結構體添加欄位」）或大的（如添加一個重要的新驅動程序），但它們在概念上
   應該是小的，並且可以在一行內簡述。每個補丁都應該做一個特定的、可以單獨
   檢查並驗證它所做的事情的更改。

 - 換種方式重申上述準則，也就是說：不要在同一補丁中混合不同類型的更改。如果
   一個補丁修復了一個關鍵的安全漏洞，又重新排列了一些結構，還重新格式化了代
   碼，那麼它很有可能會被忽略，從而導致重要的修復丟失。

 - 每個補丁都應該能創建一個可以正確地構建和運行的內核；如果補丁系列在中間被
   斷開，那麼結果仍應是一個正常工作的內核。部分應用一系列補丁是使用
   「git bisct」工具查找回歸的一個常見場景；如果結果是一個損壞的內核，那麼將使
   那些從事追蹤問題的高尚工作的開發人員和用戶的生活更加艱難。

 - 不要過分分割。一位開發人員曾經將一組針對單個文件的編輯分成500個單獨的補丁
   發布，這並沒有使他成爲內核郵件列表中最受歡迎的人。一個補丁可以相當大，
   只要它仍然包含一個單一的 *邏輯* 變更。

 - 用一系列補丁添加一個全新的基礎設施，但是該設施在系列中的最後一個補丁啓用
   整個變更之前不能使用，這看起來很誘人。如果可能的話，應該避免這種誘惑；
   如果這個系列增加了回歸，那麼二分法將指出最後一個補丁是導致問題的補丁，
   即使真正的bug在其他地方。只要有可能，添加新代碼的補丁程序應該立即激活該
   代碼。

創建完美補丁系列的工作可能是一個令人沮喪的過程，在完成「真正的工作」之後需要
花費大量的時間和思考。但是如果做得好，花費的時間就是值得的。

補丁格式和更改日誌
------------------

所以現在你有了一系列完美的補丁可以發布，但是這項工作還沒有完成。每個補丁都
需要被格式化成一條消息，以快速而清晰地將其目的傳達到世界其他地方。爲此，
每個補丁將由以下部分組成：

 - 可選的「From」行，表明補丁作者。只有當你通過電子郵件發送別人的補丁時，這一行
   才是必須的，但是爲防止疑問加上它也不會有什麼壞處。

 - 一行描述，說明補丁的作用。對於在沒有其他上下文的情況下看到該消息的讀者來說，
   該消息應足以確定修補程序的範圍；此行將顯示在「short form（簡短格式）」變更
   日誌中。此消息通常需要先加上子系統名稱前綴，然後是補丁的目的。例如：

   ::

        gpio: fix build on CONFIG_GPIO_SYSFS=n

 - 一行空白，後接補丁內容的詳細描述。此描述可以是任意需要的長度；它應該說明補丁
   的作用以及爲什麼它應該應用於內核。

 - 一個或多個標記行，至少有一個由補丁作者的 Signed-off-by 簽名。標記將在下面
   詳細描述。

上面的項目一起構成補丁的變更日誌。寫一則好的變更日誌是一門至關重要但常常被
忽視的藝術；值得花一點時間來討論這個問題。當你編寫變更日誌時，你應該記住有
很多不同的人會讀你的話。其中包括子系統維護人員和審查人員，他們需要決定是否
應該合併補丁，分銷商和其他維護人員試圖決定是否應該將補丁反向移植到其他內核，
缺陷搜尋人員想知道補丁是否導致他們正在追查的問題，以及想知道內核如何變化的
用戶等等。一個好的變更日誌以最直接和最簡潔的方式向所有這些人傳達所需的信息。

在結尾，總結行應該描述變更的影響和動機，以及在一行約束條件下可能發生的變化。
然後，詳細的描述可以詳述這些主題，並提供任何需要的附加信息。如果補丁修復了
一個缺陷，請引用引入該缺陷的提交（如果可能，請在引用提交時同時提供其 id 和
標題）。如果某個問題與特定的日誌或編譯器輸出相關聯，請包含該輸出以幫助其他
人搜索同一問題的解決方案。如果更改是爲了支持以後補丁中的其他更改，那麼應當
說明。如果更改了內部API，請詳細說明這些更改以及其他開發人員應該如何響應。
一般來說，你越把自己放在每個閱讀你變更日誌的人的位置上，變更日誌（和內核
作爲一個整體）就越好。

不消說，變更日誌是將變更提交到版本控制系統時使用的文本。接下來將是：

 - 補丁本身，採用統一的（「-u」）補丁格式。使用「-p」選項來diff將使函數名與
   更改相關聯，從而使結果補丁更容易被其他人讀取。

您應該避免在補丁中包括與更改不相關文件（例如，構建過程生成的文件或編輯器
備份文件）。文檔目錄中的「dontdiff」文件在這方面有幫助；使用「-X」選項將
其傳遞給diff。

上面提到的標籤（tag）用於描述各種開發人員如何與這個補丁的開發相關聯。
:ref:`Documentation/translations/zh_TW/process/submitting-patches.rst <tw_submittingpatches>`
文檔中對它們進行了詳細描述；下面是一個簡短的總結。每一行的格式如下：

::

	tag: Full Name <email address>  optional-other-stuff

常用的標籤有：

 - Signed-off-by: 這是一個開發人員的證明，證明他或她有權提交補丁以包含到內核
   中。這表明同意開發者來源認證協議，其全文見
   :ref:`Documentation/translations/zh_TW/process/submitting-patches.rst <tw_submittingpatches>`
   如果沒有合適的簽字，則不能合併到主線中。

 - Co-developed-by: 聲明補丁是由多個開發人員共同創建的；當幾個人在一個補丁上
   工作時，它用於給出共同作者（除了 From: 所給出的作者之外）。由於
   Co-developed-by: 表示作者身份，所以每個共同開發人，必須緊跟在相關合作作者
   的Signed-off-by之後。具體內容和示例見以下文件
   :ref:`Documentation/translations/zh_TW/process/submitting-patches.rst <tw_submittingpatches>`

 - Acked-by: 表示另一個開發人員（通常是相關代碼的維護人員）同意補丁適合包含
   在內核中。

 - Tested-by: 聲明某人已經測試了補丁並確認它可以工作。

 - Reviewed-by: 表示某開發人員已經審查了補丁的正確性；有關詳細信息，請參閱
   :ref:`Documentation/translations/zh_TW/process/submitting-patches.rst <tw_submittingpatches>`

 - Reported-by: 指定報告此補丁修復的問題的用戶；此標記用於表示感謝。

 - Cc：指定某人收到了補丁的副本，並有機會對此發表評論。

在補丁中添加標籤時要小心：只有Cc:才適合在沒有指定人員明確許可的情況下添加。

發送補丁
--------

在寄出補丁之前，您還需要注意以下幾點：

 - 您確定您的郵件發送程序不會損壞補丁嗎？被郵件客戶端更改空白或修飾了行的補丁
   無法被另一端接受，並且通常不會進行任何詳細檢查。如果有任何疑問，先把補丁寄
   給你自己，讓你自己確定它是完好無損的。

   :ref:`Documentation/translations/zh_TW/process/email-clients.rst <tw_email_clients>`
   提供了一些有用的提示，可以讓特定的郵件客戶端正常發送補丁。

 - 你確定你的補丁沒有荒唐的錯誤嗎？您應該始終通過scripts/checkpatch.pl檢查
   補丁程序，並解決它提出的問題。請記住，checkpatch.pl，雖然體現了對內核補丁
   應該是什麼樣的大量思考，但它並不比您聰明。如果修復checkpatch.pl給的問題會
   使代碼變得更糟，請不要這樣做。

補丁應始終以純文本形式發送。請不要將它們作爲附件發送；這使得審閱者在答覆中更難
引用補丁的部分。相反，只需將補丁直接放到您的消息中。

寄出補丁時，重要的是將副本發送給任何可能感興趣的人。與其他一些項目不同，內核
鼓勵人們甚至錯誤地發送過多的副本；不要假定相關人員會看到您在郵件列表中的發布。
尤其是，副本應發送至：

 - 受影響子系統的維護人員。如前所述，維護人員文件是查找這些人員的首選地方。

 - 其他在同一領域工作的開發人員，尤其是那些現在可能在那裡工作的開發人員。使用
   git查看還有誰修改了您正在處理的文件，這很有幫助。

 - 如果您對某錯誤報告或功能請求做出響應，也可以抄送原始發送人。

 - 將副本發送到相關郵件列表，或者若無相關列表，則發送到linux-kernel列表。

 - 如果您正在修復一個缺陷，請考慮該修復是否應進入下一個穩定更新。如果是這樣，
   補丁副本也應發到stable@vger.kernel.org 。另外，在補丁本身的標籤中添加一個
   「Cc: stable@vger.kernel.org」；這將使穩定版團隊在修復進入主線時收到通知。

當爲一個補丁選擇接收者時，最好清楚你認爲誰最終會接受這個補丁並將其合併。雖然
可以將補丁直接發給Linus Torvalds並讓他合併，但通常情況下不會這樣做。Linus很
忙，並且有子系統維護人員負責監視內核的特定部分。通常您會希望維護人員合併您的
補丁。如果沒有明顯的維護人員，Andrew Morton通常是最後的補丁接收者。

補丁需要好的主題行。補丁主題行的規範格式如下：

::

	[PATCH nn/mm] subsys: one-line description of the patch

其中「nn」是補丁的序號，「mm」是系列中補丁的總數，「subsys」是受影響子系統的
名稱。當然，一個單獨的補丁可以省略nn/mm。

如果您有一系列重要的補丁，那麼通常發送一個簡介作爲第〇部分。不過，這個約定
並沒有得到普遍遵循；如果您使用它，請記住簡介中的信息不會進入內核變更日誌。
因此，請確保補丁本身具有完整的變更日誌信息。

一般來說，多部分補丁的第二部分和後續部分應作爲對第一部分的回覆發送，以便它們
在接收端都連接在一起。像git和coilt這樣的工具有命令，可以通過適當的線程發送
一組補丁。但是，如果您有一長串補丁，並正使用git，請不要使用–-chain-reply-to
選項，以避免創建過深的嵌套。


code:
.. SPDX-License-Identifier: GPL-2.0

.. include:: ../disclaimer-zh_TW.rst

:Original: :ref:`Documentation/process/6.Followthrough.rst <development_followthrough>`

:Translator:

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

:校譯:

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

.. _tw_development_followthrough:

跟進
====

此時，您已經遵循了到目前爲止給出的指導方針，並且，隨著您自己的工程技能的增加，
已經發布了一系列完美的補丁。即使是經驗豐富的內核開發人員也能犯的最大錯誤之一
是，認爲他們的工作現在已經完成了。事實上，發布補丁意味著進入流程的下一個階段，
可能還需要做很多工作。

一個補丁在首次發布時就非常出色、沒有改進的餘地，這是很罕見的。內核開發流程已
認識到這一事實，因此它非常注重對已發布代碼的改進。作爲代碼的作者，您應該與
內核社區合作，以確保您的代碼符合內核的質量標準。如果不參與這個過程，很可能會
無法將補丁合併到主線中。

與審閱者合作
------------

任何意義上的補丁都會導致其他開發人員在審查代碼時發表大量評論。對於許多開發
人員來說，與審閱人員合作可能是內核開發過程中最令人生畏的部分。但是如果你
記住一些事情，生活會變得容易得多：

 - 如果你已經很好地解釋了你的補丁，審閱人員會理解它的價值，以及爲什麼你會
   費盡心思去寫它。但是這個並不能阻止他們提出一個基本的問題：在五年或十年後
   維護含有此代碼的內核會怎麼樣？你可能被要求做出的許多改變——從編碼風格的
   調整到大量的重寫——都來自於對Linux的理解，即從現在起十年後，Linux仍將
   在開發中。

 - 代碼審查是一項艱苦的工作，這是一項相對吃力不討好的工作；人們記得誰編寫了
   內核代碼，但對於那些審查它的人來說，幾乎沒有什麼長久的名聲。因此，審閱
   人員可能會變得暴躁，尤其是當他們看到同樣的錯誤被一遍又一遍地犯下時。如果
   你得到了一個看起來憤怒、侮辱或完全冒犯你的評論，請抑制以同樣方式回應的衝動。
   代碼審查是關於代碼的，而不是關於人的，代碼審閱人員不會親自攻擊您。

 - 同樣，代碼審閱人員也不想以犧牲你僱主的利益爲代價來宣傳他們僱主的議程。
   內核開發人員通常希望今後幾年能在內核上工作，但他們明白他們的僱主可能會改
   變。他們真的，幾乎毫無例外地，致力於創造他們所能做到的最好的內核；他們並
   沒有試圖給僱主的競爭對手造成不適。

所有這些歸根結底就是，當審閱者向您發送評論時，您需要注意他們正在進行的技術
評論。不要讓他們的表達方式或你自己的驕傲阻止此事。當你在一個補丁上得到評論
時，花點時間去理解評論人想說什麼。如果可能的話，請修覆審閱者要求您修復的內
容。然後回覆審閱者：謝謝他們，並描述你將如何回答他們的問題。

請注意，您不必同意審閱者建議的每個更改。如果您認爲審閱者誤解了您的代碼，請
解釋到底發生了什麼。如果您對建議的更改有技術上的異議，請描述它並證明您對該
問題的解決方案是正確的。如果你的解釋有道理，審閱者會接受的。不過，如果你的
解釋證明缺乏說服力，尤其是當其他人開始同意審稿人的觀點時，請花些時間重新考慮
一下。你很容易對自己解決問題的方法視而不見，以至於你沒有意識到某些東西完全
是錯誤的，或者你甚至沒有解決正確的問題。

Andrew Morton建議，每一個不會導致代碼更改的審閱評論都應該產生一個額外的代碼
注釋；這可以幫助未來的審閱人員避免第一次出現的問題。

一個致命的錯誤是忽視評論，希望它們會消失。它們不會走的。如果您在沒有對之前
收到的評論做出響應的情況下重新發布代碼，那麼很可能會發現補丁毫無用處。

說到重新發布代碼：請記住，審閱者不會記住您上次發布的代碼的所有細節。因此，
提醒審閱人員以前提出的問題以及您如何處理這些問題總是一個好主意；補丁變更
日誌是提供此類信息的好地方。審閱者不必搜索列表檔案來熟悉上次所說的內容；
如果您幫助他們直接開始，當他們重新查看您的代碼時，心情會更好。

如果你已經試著做正確的事情，但事情仍然沒有進展呢？大多數技術上的分歧都可以
通過討論來解決，但有時人們仍需要做出決定。如果你真的認爲這個決定對你不利，
你可以試著向有更高權力的人上訴。對於本文，更高權力的人是 Andrew Morton 。
Andrew 在內核開發社區中非常受尊敬；他經常爲似乎被絕望阻塞的事情清障。儘管
如此，不應輕易就直接找 Andrew ，也不應在所有其他替代方案都被嘗試之前找他。
當然，記住，他也可能不同意你的意見。

接下來會發生什麼
----------------

如果一個補丁被認爲適合添加到內核中，並且大多數審查問題得到解決，下一步通常
是進入子系統維護人員的樹中。工作方式因子系統而異；每個維護人員都有自己的
工作方式。特別是可能有不止一棵樹——也許一棵樹專門用於計劃下一個合併窗口的
補丁，另一棵樹用於長期工作。

對於應用到不屬於明顯子系統樹（例如內存管理修補程序）的區域的修補程序，默認樹
通常上溯到-mm。影響多個子系統的補丁也可以最終進入-mm樹。

包含在子系統樹中可以提高補丁的可見性。現在，使用該樹的其他開發人員將默認獲
得補丁。子系統樹通常也爲Linux提供支持，使其內容對整個開發社區可見。在這一點
上，您很可能會從一組新的審閱者那裡得到更多的評論；這些評論需要像上一輪那樣
得到回應。

在這時也會發生點什麼，這取決於你的補丁的性質，是否與其他人正在做的工作發生
衝突。在最壞的情況下，嚴重的補丁衝突可能會導致一些工作被擱置，以便剩餘的補丁
可以成形併合並。另一些時候，衝突解決將涉及到與其他開發人員合作，可能還會
在樹之間移動一些補丁，以確保所有的應用都是乾淨的。這項工作可能是一件痛苦的
事情，但也需慶幸現在的幸福：在linux-next樹出現之前，這些衝突通常只在合併窗口
中出現，必須迅速解決。現在可以在合併窗口打開之前的空閒時間解決這些問題。

有朝一日，如果一切順利，您將登錄並看到您的補丁已經合併到主線內核中。祝賀你！
然而，一旦慶祝完了（並且您已經將自己添加到維護人員文件中），就一定要記住
一個重要的小事實：工作仍然沒有完成。併入主線也帶來了它的挑戰。

首先，補丁的可見性再次提高。可能會有以前不知道這個補丁的開發者的新一輪評論。
忽略它們可能很有誘惑力，因爲您的代碼不再存在任何被合併的問題。但是，要抵制
這種誘惑，您仍然需要對有問題或建議的開發人員作出響應。

不過，更重要的是：將代碼包含在主線中會將代碼交給更多的一些測試人員。即使您
爲尚未可用的硬體提供了驅動程序，您也會驚訝於有多少人會將您的代碼構建到內核
中。當然，如果有測試人員，也可能會有錯誤報告。

最糟糕的錯誤報告是回歸。如果你的補丁導致回歸，你會發現多到讓你不舒服的眼睛盯
著你；回歸需要儘快修復。如果您不願意或無法修復回歸（其他人都不會爲您修復），
那麼在穩定期內，您的補丁幾乎肯定會被移除。除了否定您爲使補丁進入主線所做的
所有工作之外，如果由於未能修復回歸而取消補丁，很可能會使將來的工作更難被合併。

在處理完任何回歸之後，可能還有其他普通缺陷需要處理。穩定期是修復這些錯誤並
確保代碼在主線內核版本中的首次發布儘可能可靠的最好機會。所以，請回應錯誤
報告，並儘可能解決問題。這就是穩定期的目的；一旦解決了舊補丁的任何問題，就
可以開始盡情創建新補丁。

別忘了，還有其他節點也可能會創建缺陷報告：下一個主線穩定版本，當著名的發行
商選擇包含您補丁的內核版本時等等。繼續響應這些報告是您工作的基本素養。但是
如果這不能提供足夠的動機，那麼也需要考慮：開發社區會記住那些在合併後對代碼
失去興趣的開發人員。下一次你發布補丁時，他們會以你以後不會持續維護它爲前提
來評估它。

其他可能發生的事情
------------------

某天，當你打開你的郵件客戶端時，看到有人給你寄了一個代碼補丁。畢竟，這是
讓您的代碼公開存在的好處之一。如果您同意這個補丁，您可以將它轉發給子系統
維護人員（確保包含一個正確的From:行，這樣屬性是正確的，並添加一個您自己的
signoff ），或者回復一個 Acked-by: 讓原始發送者向上發送它。

如果您不同意補丁，請禮貌地回復，解釋原因。如果可能的話，告訴作者需要做哪些
更改才能讓您接受補丁。合併代碼的編寫者和維護者所反對的補丁的確存在著一定的
阻力，但僅此而已。如果你被認爲不必要的阻礙了好的工作，那麼這些補丁最終會
繞過你並進入主線。在Linux內核中，沒有人對任何代碼擁有絕對的否決權。可能除
了Linus。

在非常罕見的情況下，您可能會看到完全不同的東西：另一個開發人員發布了針對您
的問題的不同解決方案。在這時，兩個補丁之一可能不會被合併，「我的補丁首先
發布」不被認爲是一個令人信服的技術論據。如果有別人的補丁取代了你的補丁而進
入了主線，那麼只有一種方法可以回應你：很高興你的問題解決了，請繼續工作吧。
以這種方式把某人的工作推到一邊可能導致傷心和氣餒，但是社區會記住你的反應，
即使很久以後他們已經忘記了誰的補丁真正被合併。


code:
.. SPDX-License-Identifier: GPL-2.0

.. include:: ../disclaimer-zh_TW.rst

:Original: :ref:`Documentation/process/7.AdvancedTopics.rst <development_advancedtopics>`

:Translator:

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

:校譯:

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

.. _tw_development_advancedtopics:

高級主題
========

現在，希望您能夠掌握開發流程的工作方式。然而，還有更多的東西要學！本節將介紹
一些主題，這些主題對希望成爲Linux內核開發過程常規部分的開發人員有幫助。

使用Git管理補丁
---------------

內核使用分布式版本控制始於2002年初，當時Linus首次開始使用專有的Bitkeeper應用
程序。雖然BitKeeper存在爭議，但它所體現的軟體版本管理方法卻肯定不是。分布式
版本控制可以立即加速內核開發項目。現在有好幾種免費的BitKeeper替代品。
但無論好壞，內核項目都已經選擇了Git作爲其工具。

使用Git管理補丁可以使開發人員的生活更加輕鬆，尤其是隨著補丁數量的增長。Git也
有其粗糙的邊角和一定的危險性，它是一個年輕和強大的工具，仍然在其開發人員完善
中。本文檔不會試圖教會讀者如何使用git；這會是個巨長的文檔。相反，這裡的重點
將是Git如何特別適合內核開發過程。想要加快用Git速度的開發人員可以在以下網站上
找到更多信息：

	https://git-scm.com/

	https://www.kernel.org/pub/software/scm/git/docs/user-manual.html

同時網上也能找到各種各樣的教程。

在嘗試使用它生成補丁供他人使用之前，第一要務是閱讀上述網頁，對Git的工作方式
有一個紮實的了解。使用Git的開發人員應能進行拉取主線存儲庫的副本，查詢修訂
歷史，提交對樹的更改，使用分支等操作。了解Git用於重寫歷史的工具（如rebase）
也很有用。Git有自己的術語和概念；Git的新用戶應該了解引用、遠程分支、索引、
快進合併、推拉、游離頭等。一開始可能有點嚇人，但這些概念不難通過一點學習來
理解。

使用git生成通過電子郵件提交的補丁是提高速度的一個很好的練習。

當您準備好開始建立Git樹供其他人查看時，無疑需要一個可以從中拉取的伺服器。
如果您有一個可以訪問網際網路的系統，那麼使用git-daemon設置這樣的伺服器相對
簡單。同時，免費的公共託管網站（例如github）也開始出現在網絡上。成熟的開發
人員可以在kernel.org上獲得一個帳戶，但這些帳戶並不容易得到；更多有關信息，
請參閱 https://kernel.org/faq/ 。

正常的Git工作流程涉及到許多分支的使用。每一條開發線都可以分爲單獨的「主題
分支」，並獨立維護。Git的分支很容易使用，沒有理由不使用它們。而且，在任何
情況下，您都不應該在任何您打算讓其他人從中拉取的分支中進行開發。應該小心地
創建公開可用的分支；當開發分支處於完整狀態並已準備好時(而不是之前）才合併
開發分支的補丁。

Git提供了一些強大的工具，可以讓您重寫開發歷史。一個不方便的補丁（比如說，
一個打破二分法的補丁，或者有其他一些明顯的缺陷）可以在適當的位置修復，或者
完全從歷史中消失。一個補丁系列可以被重寫，就好像它是在今天的主線上寫的一樣，
即使你已經花了幾個月的時間在寫它。可以透明地將更改從一個分支轉移到另一個
分支。等等。明智地使用git修改歷史的能力可以幫助創建問題更少的乾淨補丁集。

然而，過度使用這種功能可能會導致其他問題，而不僅僅是對創建完美項目歷史的
簡單癡迷。重寫歷史將重寫該歷史中包含的更改，將經過測試（希望如此）的內核樹
變爲未經測試的內核樹。除此之外，如果開發人員沒有共享項目歷史，他們就無法
輕鬆地協作；如果您重寫了其他開發人員拉入他們存儲庫的歷史，您將使這些開發
人員的生活更加困難。因此，這裡有一個簡單的經驗法則：被導出到其他地方的歷史
在此後通常被認爲是不可變的。

因此，一旦將一組更改推送到公開可用的伺服器上，就不應該重寫這些更改。如果您
嘗試強制進行無法快進合併的更改（即不共享同一歷史記錄的更改），Git將嘗試強制
執行此規則。這可能覆蓋檢查，有時甚至需要重寫導出的樹。在樹之間移動變更集以
避免linux-next中的衝突就是一個例子。但這種行爲應該是罕見的。這就是爲什麼
開發應該在私有分支中進行（必要時可以重寫）並且只有在公共分支處於合理的較新
狀態時才轉移到公共分支中的原因之一。

當主線（或其他一組變更所基於的樹）前進時，很容易與該樹合併以保持領先地位。
對於一個私有的分支，rebasing 可能是一個很容易跟上另一棵樹的方法，但是一旦
一棵樹被導出到外界，rebasing就不可取了。一旦發生這種情況，就必須進行完全
合併（merge）。合併有時是很有意義的，但是過於頻繁的合併會不必要地擾亂歷史。
在這種情況下建議的做法是不要頻繁合併，通常只在特定的發布點（如主線-rc發布）
合併。如果您對特定的更改感到緊張，則可以始終在私有分支中執行測試合併。在
這種情況下，git「rerere」工具很有用；它能記住合併衝突是如何解決的，這樣您
就不必重複相同的工作。

關於Git這樣的工具的一個最大的反覆抱怨是：補丁從一個存儲庫到另一個存儲庫的
大量移動使得很容易陷入錯誤建議的變更中，這些變更避開審查雷達進入主線。當內
核開發人員看到這種情況發生時，他們往往會感到不高興；在Git樹上放置未審閱或
主題外的補丁可能會影響您將來讓樹被拉取的能力。引用Linus的話:

::

   你可以給我發補丁，但當我從你那裡拉取一個Git補丁時，我需要知道你清楚
   自己在做什麼，我需要能夠相信事情而 *無需* 手動檢查每個單獨的更改。

（http://lwn.net/articles/224135/）。

爲了避免這種情況，請確保給定分支中的所有補丁都與相關主題緊密相關；「驅動程序
修復」分支不應更改核心內存管理代碼。而且，最重要的是，不要使用Git樹來繞過
審查過程。不時的將樹的摘要發布到相關的列表中，在合適時候請求linux-next中
包含該樹。

如果其他人開始發送補丁以包含到您的樹中，不要忘記審閱它們。還要確保您維護正確
的作者信息； git 「am」工具在這方面做得最好，但是如果補丁通過第三方轉發給您，
您可能需要在補丁中添加「From:」行。

請求拉取時，請務必提供所有相關信息：樹的位置、要拉取的分支以及拉取將導致的
更改。在這方面 git request-pull 命令非常有用；它將按照其他開發人員所期望的
格式化請求，並檢查以確保您已記得將這些更改推送到公共伺服器。

審閱補丁
--------

一些讀者顯然會反對將本節與「高級主題」放在一起，因爲即使是剛開始的內核開發人員
也應該審閱補丁。當然，沒有比查看其他人發布的代碼更好的方法來學習如何在內核環境
中編程了。此外，審閱者永遠供不應求；通過審閱代碼，您可以對整個流程做出重大貢獻。

審查代碼可能是一副令人生畏的圖景，特別是對一個新的內核開發人員來說，他們
可能會對公開詢問代碼感到緊張，而這些代碼是由那些有更多經驗的人發布的。不過，
即使是最有經驗的開發人員編寫的代碼也可以得到改進。也許對（所有）審閱者最好
的建議是：把審閱評論當成問題而不是批評。詢問「在這條路徑中如何釋放鎖？」
總是比說「這裡的鎖是錯誤的」更好。

不同的開發人員將從不同的角度審查代碼。部分人會主要關注代碼風格以及代碼行是
否有尾隨空格。其他人會主要關注補丁作爲一個整體實現的變更是否對內核有好處。
同時也有人會檢查是否存在鎖問題、堆棧使用過度、可能的安全問題、在其他地方
發現的代碼重複、足夠的文檔、對性能的不利影響、用戶空間ABI更改等。所有類型
的檢查，只要它們能引導更好的代碼進入內核，都是受歡迎和值得的。


code:
.. SPDX-License-Identifier: GPL-2.0

.. include:: ../disclaimer-zh_TW.rst

:Original: :ref:`Documentation/process/8.Conclusion.rst <development_conclusion>`
:Translator:

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

:校譯:

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

.. _tw_development_conclusion:

更多信息
========

關於Linux內核開發和相關主題的信息來源很多。首先是在內核原始碼分發中找到的
文檔目錄。頂級
:ref:`Documentation/translations/zh_TW/process/howto.rst <tw_process_howto>`
文件是一個重要的起點；
:ref:`Documentation/translations/zh_TW/process/submitting-patches.rst <tw_submittingpatches>`
也是所有內核開發人員都應該閱讀的內容。許多內部內核API都是使用kerneldoc機制
記錄的；「make htmldocs」或「make pdfdocs」可用於以HTML或PDF格式生成這些文檔
（儘管某些發行版提供的tex版本會遇到內部限制，無法正確處理文檔）。

不同的網站在各個細節層次上討論內核開發。本文作者想謙虛地建議用 https://lwn.net/
作爲來源；有關許多特定內核主題的信息可以通過以下網址的 LWN 內核索引找到：

  http://lwn.net/kernel/index/

除此之外，內核開發人員的一個寶貴資源是：

  https://kernelnewbies.org/

當然，也不應該忘記 https://kernel.org/ ，這是內核發布信息的最終位置。

關於內核開發有很多書：

  《Linux設備驅動程序》第三版（Jonathan Corbet、Alessandro Rubini和Greg Kroah Hartman）
  線上版本在 http://lwn.net/kernel/ldd3/

  《Linux內核設計與實現》（Robert Love）

  《深入理解Linux內核》(Daniel Bovet和Marco Cesati）

然而，所有這些書都有一個共同的缺點：它們上架時就往往有些過時，而且已經上架
一段時間了。不過，在那裡還是可以找到相當多的好信息。

有關git的文檔，請訪問：

  https://www.kernel.org/pub/software/scm/git/docs/

  https://www.kernel.org/pub/software/scm/git/docs/user-manual.html

結論
====

祝賀所有通過這篇冗長的文檔的人。希望它能夠幫助您理解Linux內核是如何開發的，
以及您如何參與這個過程。

最後，重要的是參與。任何開源軟體項目都不會超過其貢獻者投入其中的總和。Linux
內核的發展速度和以前一樣快，因爲它得到了大量開發人員的幫助，他們都在努力使它
變得更好。內核是一個最成功的例子，說明了當成千上萬的人爲了一個共同的目標一起
工作時，可以做出什麼。

不過，內核總是可以從更大的開發人員基礎中獲益。總有更多的工作要做。但是同樣
重要的是，Linux生態系統中的大多數其他參與者可以通過爲內核做出貢獻而受益。使
代碼進入主線是提高代碼質量、降低維護和分發成本、提高對內核開發方向的影響程度
等的關鍵。這是一種共贏的局面。啓動你的編輯器，來加入我們吧；你會非常受歡迎的。


code:
.. SPDX-License-Identifier: GPL-2.0

.. include:: ../disclaimer-zh_TW.rst

:Original: :ref:`Documentation/process/code-of-conduct-interpretation.rst <code_of_conduct_interpretation>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>
             Hu Haowen <src.res@email.cn>

.. _tw_code_of_conduct_interpretation:

Linux內核貢獻者契約行為準則解釋
===============================

:ref:`tw_code_of_conduct` 準則是一個通用文檔，旨在爲幾乎所有開源社區提供一套規則。
每個開源社區都是獨一無二的，Linux內核也不例外。因此，本文描述了Linux內核社區中
如何解釋它。我們也不希望這種解釋隨著時間的推移是靜態的，並將根據需要進行調整。

與開發軟體的「傳統」方法相比，Linux內核開發工作是一個非常個人化的過程。你的貢獻
和背後的想法將被仔細審查，往往導致批判和批評。審查將幾乎總是需要改進，材料才
能包括在內核中。要知道這是因爲所有相關人員都希望看到Linux整體成功的最佳解決方
案。這個開發過程已經被證明可以創建有史以來最健壯的作業系統內核，我們不想做任何
事情來導致提交質量和最終結果的下降。

維護者
------

行為準則多次使用「維護者」一詞。在內核社區中，「維護者」是負責子系統、驅動程序或
文件的任何人，並在內核原始碼樹的維護者文件中列出。

責任
----

《行為準則》提到了維護人員的權利和責任，這需要進一步澄清。

首先，最重要的是，有一個合理的期望是由維護人員通過實例來領導。

也就是說，我們的社區是廣闊的，對維護者沒有新的要求，他們單方面處理其他人在
他們活躍的社區的行爲。這一責任由我們所有人承擔，最終《行為準則》記錄了最終的
上訴路徑，以防有關行爲問題的問題懸而未決。

維護人員應該願意在出現問題時提供幫助，並在需要時與社區中的其他人合作。如果您
不確定如何處理出現的情況，請不要害怕聯繫技術諮詢委員會（TAB）或其他維護人員。
除非您願意，否則不會將其視爲違規報告。如果您不確定是否該聯繫TAB 或任何其他維
護人員，請聯繫我們的衝突調解人 Mishi Choudhary <mishi@linux.com>。

最後，「善待對方」才是每個人的最終目標。我們知道每個人都是人，有時我們都會失敗，
但我們所有人的首要目標應該是努力友好地解決問題。執行行為準則將是最後的選擇。

我們的目標是創建一個強大的、技術先進的作業系統，以及所涉及的技術複雜性，這自
然需要專業知識和決策。

所需的專業知識因貢獻領域而異。它主要由上下文和技術複雜性決定，其次由貢獻者和
維護者的期望決定。

專家的期望和決策都要經過討論，但在最後，爲了取得進展，必須能夠做出決策。這一
特權掌握在維護人員和項目領導的手中，預計將善意使用。

因此，設定專業知識期望、作出決定和拒絕不適當的貢獻不被視爲違反行為準則。

雖然維護人員一般都歡迎新來者，但他們幫助（新）貢獻者克服障礙的能力有限，因此
他們必須確定優先事項。這也不應被視爲違反了行為準則。內核社區意識到這一點，並
以各種形式提供入門級節目，如 kernelnewbies.org 。

範圍
----

Linux內核社區主要在一組公共電子郵件列表上進行交互，這些列表分布在由多個不同
公司或個人控制的多個不同伺服器上。所有這些列表都在內核原始碼樹中的
MAINTAINERS 文件中定義。發送到這些郵件列表的任何電子郵件都被視爲包含在行爲
準則中。

使用 kernel.org bugzilla和其他子系統bugzilla 或bug跟蹤工具的開發人員應該遵循
行為準則的指導原則。Linux內核社區沒有「官方」項目電子郵件地址或「官方」社交媒體
地址。使用kernel.org電子郵件帳戶執行的任何活動必須遵循爲kernel.org發布的行爲
準則，就像任何使用公司電子郵件帳戶的個人必須遵循該公司的特定規則一樣。

行為準則並不禁止在郵件列表消息、內核更改日誌消息或代碼注釋中繼續包含名稱、
電子郵件地址和相關注釋。

其他論壇中的互動包括在適用於上述論壇的任何規則中，通常不包括在行為準則中。
除了在極端情況下可考慮的例外情況。

提交給內核的貢獻應該使用適當的語言。在行為準則之前已經存在的內容現在不會被
視爲違反。然而，不適當的語言可以被視爲一個bug；如果任何相關方提交補丁，
這樣的bug將被更快地修復。當前屬於用戶/內核API的一部分的表達式，或者反映已
發布標準或規範中使用的術語的表達式，不被視爲bug。

執行
----

行為準則中列出的地址屬於行為準則委員會。https://kernel.org/code-of-conduct.html
列出了在任何給定時間接收這些電子郵件的確切成員。成員不能訪問在加入委員會之前
或離開委員會之後所做的報告。

最初的行為準則委員會由TAB的志願者以及作爲中立第三方的專業調解人組成。委員會
的首要任務是建立文件化的流程，並將其公開。

如果報告人不希望將整個委員會納入投訴或關切，可直接聯繫委員會的任何成員，包括
調解人。

行為準則委員會根據流程審查案例（見上文），並根據需要和適當與TAB協商，例如請求
和接收有關內核社區的信息。

委員會做出的任何決定都將提交到表中，以便在必要時與相關維護人員一起執行。行爲
準則委員會的決定可以通過三分之二的投票推翻。

每季度，行為準則委員會和標籤將提供一份報告，概述行為準則委員會收到的匿名報告
及其狀態，以及任何否決決定的細節，包括完整和可識別的投票細節。

我們希望在啓動期之後爲行為準則委員會人員配備建立一個不同的流程。發生此情況時，
將使用該信息更新此文檔。


code:
.. SPDX-License-Identifier: GPL-2.0

.. include:: ../disclaimer-zh_TW.rst

:Original: :ref:`Documentation/process/code-of-conduct.rst <code_of_conduct>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>
             Hu Haowen <src.res@email.cn>

.. _tw_code_of_conduct:

貢獻者契約行為準則
++++++++++++++++++

我們的誓言
==========

爲了營造一個開放、友好的環境，我們作爲貢獻者和維護人承諾，讓我們的社區和參
與者，擁有一個無騷擾的體驗，無論年齡、體型、殘疾、種族、性別特徵、性別認同
和表達、經驗水平、教育程度、社會狀況，經濟地位、國籍、個人外貌、種族、宗教
或性身份和取向。

我們的標準
==========

有助於創造積極環境的行爲包括：

* 使用歡迎和包容的語言
* 尊重不同的觀點和經驗
* 優雅地接受建設性的批評
* 關注什麼對社區最有利
* 對其他社區成員表示同情

參與者的不可接受行爲包括：

* 使用性意味的語言或意象以及不受歡迎的性注意或者更過分的行爲
* 煽動、侮辱/貶損評論以及個人或政治攻擊
* 公開或私下騷擾
* 未經明確許可，發布他人的私人信息，如物理或電子地址。
* 在專業場合被合理認爲不適當的其他行爲

我們的責任
==========

維護人員負責澄清可接受行爲的標準，並應針對任何不可接受行爲採取適當和公平的
糾正措施。

維護人員有權和責任刪除、編輯或拒絕與本行為準則不一致的評論、承諾、代碼、
wiki編輯、問題和其他貢獻，或暫時或永久禁止任何貢獻者從事他們認爲不適當、
威脅、冒犯或有害的其他行爲。

範圍
====

當個人代表項目或其社區時，本行為準則既適用於項目空間，也適用於公共空間。
代表一個項目或社區的例子包括使用一個正式的項目電子郵件地址，通過一個正式
的社交媒體帳戶發布，或者在在線或離線事件中擔任指定的代表。項目維護人員可以
進一步定義和澄清項目的表示。

執行
====

如有濫用、騷擾或其他不可接受的行爲，可聯繫行為準則委員會<conduct@kernel.org>。
所有投訴都將接受審查和調查，並將得到必要和適當的答覆。行為準則委員會有義務
對事件報告人保密。具體執行政策的進一步細節可單獨公布。

歸屬
====

本行為準則改編自《貢獻者契約》，版本1.4，可從
https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 獲取。

解釋
====

有關Linux內核社區如何解釋此文檔，請參閱 :ref:`tw_code_of_conduct_interpretation`


code:
.. SPDX-License-Identifier: GPL-2.0

.. include:: ../disclaimer-zh_TW.rst

:Original: :ref:`Documentation/process/coding-style.rst <codingstyle>`

.. _tw_codingstyle:

譯者::

  中文版維護者： 張樂 Zhang Le <r0bertz@gentoo.org>
  中文版翻譯者： 張樂 Zhang Le <r0bertz@gentoo.org>
  中文版校譯者： 王聰 Wang Cong <xiyou.wangcong@gmail.com>
                 wheelz <kernel.zeng@gmail.com>
                 管旭東 Xudong Guan <xudong.guan@gmail.com>
                 Li Zefan <lizf@cn.fujitsu.com>
                 Wang Chen <wangchen@cn.fujitsu.com>
                 Hu Haowen <src.res@email.cn>

Linux 內核代碼風格
=========================

這是一個簡短的文檔，描述了 linux 內核的首選代碼風格。代碼風格是因人而異的，
而且我不願意把自己的觀點強加給任何人，但這就像我去做任何事情都必須遵循的原則
那樣，我也希望在絕大多數事上保持這種的態度。請 (在寫代碼時) 至少考慮一下這裡
的代碼風格。

首先，我建議你列印一份 GNU 代碼規範，然後不要讀。燒了它，這是一個具有重大象徵
性意義的動作。

不管怎樣，現在我們開始：

1) 縮進
--------------

制表符是 8 個字符，所以縮進也是 8 個字符。有些異端運動試圖將縮進變爲 4 (甚至
2！) 字符深，這幾乎相當於嘗試將圓周率的值定義爲 3。

理由：縮進的全部意義就在於清楚的定義一個控制塊起止於何處。尤其是當你盯著你的
屏幕連續看了 20 小時之後，你將會發現大一點的縮進會使你更容易分辨縮進。

現在，有些人會抱怨 8 個字符的縮進會使代碼向右邊移動的太遠，在 80 個字符的終端
屏幕上就很難讀這樣的代碼。這個問題的答案是，如果你需要 3 級以上的縮進，不管用
何種方式你的代碼已經有問題了，應該修正你的程序。

簡而言之，8 個字符的縮進可以讓代碼更容易閱讀，還有一個好處是當你的函數嵌套太
深的時候可以給你警告。留心這個警告。

在 switch 語句中消除多級縮進的首選的方式是讓 ``switch`` 和從屬於它的 ``case``
標籤對齊於同一列，而不要 ``兩次縮進`` ``case`` 標籤。比如：

.. code-block:: c

	switch (suffix) {
	case 'G':
	case 'g':
		mem <<= 30;
		break;
	case 'M':
	case 'm':
		mem <<= 20;
		break;
	case 'K':
	case 'k':
		mem <<= 10;
		fallthrough;
	default:
		break;
	}

不要把多個語句放在一行里，除非你有什麼東西要隱藏：

.. code-block:: c

	if (condition) do_this;
	  do_something_everytime;

也不要在一行里放多個賦值語句。內核代碼風格超級簡單。就是避免可能導致別人誤讀
的表達式。

除了注釋、文檔和 Kconfig 之外，不要使用空格來縮進，前面的例子是例外，是有意爲
之。

選用一個好的編輯器，不要在行尾留空格。

2) 把長的行和字符串打散
------------------------------

代碼風格的意義就在於使用平常使用的工具來維持代碼的可讀性和可維護性。

每一行的長度的限制是 80 列，我們強烈建議您遵守這個慣例。

長於 80 列的語句要打散成有意義的片段。除非超過 80 列能顯著增加可讀性，並且不
會隱藏信息。子片段要明顯短於母片段，並明顯靠右。這同樣適用於有著很長參數列表
的函數頭。然而，絕對不要打散對用戶可見的字符串，例如 printk 信息，因爲這樣就
很難對它們 grep。

3) 大括號和空格的放置
------------------------------

C 語言風格中另外一個常見問題是大括號的放置。和縮進大小不同，選擇或棄用某种放
置策略並沒有多少技術上的原因，不過首選的方式，就像 Kernighan 和 Ritchie 展示
給我們的，是把起始大括號放在行尾，而把結束大括號放在行首，所以：

.. code-block:: c

	if (x is true) {
		we do y
	}

這適用於所有的非函數語句塊 (if, switch, for, while, do)。比如：

.. code-block:: c

	switch (action) {
	case KOBJ_ADD:
		return "add";
	case KOBJ_REMOVE:
		return "remove";
	case KOBJ_CHANGE:
		return "change";
	default:
		return NULL;
	}

不過，有一個例外，那就是函數：函數的起始大括號放置於下一行的開頭，所以：

.. code-block:: c

	int function(int x)
	{
		body of function
	}

全世界的異端可能會抱怨這個不一致性是... 呃... 不一致的，不過所有思維健全的人
都知道 (a) K&R 是 **正確的** 並且 (b) K&R 是正確的。此外，不管怎樣函數都是特
殊的 (C 函數是不能嵌套的)。

注意結束大括號獨自占據一行，除非它後面跟著同一個語句的剩餘部分，也就是 do 語
句中的 "while" 或者 if 語句中的 "else"，像這樣：

.. code-block:: c

	do {
		body of do-loop
	} while (condition);

和

.. code-block:: c

	if (x == y) {
		..
	} else if (x > y) {
		...
	} else {
		....
	}

理由：K&R。

也請注意這種大括號的放置方式也能使空 (或者差不多空的) 行的數量最小化，同時不
失可讀性。因此，由於你的屏幕上的新行是不可再生資源 (想想 25 行的終端屏幕)，你
將會有更多的空行來放置注釋。

當只有一個單獨的語句的時候，不用加不必要的大括號。

.. code-block:: c

	if (condition)
		action();

和

.. code-block:: c

	if (condition)
		do_this();
	else
		do_that();

這並不適用於只有一個條件分支是單語句的情況；這時所有分支都要使用大括號：

.. code-block:: c

	if (condition) {
		do_this();
		do_that();
	} else {
		otherwise();
	}

3.1) 空格
********************

Linux 內核的空格使用方式 (主要) 取決於它是用於函數還是關鍵字。(大多數) 關鍵字
後要加一個空格。值得注意的例外是 sizeof, typeof, alignof 和 __attribute__，這
些關鍵字某些程度上看起來更像函數 (它們在 Linux 里也常常伴隨小括號而使用，儘管
在 C 里這樣的小括號不是必需的，就像 ``struct fileinfo info;`` 聲明過後的
``sizeof info``)。

所以在這些關鍵字之後放一個空格::

	if, switch, case, for, do, while

但是不要在 sizeof, typeof, alignof 或者 __attribute__ 這些關鍵字之後放空格。
例如，

.. code-block:: c

	s = sizeof(struct file);

不要在小括號里的表達式兩側加空格。這是一個 **反例** ：

.. code-block:: c

	s = sizeof( struct file );

當聲明指針類型或者返回指針類型的函數時， ``*`` 的首選使用方式是使之靠近變量名
或者函數名，而不是靠近類型名。例子：

.. code-block:: c

	char *linux_banner;
	unsigned long long memparse(char *ptr, char **retptr);
	char *match_strdup(substring_t *s);

在大多數二元和三元操作符兩側使用一個空格，例如下面所有這些操作符::

	=  +  -  <  >  *  /  %  |  &  ^  <=  >=  ==  !=  ?  :

但是一元操作符後不要加空格::

	&  *  +  -  ~  !  sizeof  typeof  alignof  __attribute__  defined

後綴自加和自減一元操作符前不加空格::

	++  --

前綴自加和自減一元操作符後不加空格::

	++  --

``.`` 和 ``->`` 結構體成員操作符前後不加空格。

不要在行尾留空白。有些可以自動縮進的編輯器會在新行的行首加入適量的空白，然後
你就可以直接在那一行輸入代碼。不過假如你最後沒有在那一行輸入代碼，有些編輯器
就不會移除已經加入的空白，就像你故意留下一個只有空白的行。包含行尾空白的行就
這樣產生了。

當 git 發現補丁包含了行尾空白的時候會警告你，並且可以應你的要求去掉行尾空白；
不過如果你是正在打一系列補丁，這樣做會導致後面的補丁失敗，因爲你改變了補丁的
上下文。

4) 命名
------------------------------

C 是一個簡樸的語言，你的命名也應該這樣。和 Modula-2 和 Pascal 程式設計師不同，
C 程式設計師不使用類似 ThisVariableIsATemporaryCounter 這樣華麗的名字。C 程式設計師會
稱那個變量爲 ``tmp`` ，這樣寫起來會更容易，而且至少不會令其難於理解。

不過，雖然混用大小寫的名字是不提倡使用的，但是全局變量還是需要一個具描述性的
名字。稱一個全局函數爲 ``foo`` 是一個難以饒恕的錯誤。

全局變量 (只有當你 **真正** 需要它們的時候再用它) 需要有一個具描述性的名字，就
像全局函數。如果你有一個可以計算活動用戶數量的函數，你應該叫它
``count_active_users()`` 或者類似的名字，你不應該叫它 ``cntuser()`` 。

在函數名中包含函數類型 (所謂的匈牙利命名法) 是腦子出了問題——編譯器知道那些類
型而且能夠檢查那些類型，這樣做只能把程式設計師弄糊塗了。難怪微軟總是製造出有問題
的程序。

本地變量名應該簡短，而且能夠表達相關的含義。如果你有一些隨機的整數型的循環計
數器，它應該被稱爲 ``i`` 。叫它 ``loop_counter`` 並無益處，如果它沒有被誤解的
可能的話。類似的， ``tmp`` 可以用來稱呼任意類型的臨時變量。

如果你怕混淆了你的本地變量名，你就遇到另一個問題了，叫做函數增長荷爾蒙失衡綜
合症。請看第六章 (函數)。

5) Typedef
-----------

不要使用類似 ``vps_t`` 之類的東西。

對結構體和指針使用 typedef 是一個 **錯誤** 。當你在代碼里看到：

.. code-block:: c

	vps_t a;

這代表什麼意思呢？

相反，如果是這樣

.. code-block:: c

	struct virtual_container *a;

你就知道 ``a`` 是什麼了。

很多人認爲 typedef ``能提高可讀性`` 。實際不是這樣的。它們只在下列情況下有用：

 (a) 完全不透明的對象 (這種情況下要主動使用 typedef 來 **隱藏** 這個對象實際上
     是什麼)。

     例如： ``pte_t`` 等不透明對象，你只能用合適的訪問函數來訪問它們。

     .. note::

       不透明性和 "訪問函數" 本身是不好的。我們使用 pte_t 等類型的原因在於真
       的是完全沒有任何共用的可訪問信息。

 (b) 清楚的整數類型，如此，這層抽象就可以 **幫助** 消除到底是 ``int`` 還是
     ``long`` 的混淆。

     u8/u16/u32 是完全沒有問題的 typedef，不過它們更符合類別 (d) 而不是這裡。

     .. note::

       要這樣做，必須事出有因。如果某個變量是 ``unsigned long`` ，那麼沒有必要

	typedef unsigned long myflags_t;

     不過如果有一個明確的原因，比如它在某種情況下可能會是一個 ``unsigned int``
     而在其他情況下可能爲 ``unsigned long`` ，那麼就不要猶豫，請務必使用
     typedef。

 (c) 當你使用 sparse 按字面的創建一個 **新** 類型來做類型檢查的時候。

 (d) 和標準 C99 類型相同的類型，在某些例外的情況下。

     雖然讓眼睛和腦筋來適應新的標準類型比如 ``uint32_t`` 不需要花很多時間，可
     是有些人仍然拒絕使用它們。

     因此，Linux 特有的等同於標準類型的 ``u8/u16/u32/u64`` 類型和它們的有符號
     類型是被允許的——儘管在你自己的新代碼中，它們不是強制要求要使用的。

     當編輯已經使用了某個類型集的已有代碼時，你應該遵循那些代碼中已經做出的選
     擇。

 (e) 可以在用戶空間安全使用的類型。

     在某些用戶空間可見的結構體裡，我們不能要求 C99 類型而且不能用上面提到的
     ``u32`` 類型。因此，我們在與用戶空間共享的所有結構體中使用 __u32 和類似
     的類型。

可能還有其他的情況，不過基本的規則是 **永遠不要** 使用 typedef，除非你可以明
確的應用上述某個規則中的一個。

總的來說，如果一個指針或者一個結構體裡的元素可以合理的被直接訪問到，那麼它們
就不應該是一個 typedef。

6) 函數
------------------------------

函數應該簡短而漂亮，並且只完成一件事情。函數應該可以一屏或者兩屏顯示完 (我們
都知道 ISO/ANSI 屏幕大小是 80x24)，只做一件事情，而且把它做好。

一個函數的最大長度是和該函數的複雜度和縮進級數成反比的。所以，如果你有一個理
論上很簡單的只有一個很長 (但是簡單) 的 case 語句的函數，而且你需要在每個 case
里做很多很小的事情，這樣的函數儘管很長，但也是可以的。

不過，如果你有一個複雜的函數，而且你懷疑一個天分不是很高的高中一年級學生可能
甚至搞不清楚這個函數的目的，你應該嚴格遵守前面提到的長度限制。使用輔助函數，
並爲之取個具描述性的名字 (如果你覺得它們的性能很重要的話，可以讓編譯器內聯它
們，這樣的效果往往會比你寫一個複雜函數的效果要好。)

函數的另外一個衡量標準是本地變量的數量。此數量不應超過 5－10 個，否則你的函數
就有問題了。重新考慮一下你的函數，把它分拆成更小的函數。人的大腦一般可以輕鬆
的同時跟蹤 7 個不同的事物，如果再增多的話，就會糊塗了。即便你聰穎過人，你也可
能會記不清你 2 個星期前做過的事情。

在源文件里，使用空行隔開不同的函數。如果該函數需要被導出，它的 **EXPORT** 宏
應該緊貼在它的結束大括號之下。比如：

.. code-block:: c

	int system_is_up(void)
	{
		return system_state == SYSTEM_RUNNING;
	}
	EXPORT_SYMBOL(system_is_up);

在函數原型中，包含函數名和它們的數據類型。雖然 C 語言裡沒有這樣的要求，在
Linux 里這是提倡的做法，因爲這樣可以很簡單的給讀者提供更多的有價值的信息。

7) 集中的函數退出途徑
------------------------------

雖然被某些人聲稱已經過時，但是 goto 語句的等價物還是經常被編譯器所使用，具體
形式是無條件跳轉指令。

當一個函數從多個位置退出，並且需要做一些類似清理的常見操作時，goto 語句就很方
便了。如果並不需要清理操作，那麼直接 return 即可。

選擇一個能夠說明 goto 行爲或它爲何存在的標籤名。如果 goto 要釋放 ``buffer``,
一個不錯的名字可以是 ``out_free_buffer:`` 。別去使用像 ``err1:`` 和 ``err2:``
這樣的GW_BASIC 名稱，因爲一旦你添加或刪除了 (函數的) 退出路徑，你就必須對它們
重新編號，這樣會難以去檢驗正確性。

使用 goto 的理由是：

- 無條件語句容易理解和跟蹤
- 嵌套程度減小
- 可以避免由於修改時忘記更新個別的退出點而導致錯誤
- 讓編譯器省去刪除冗餘代碼的工作 ;)

.. code-block:: c

	int fun(int a)
	{
		int result = 0;
		char *buffer;

		buffer = kmalloc(SIZE, GFP_KERNEL);
		if (!buffer)
			return -ENOMEM;

		if (condition1) {
			while (loop1) {
				...
			}
			result = 1;
			goto out_free_buffer;
		}
		...
	out_free_buffer:
		kfree(buffer);
		return result;
	}

一個需要注意的常見錯誤是 ``一個 err 錯誤`` ，就像這樣：

.. code-block:: c

	err:
		kfree(foo->bar);
		kfree(foo);
		return ret;

這段代碼的錯誤是，在某些退出路徑上 ``foo`` 是 NULL。通常情況下，通過把它分離
成兩個錯誤標籤 ``err_free_bar:`` 和 ``err_free_foo:`` 來修復這個錯誤：

.. code-block:: c

	 err_free_bar:
		kfree(foo->bar);
	 err_free_foo:
		kfree(foo);
		return ret;

理想情況下，你應該模擬錯誤來測試所有退出路徑。

8) 注釋
------------------------------

注釋是好的，不過有過度注釋的危險。永遠不要在注釋里解釋你的代碼是如何運作的：
更好的做法是讓別人一看你的代碼就可以明白，解釋寫的很差的代碼是浪費時間。

一般的，你想要你的注釋告訴別人你的代碼做了什麼，而不是怎麼做的。也請你不要把
注釋放在一個函數體內部：如果函數複雜到你需要獨立的注釋其中的一部分，你很可能
需要回到第六章看一看。你可以做一些小注釋來註明或警告某些很聰明 (或者槽糕) 的
做法，但不要加太多。你應該做的，是把注釋放在函數的頭部，告訴人們它做了什麼，
也可以加上它做這些事情的原因。

當注釋內核 API 函數時，請使用 kernel-doc 格式。請看
Documentation/doc-guide/ 和 scripts/kernel-doc 以獲得詳細信息。

長 (多行) 注釋的首選風格是：

.. code-block:: c

	/*
	 * This is the preferred style for multi-line
	 * comments in the Linux kernel source code.
	 * Please use it consistently.
	 *
	 * Description:  A column of asterisks on the left side,
	 * with beginning and ending almost-blank lines.
	 */

對於在 net/ 和 drivers/net/ 的文件，首選的長 (多行) 注釋風格有些不同。

.. code-block:: c

	/* The preferred comment style for files in net/ and drivers/net
	 * looks like this.
	 *
	 * It is nearly the same as the generally preferred comment style,
	 * but there is no initial almost-blank line.
	 */

注釋數據也是很重要的，不管是基本類型還是衍生類型。爲了方便實現這一點，每一行
應只聲明一個數據 (不要使用逗號來一次聲明多個數據)。這樣你就有空間來爲每個數據
寫一段小注釋來解釋它們的用途了。

9) 你已經把事情弄糟了
------------------------------

這沒什麼，我們都是這樣。可能你的使用了很長時間 Unix 的朋友已經告訴你
``GNU emacs`` 能自動幫你格式化 C 原始碼，而且你也注意到了，確實是這樣，不過它
所使用的默認值和我們想要的相去甚遠 (實際上，甚至比隨機打的還要差——無數個猴子
在 GNU emacs 里打字永遠不會創造出一個好程序) (譯註：Infinite Monkey Theorem)

所以你要麼放棄 GNU emacs，要麼改變它讓它使用更合理的設定。要採用後一個方案，
你可以把下面這段粘貼到你的 .emacs 文件里。

.. code-block:: none

  (defun c-lineup-arglist-tabs-only (ignored)
    "Line up argument lists by tabs, not spaces"
    (let* ((anchor (c-langelem-pos c-syntactic-element))
           (column (c-langelem-2nd-pos c-syntactic-element))
           (offset (- (1+ column) anchor))
           (steps (floor offset c-basic-offset)))
      (* (max steps 1)
         c-basic-offset)))

  (dir-locals-set-class-variables
   'linux-kernel
   '((c-mode . (
          (c-basic-offset . 8)
          (c-label-minimum-indentation . 0)
          (c-offsets-alist . (
                  (arglist-close         . c-lineup-arglist-tabs-only)
                  (arglist-cont-nonempty .
		      (c-lineup-gcc-asm-reg c-lineup-arglist-tabs-only))
                  (arglist-intro         . +)
                  (brace-list-intro      . +)
                  (c                     . c-lineup-C-comments)
                  (case-label            . 0)
                  (comment-intro         . c-lineup-comment)
                  (cpp-define-intro      . +)
                  (cpp-macro             . -1000)
                  (cpp-macro-cont        . +)
                  (defun-block-intro     . +)
                  (else-clause           . 0)
                  (func-decl-cont        . +)
                  (inclass               . +)
                  (inher-cont            . c-lineup-multi-inher)
                  (knr-argdecl-intro     . 0)
                  (label                 . -1000)
                  (statement             . 0)
                  (statement-block-intro . +)
                  (statement-case-intro  . +)
                  (statement-cont        . +)
                  (substatement          . +)
                  ))
          (indent-tabs-mode . t)
          (show-trailing-whitespace . t)
          ))))

  (dir-locals-set-directory-class
   (expand-file-name "~/src/linux-trees")
   'linux-kernel)

這會讓 emacs 在 ``~/src/linux-trees`` 下的 C 源文件獲得更好的內核代碼風格。

不過就算你嘗試讓 emacs 正確的格式化代碼失敗了，也並不意味著你失去了一切：還可
以用 ``indent`` 。

不過，GNU indent 也有和 GNU emacs 一樣有問題的設定，所以你需要給它一些命令選
項。不過，這還不算太糟糕，因爲就算是 GNU indent 的作者也認同 K&R 的權威性
(GNU 的人並不是壞人，他們只是在這個問題上被嚴重的誤導了)，所以你只要給 indent
指定選項 ``-kr -i8`` (代表 ``K&R，8 字符縮進``)，或使用 ``scripts/Lindent``
這樣就可以以最時髦的方式縮進原始碼。

``indent`` 有很多選項，特別是重新格式化注釋的時候，你可能需要看一下它的手冊。
不過記住： ``indent`` 不能修正壞的編程習慣。

10) Kconfig 配置文件
------------------------------

對於遍布源碼樹的所有 Kconfig* 配置文件來說，它們縮進方式有所不同。緊挨著
``config`` 定義的行，用一個制表符縮進，然而 help 信息的縮進則額外增加 2 個空
格。舉個例子::

  config AUDIT
	bool "Auditing support"
	depends on NET
	help
	  Enable auditing infrastructure that can be used with another
	  kernel subsystem, such as SELinux (which requires this for
	  logging of avc messages output).  Does not do system-call
	  auditing without CONFIG_AUDITSYSCALL.

而那些危險的功能 (比如某些文件系統的寫支持) 應該在它們的提示字符串里顯著的聲
明這一點::

  config ADFS_FS_RW
	bool "ADFS write support (DANGEROUS)"
	depends on ADFS_FS
	...

要查看配置文件的完整文檔，請看 Documentation/kbuild/kconfig-language.rst。

11) 數據結構
------------------------------

如果一個數據結構，在創建和銷毀它的單線執行環境之外可見，那麼它必須要有一個引
用計數器。內核里沒有垃圾收集 (並且內核之外的垃圾收集慢且效率低下)，這意味著你
絕對需要記錄你對這種數據結構的使用情況。

引用計數意味著你能夠避免上鎖，並且允許多個用戶並行訪問這個數據結構——而不需要
擔心這個數據結構僅僅因爲暫時不被使用就消失了，那些用戶可能不過是沉睡了一陣或
者做了一些其他事情而已。

注意上鎖 **不能** 取代引用計數。上鎖是爲了保持數據結構的一致性，而引用計數是一
個內存管理技巧。通常二者都需要，不要把兩個搞混了。

很多數據結構實際上有 2 級引用計數，它們通常有不同 ``類`` 的用戶。子類計數器統
計子類用戶的數量，每當子類計數器減至零時，全局計數器減一。

這種 ``多級引用計數`` 的例子可以在內存管理 (``struct mm_struct``: mm_users 和
mm_count)，和文件系統 (``struct super_block``: s_count 和 s_active) 中找到。

記住：如果另一個執行線索可以找到你的數據結構，但這個數據結構沒有引用計數器，
這裡幾乎肯定是一個 bug。

12) 宏，枚舉和RTL
------------------------------

用於定義常量的宏的名字及枚舉里的標籤需要大寫。

.. code-block:: c

	#define CONSTANT 0x12345

在定義幾個相關的常量時，最好用枚舉。

宏的名字請用大寫字母，不過形如函數的宏的名字可以用小寫字母。

一般的，如果能寫成內聯函數就不要寫成像函數的宏。

含有多個語句的宏應該被包含在一個 do-while 代碼塊里：

.. code-block:: c

	#define macrofun(a, b, c)			\
		do {					\
			if (a == 5)			\
				do_this(b, c);		\
		} while (0)

使用宏的時候應避免的事情：

1) 影響控制流程的宏：

.. code-block:: c

	#define FOO(x)					\
		do {					\
			if (blah(x) < 0)		\
				return -EBUGGERED;	\
		} while (0)

**非常** 不好。它看起來像一個函數，不過卻能導致 ``調用`` 它的函數退出；不要打
亂讀者大腦里的語法分析器。

2) 依賴於一個固定名字的本地變量的宏：

.. code-block:: c

	#define FOO(val) bar(index, val)

可能看起來像是個不錯的東西，不過它非常容易把讀代碼的人搞糊塗，而且容易導致看起
來不相關的改動帶來錯誤。

3) 作爲左值的帶參數的宏： FOO(x) = y；如果有人把 FOO 變成一個內聯函數的話，這
   種用法就會出錯了。

4) 忘記了優先級：使用表達式定義常量的宏必須將表達式置於一對小括號之內。帶參數
   的宏也要注意此類問題。

.. code-block:: c

	#define CONSTANT 0x4000
	#define CONSTEXP (CONSTANT | 3)

5) 在宏里定義類似函數的本地變量時命名衝突：

.. code-block:: c

	#define FOO(x)				\
	({					\
		typeof(x) ret;			\
		ret = calc_ret(x);		\
		(ret);				\
	})

ret 是本地變量的通用名字 - __foo_ret 更不容易與一個已存在的變量衝突。

cpp 手冊對宏的講解很詳細。gcc internals 手冊也詳細講解了 RTL，內核里的彙編語
言經常用到它。

13) 列印內核消息
------------------------------

內核開發者應該是受過良好教育的。請一定注意內核信息的拼寫，以給人以好的印象。
不要用不規範的單詞比如 ``dont``，而要用 ``do not`` 或者 ``don't`` 。保證這些信
息簡單明了,無歧義。

內核信息不必以英文句號結束。

在小括號里列印數字 (%d) 沒有任何價值，應該避免這樣做。

<linux/device.h> 里有一些驅動模型診斷宏，你應該使用它們，以確保信息對應於正確
的設備和驅動，並且被標記了正確的消息級別。這些宏有：dev_err(), dev_warn(),
dev_info() 等等。對於那些不和某個特定設備相關連的信息，<linux/printk.h> 定義
了 pr_notice(), pr_info(), pr_warn(), pr_err() 和其他。

寫出好的調試信息可以是一個很大的挑戰；一旦你寫出後，這些信息在遠程除錯時能提
供極大的幫助。然而列印調試信息的處理方式同列印非調試信息不同。其他 pr_XXX()
函數能無條件地列印，pr_debug() 卻不；默認情況下它不會被編譯，除非定義了 DEBUG
或設定了 CONFIG_DYNAMIC_DEBUG。實際這同樣是爲了 dev_dbg()，一個相關約定是在一
個已經開啓了 DEBUG 時，使用 VERBOSE_DEBUG 來添加 dev_vdbg()。

許多子系統擁有 Kconfig 調試選項來開啓 -DDEBUG 在對應的 Makefile 裡面；在其他
情況下，特殊文件使用 #define DEBUG。當一條調試信息需要被無條件列印時，例如，
如果已經包含一個調試相關的 #ifdef 條件，printk(KERN_DEBUG ...) 就可被使用。

14) 分配內存
------------------------------

內核提供了下面的一般用途的內存分配函數：
kmalloc(), kzalloc(), kmalloc_array(), kcalloc(), vmalloc() 和 vzalloc()。
請參考 API 文檔以獲取有關它們的詳細信息。

傳遞結構體大小的首選形式是這樣的：

.. code-block:: c

	p = kmalloc(sizeof(*p), ...);

另外一種傳遞方式中，sizeof 的操作數是結構體的名字，這樣會降低可讀性，並且可能
會引入 bug。有可能指針變量類型被改變時，而對應的傳遞給內存分配函數的 sizeof
的結果不變。

強制轉換一個 void 指針返回值是多餘的。C 語言本身保證了從 void 指針到其他任何
指針類型的轉換是沒有問題的。

分配一個數組的首選形式是這樣的：

.. code-block:: c

	p = kmalloc_array(n, sizeof(...), ...);

分配一個零長數組的首選形式是這樣的：

.. code-block:: c

	p = kcalloc(n, sizeof(...), ...);

兩種形式檢查分配大小 n * sizeof(...) 的溢出，如果溢出返回 NULL。

15) 內聯弊病
------------------------------

有一個常見的誤解是 ``內聯`` 是 gcc 提供的可以讓代碼運行更快的一個選項。雖然使
用內聯函數有時候是恰當的 (比如作爲一種替代宏的方式，請看第十二章)，不過很多情
況下不是這樣。inline 的過度使用會使內核變大，從而使整個系統運行速度變慢。
因爲體積大內核會占用更多的指令高速緩存，而且會導致 pagecache 的可用內存減少。
想像一下，一次 pagecache 未命中就會導致一次磁碟尋址，將耗時 5 毫秒。5 毫秒的
時間內 CPU 能執行很多很多指令。

一個基本的原則是如果一個函數有 3 行以上，就不要把它變成內聯函數。這個原則的一
個例外是，如果你知道某個參數是一個編譯時常量，而且因爲這個常量你確定編譯器在
編譯時能優化掉你的函數的大部分代碼，那仍然可以給它加上 inline 關鍵字。
kmalloc() 內聯函數就是一個很好的例子。

人們經常主張給 static 的而且只用了一次的函數加上 inline，如此不會有任何損失，
因爲沒有什麼好權衡的。雖然從技術上說這是正確的，但是實際上這種情況下即使不加
inline gcc 也可以自動使其內聯。而且其他用戶可能會要求移除 inline，由此而來的
爭論會抵消 inline 自身的潛在價值，得不償失。

16) 函數返回值及命名
------------------------------

函數可以返回多種不同類型的值，最常見的一種是表明函數執行成功或者失敗的值。這樣
的一個值可以表示爲一個錯誤代碼整數 (-Exxx＝失敗，0＝成功) 或者一個 ``成功``
布爾值 (0＝失敗，非0＝成功)。

混合使用這兩種表達方式是難於發現的 bug 的來源。如果 C 語言本身嚴格區分整形和
布爾型變量，那麼編譯器就能夠幫我們發現這些錯誤... 不過 C 語言不區分。爲了避免
產生這種 bug，請遵循下面的慣例::

	如果函數的名字是一個動作或者強制性的命令，那麼這個函數應該返回錯誤代
	碼整數。如果是一個判斷，那麼函數應該返回一個 "成功" 布爾值。

比如， ``add work`` 是一個命令，所以 add_work() 在成功時返回 0，在失敗時返回
-EBUSY。類似的，因爲 ``PCI device present`` 是一個判斷，所以 pci_dev_present()
在成功找到一個匹配的設備時應該返回 1，如果找不到時應該返回 0。

所有 EXPORTed 函數都必須遵守這個慣例，所有的公共函數也都應該如此。私有
(static) 函數不需要如此，但是我們也推薦這樣做。

返回值是實際計算結果而不是計算是否成功的標誌的函數不受此慣例的限制。一般的，
他們通過返回一些正常值範圍之外的結果來表示出錯。典型的例子是返回指針的函數，
他們使用 NULL 或者 ERR_PTR 機制來報告錯誤。

17) 不要重新發明內核宏
------------------------------

頭文件 include/linux/kernel.h 包含了一些宏，你應該使用它們，而不要自己寫一些
它們的變種。比如，如果你需要計算一個數組的長度，使用這個宏

.. code-block:: c

	#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))

類似的，如果你要計算某結構體成員的大小，使用

.. code-block:: c

	#define sizeof_field(t, f) (sizeof(((t*)0)->f))

還有可以做嚴格的類型檢查的 min() 和 max() 宏，如果你需要可以使用它們。你可以
自己看看那個頭文件里還定義了什麼你可以拿來用的東西，如果有定義的話，你就不應
在你的代碼里自己重新定義。

18) 編輯器模式行和其他需要羅嗦的事情
--------------------------------------------------

有一些編輯器可以解釋嵌入在源文件里的由一些特殊標記標明的配置信息。比如，emacs
能夠解釋被標記成這樣的行：

.. code-block:: c

	-*- mode: c -*-

或者這樣的：

.. code-block:: c

	/*
	Local Variables:
	compile-command: "gcc -DMAGIC_DEBUG_FLAG foo.c"
	End:
	*/

Vim 能夠解釋這樣的標記：

.. code-block:: c

	/* vim:set sw=8 noet */

不要在原始碼中包含任何這樣的內容。每個人都有他自己的編輯器配置，你的源文件不
應該覆蓋別人的配置。這包括有關縮進和模式配置的標記。人們可以使用他們自己定製
的模式，或者使用其他可以產生正確的縮進的巧妙方法。

19) 內聯彙編
------------------------------

在特定架構的代碼中，你可能需要內聯彙編與 CPU 和平台相關功能連接。需要這麼做時
就不要猶豫。然而，當 C 可以完成工作時，不要平白無故地使用內聯彙編。在可能的情
況下，你可以並且應該用 C 和硬體溝通。

請考慮去寫捆綁通用位元 (wrap common bits) 的內聯彙編的簡單輔助函數，別去重複
地寫下只有細微差異內聯彙編。記住內聯彙編可以使用 C 參數。

大型，有一定複雜度的彙編函數應該放在 .S 文件內，用相應的 C 原型定義在 C 頭文
件中。彙編函數的 C 原型應該使用 ``asmlinkage`` 。

你可能需要把彙編語句標記爲 volatile，用來阻止 GCC 在沒發現任何副作用後就把它
移除了。你不必總是這樣做，儘管，這不必要的舉動會限制優化。

在寫一個包含多條指令的單個內聯彙編語句時，把每條指令用引號分割而且各占一行，
除了最後一條指令外，在每個指令結尾加上 \n\t，讓彙編輸出時可以正確地縮進下一條
指令：

.. code-block:: c

	asm ("magic %reg1, #42\n\t"
	     "more_magic %reg2, %reg3"
	     : /* outputs */ : /* inputs */ : /* clobbers */);

20) 條件編譯
------------------------------

只要可能，就不要在 .c 文件裡面使用預處理條件 (#if, #ifdef)；這樣做讓代碼更難
閱讀並且更難去跟蹤邏輯。替代方案是，在頭文件中用預處理條件提供給那些 .c 文件
使用，再給 #else 提供一個空樁 (no-op stub) 版本，然後在 .c 文件內無條件地調用
那些 (定義在頭文件內的) 函數。這樣做，編譯器會避免爲樁函數 (stub) 的調用生成
任何代碼，產生的結果是相同的，但邏輯將更加清晰。

最好傾向於編譯整個函數，而不是函數的一部分或表達式的一部分。與其放一個 ifdef
在表達式內，不如分解出部分或全部表達式，放進一個單獨的輔助函數，並應用預處理
條件到這個輔助函數內。

如果你有一個在特定配置中，可能變成未使用的函數或變量，編譯器會警告它定義了但
未使用，把它標記爲 __maybe_unused 而不是將它包含在一個預處理條件中。(然而，如
果一個函數或變量總是未使用，就直接刪除它。)

在代碼中，儘可能地使用 IS_ENABLED 宏來轉化某個 Kconfig 標記爲 C 的布爾
表達式，並在一般的 C 條件中使用它：

.. code-block:: c

	if (IS_ENABLED(CONFIG_SOMETHING)) {
		...
	}

編譯器會做常量摺疊，然後就像使用 #ifdef 那樣去包含或排除代碼塊，所以這不會帶
來任何運行時開銷。然而，這種方法依舊允許 C 編譯器查看塊內的代碼，並檢查它的正
確性 (語法，類型，符號引用，等等)。因此，如果條件不滿足，代碼塊內的引用符號就
不存在時，你還是必須去用 #ifdef。

在任何有意義的 #if 或 #ifdef 塊的末尾 (超過幾行的)，在 #endif 同一行的後面寫下
註解，注釋這個條件表達式。例如：

.. code-block:: c

	#ifdef CONFIG_SOMETHING
	...
	#endif /* CONFIG_SOMETHING */

附錄 I) 參考
-------------------

The C Programming Language, 第二版
作者：Brian W. Kernighan 和 Denni M. Ritchie.
Prentice Hall, Inc., 1988.
ISBN 0-13-110362-8 (軟皮), 0-13-110370-9 (硬皮).

The Practice of Programming
作者：Brian W. Kernighan 和 Rob Pike.
Addison-Wesley, Inc., 1999.
ISBN 0-201-61586-X.

GNU 手冊 - 遵循 K&R 標準和此文本 - cpp, gcc, gcc internals and indent,
都可以從 https://www.gnu.org/manual/ 找到

WG14 是 C 語言的國際標準化工作組，URL: http://www.open-std.org/JTC1/SC22/WG14/

Kernel process/coding-style.rst，作者 greg@kroah.com 發表於 OLS 2002：
http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/


code:
.. SPDX-License-Identifier: GPL-2.0

.. include:: ../disclaimer-zh_TW.rst

:Original: :ref:`Documentation/process/development-process.rst <development_process_main>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>
             Hu Haowen <src.res@email.cn>

.. _tw_development_process_main:

內核開發過程指南
================

內容:

.. toctree::
   :numbered:
   :maxdepth: 2

   1.Intro
   2.Process
   3.Early-stage
   4.Coding
   5.Posting
   6.Followthrough
   7.AdvancedTopics
   8.Conclusion

本文檔的目的是幫助開發人員（及其經理）以最小的挫折感與開發社區合作。它試圖記錄這個社區如何以一種不熟悉Linux內核開發（或者實際上是自由軟體開發）的人可以訪問的方式工作。雖然這裡有一些技術資料，但這是一個面向過程的討論，不需要深入了解內核編程就可以理解。


code:
.. SPDX-License-Identifier: GPL-2.0

.. _tw_email_clients:

.. include:: ../disclaimer-zh_TW.rst

:Original: :ref:`Documentation/process/email-clients.rst <email_clients>`

譯者::

        中文版維護者： 賈威威  Harry Wei <harryxiyou@gmail.com>
        中文版翻譯者： 賈威威  Harry Wei <harryxiyou@gmail.com>
                       時奎亮  Alex Shi <alex.shi@linux.alibaba.com>
        中文版校譯者： Yinglin Luan <synmyth@gmail.com>
        	       Xiaochen Wang <wangxiaochen0@gmail.com>
                       yaxinsn <yaxinsn@163.com>
                      Hu Haowen <src.res@email.cn>

Linux郵件客戶端配置信息
=======================

Git
---

現在大多數開發人員使用 ``git send-email`` 而不是常規的電子郵件客戶端。這方面
的手冊非常好。在接收端，維護人員使用 ``git am`` 加載補丁。

如果你是 ``git`` 新手，那麼把你的第一個補丁發送給你自己。將其保存爲包含所有
標題的原始文本。運行 ``git am raw_email.txt`` ，然後使用 ``git log`` 查看更
改日誌。如果工作正常，再將補丁發送到相應的郵件列表。

普通配置
--------
Linux內核補丁是通過郵件被提交的，最好把補丁作爲郵件體的內嵌文本。有些維護者
接收附件，但是附件的內容格式應該是"text/plain"。然而，附件一般是不贊成的，
因爲這會使補丁的引用部分在評論過程中變的很困難。

用來發送Linux內核補丁的郵件客戶端在發送補丁時應該處於文本的原始狀態。例如，
他們不能改變或者刪除制表符或者空格，甚至是在每一行的開頭或者結尾。

不要通過"format=flowed"模式發送補丁。這樣會引起不可預期以及有害的斷行。

不要讓你的郵件客戶端進行自動換行。這樣也會破壞你的補丁。

郵件客戶端不能改變文本的字符集編碼方式。要發送的補丁只能是ASCII或者UTF-8編碼方式，
如果你使用UTF-8編碼方式發送郵件，那麼你將會避免一些可能發生的字符集問題。

郵件客戶端應該形成並且保持 References: 或者 In-Reply-To: 標題，那麼
郵件話題就不會中斷。

複製粘帖(或者剪貼粘帖)通常不能用於補丁，因爲制表符會轉換爲空格。使用xclipboard, xclip
或者xcutsel也許可以，但是最好測試一下或者避免使用複製粘帖。

不要在使用PGP/GPG署名的郵件中包含補丁。這樣會使得很多腳本不能讀取和適用於你的補丁。
（這個問題應該是可以修復的）

在給內核郵件列表發送補丁之前，給自己發送一個補丁是個不錯的主意，保存接收到的
郵件，將補丁用'patch'命令打上，如果成功了，再給內核郵件列表發送。

一些郵件客戶端提示
------------------
這裡給出一些詳細的MUA配置提示，可以用於給Linux內核發送補丁。這些並不意味是
所有的軟體包配置總結。

說明：
TUI = 以文本爲基礎的用戶接口
GUI = 圖形界面用戶接口

Alpine (TUI)
~~~~~~~~~~~~

配置選項：
在"Sending Preferences"部分：

- "Do Not Send Flowed Text"必須開啓
- "Strip Whitespace Before Sending"必須關閉

當寫郵件時，光標應該放在補丁會出現的地方，然後按下CTRL-R組合鍵，使指定的
補丁文件嵌入到郵件中。

Evolution (GUI)
~~~~~~~~~~~~~~~

一些開發者成功的使用它發送補丁

當選擇郵件選項：Preformat
  從Format->Heading->Preformatted (Ctrl-7)或者工具欄

然後使用：
  Insert->Text File... (Alt-n x)插入補丁文件。

你還可以"diff -Nru old.c new.c | xclip"，選擇Preformat，然後使用中間鍵進行粘帖。

Kmail (GUI)
~~~~~~~~~~~

一些開發者成功的使用它發送補丁。

默認設置不爲HTML格式是合適的；不要啓用它。

當書寫一封郵件的時候，在選項下面不要選擇自動換行。唯一的缺點就是你在郵件中輸入的任何文本
都不會被自動換行，因此你必須在發送補丁之前手動換行。最簡單的方法就是啓用自動換行來書寫郵件，
然後把它保存爲草稿。一旦你在草稿中再次打開它，它已經全部自動換行了，那麼你的郵件雖然沒有
選擇自動換行，但是還不會失去已有的自動換行。

在郵件的底部，插入補丁之前，放上常用的補丁定界符：三個連字號(---)。

然後在"Message"菜單條目，選擇插入文件，接著選取你的補丁文件。還有一個額外的選項，你可以
通過它配置你的郵件建立工具欄菜單，還可以帶上"insert file"圖標。

你可以安全地通過GPG標記附件，但是內嵌補丁最好不要使用GPG標記它們。作爲內嵌文本的簽發補丁，
當從GPG中提取7位編碼時會使他們變的更加複雜。

如果你非要以附件的形式發送補丁，那麼就右鍵點擊附件，然後選中屬性，突出"Suggest automatic
display"，這樣內嵌附件更容易讓讀者看到。

當你要保存將要發送的內嵌文本補丁，你可以從消息列表窗格選擇包含補丁的郵件，然後右擊選擇
"save as"。你可以使用一個沒有更改的包含補丁的郵件，如果它是以正確的形式組成。當你正真在它
自己的窗口之下察看，那時沒有選項可以保存郵件--已經有一個這樣的bug被匯報到了kmail的bugzilla
並且希望這將會被處理。郵件是以只針對某個用戶可讀寫的權限被保存的，所以如果你想把郵件複製到其他地方，
你不得不把他們的權限改爲組或者整體可讀。

Lotus Notes (GUI)
~~~~~~~~~~~~~~~~~

不要使用它。

Mutt (TUI)
~~~~~~~~~~

很多Linux開發人員使用mutt客戶端，所以證明它肯定工作的非常漂亮。

Mutt不自帶編輯器，所以不管你使用什麼編輯器都不應該帶有自動斷行。大多數編輯器都帶有
一個"insert file"選項，它可以通過不改變文件內容的方式插入文件。

'vim'作爲mutt的編輯器：
  set editor="vi"

  如果使用xclip，敲入以下命令
  :set paste
  按中鍵之前或者shift-insert或者使用
  :r filename

如果想要把補丁作爲內嵌文本。
(a)ttach工作的很好，不帶有"set paste"。

你可以通過 ``git format-patch`` 生成補丁，然後用 Mutt發送它們::

        $ mutt -H 0001-some-bug-fix.patch

配置選項：
它應該以默認設置的形式工作。
然而，把"send_charset"設置爲"us-ascii::utf-8"也是一個不錯的主意。

Mutt 是高度可配置的。 這裡是個使用mutt通過 Gmail 發送的補丁的最小配置::

  # .muttrc
  # ================  IMAP ====================
  set imap_user = 'yourusername@gmail.com'
  set imap_pass = 'yourpassword'
  set spoolfile = imaps://imap.gmail.com/INBOX
  set folder = imaps://imap.gmail.com/
  set record="imaps://imap.gmail.com/[Gmail]/Sent Mail"
  set postponed="imaps://imap.gmail.com/[Gmail]/Drafts"
  set mbox="imaps://imap.gmail.com/[Gmail]/All Mail"

  # ================  SMTP  ====================
  set smtp_url = "smtp://username@smtp.gmail.com:587/"
  set smtp_pass = $imap_pass
  set ssl_force_tls = yes # Require encrypted connection

  # ================  Composition  ====================
  set editor = `echo \$EDITOR`
  set edit_headers = yes  # See the headers when editing
  set charset = UTF-8     # value of $LANG; also fallback for send_charset
  # Sender, email address, and sign-off line must match
  unset use_domain        # because joe@localhost is just embarrassing
  set realname = "YOUR NAME"
  set from = "username@gmail.com"
  set use_from = yes

Mutt文檔含有更多信息:

    http://dev.mutt.org/trac/wiki/UseCases/Gmail

    http://dev.mutt.org/doc/manual.html

Pine (TUI)
~~~~~~~~~~

Pine過去有一些空格刪減問題，但是這些現在應該都被修復了。

如果可以，請使用alpine(pine的繼承者)

配置選項：
- 最近的版本需要消除流程文本
- "no-strip-whitespace-before-send"選項也是需要的。

Sylpheed (GUI)
~~~~~~~~~~~~~~

- 內嵌文本可以很好的工作（或者使用附件）。
- 允許使用外部的編輯器。
- 對於目錄較多時非常慢。
- 如果通過non-SSL連接，無法使用TLS SMTP授權。
- 在組成窗口中有一個很有用的ruler bar。
- 給地址本中添加地址就不會正確的了解顯示名。

Thunderbird (GUI)
~~~~~~~~~~~~~~~~~

默認情況下，thunderbird很容易損壞文本，但是還有一些方法可以強制它變得更好。

- 在用戶帳號設置里，組成和尋址，不要選擇"Compose messages in HTML format"。

- 編輯你的Thunderbird配置設置來使它不要拆行使用：user_pref("mailnews.wraplength", 0);

- 編輯你的Thunderbird配置設置，使它不要使用"format=flowed"格式：user_pref("mailnews.
  send_plaintext_flowed", false);

- 你需要使Thunderbird變爲預先格式方式：
  如果默認情況下你書寫的是HTML格式，那不是很難。僅僅從標題欄的下拉框中選擇"Preformat"格式。
  如果默認情況下你書寫的是文本格式，你不得把它改爲HTML格式（僅僅作爲一次性的）來書寫新的消息，
  然後強制使它回到文本格式，否則它就會拆行。要實現它，在寫信的圖標上使用shift鍵來使它變爲HTML
  格式，然後標題欄的下拉框中選擇"Preformat"格式。

- 允許使用外部的編輯器：
  針對Thunderbird打補丁最簡單的方法就是使用一個"external editor"擴展，然後使用你最喜歡的
  $EDITOR來讀取或者合併補丁到文本中。要實現它，可以下載並且安裝這個擴展，然後添加一個使用它的
  按鍵View->Toolbars->Customize...最後當你書寫信息的時候僅僅點擊它就可以了。

TkRat (GUI)
~~~~~~~~~~~

可以使用它。使用"Insert file..."或者外部的編輯器。

Gmail (Web GUI)
~~~~~~~~~~~~~~~

不要使用它發送補丁。

Gmail網頁客戶端自動地把制表符轉換爲空格。

雖然制表符轉換爲空格問題可以被外部編輯器解決，同時它還會使用回車換行把每行拆分爲78個字符。

另一個問題是Gmail還會把任何不是ASCII的字符的信息改爲base64編碼。它把東西變的像歐洲人的名字。

                                ###


code:
.. SPDX-License-Identifier: GPL-2.0

.. include:: ../disclaimer-zh_TW.rst

:Original: :ref:`Documentation/process/embargoed-hardware-issues.rst <embargoed_hardware_issues>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>
             Hu Haowen <src.res@email.cn>

被限制的硬體問題
================

範圍
----

導致安全問題的硬體問題與只影響Linux內核的純軟體錯誤是不同的安全錯誤類別。

必須區別對待諸如熔毀(Meltdown)、Spectre、L1TF等硬體問題，因爲它們通常會影響
所有作業系統（「OS」），因此需要在不同的OS供應商、發行版、硬體供應商和其他各方
之間進行協調。對於某些問題，軟體緩解可能依賴於微碼或固件更新，這需要進一步的
協調。

.. _tw_Contact:

接觸
----

Linux內核硬體安全小組獨立於普通的Linux內核安全小組。

該小組只負責協調被限制的硬體安全問題。Linux內核中純軟體安全漏洞的報告不由該
小組處理，報告者將被引導至常規Linux內核安全小組(:ref:`Documentation/admin-guide/
<securitybugs>`)聯繫。

可以通過電子郵件 <hardware-security@kernel.org> 與小組聯繫。這是一份私密的安全
官名單，他們將幫助您根據我們的文檔化流程協調問題。

郵件列表是加密的，發送到列表的電子郵件可以通過PGP或S/MIME加密，並且必須使用報告
者的PGP密鑰或S/MIME證書籤名。該列表的PGP密鑰和S/MIME證書可從
https://www.kernel.org/.... 獲得。

雖然硬體安全問題通常由受影響的硬體供應商處理，但我們歡迎發現潛在硬體缺陷的研究
人員或個人與我們聯繫。

硬體安全官
^^^^^^^^^^

目前的硬體安全官小組:

  - Linus Torvalds（Linux基金會院士）
  - Greg Kroah Hartman（Linux基金會院士）
  - Thomas Gleixner（Linux基金會院士）

郵件列表的操作
^^^^^^^^^^^^^^

處理流程中使用的加密郵件列表託管在Linux Foundation的IT基礎設施上。通過提供這項
服務，Linux基金會的IT基礎設施安全總監在技術上有能力訪問被限制的信息，但根據他
的僱傭合同，他必須保密。Linux基金會的IT基礎設施安全總監還負責 kernel.org 基礎
設施。

Linux基金會目前的IT基礎設施安全總監是 Konstantin Ryabitsev。

保密協議
--------

Linux內核硬體安全小組不是正式的機構，因此無法簽訂任何保密協議。核心社區意識到
這些問題的敏感性，並提供了一份諒解備忘錄。

諒解備忘錄
----------

Linux內核社區深刻理解在不同作業系統供應商、發行商、硬體供應商和其他各方之間
進行協調時，保持硬體安全問題處於限制狀態的要求。

Linux內核社區在過去已經成功地處理了硬體安全問題，並且有必要的機制允許在限制
限制下進行符合社區的開發。

Linux內核社區有一個專門的硬體安全小組負責初始聯繫，並監督在限制規則下處理
此類問題的過程。

硬體安全小組確定開發人員（領域專家），他們將組成特定問題的初始響應小組。最初
的響應小組可以引入更多的開發人員（領域專家）以最佳的技術方式解決這個問題。

所有相關開發商承諾遵守限制規定，並對收到的信息保密。違反承諾將導致立即從當前
問題中排除，並從所有相關郵件列表中刪除。此外，硬體安全小組還將把違反者排除在
未來的問題之外。這一後果的影響在我們社區是一種非常有效的威懾。如果發生違規
情況，硬體安全小組將立即通知相關方。如果您或任何人發現潛在的違規行爲，請立即
向硬體安全人員報告。

流程
^^^^

由於Linux內核開發的全球分布式特性，面對面的會議幾乎不可能解決硬體安全問題。
由於時區和其他因素，電話會議很難協調，只能在絕對必要時使用。加密電子郵件已被
證明是解決此類問題的最有效和最安全的通信方法。

開始披露
""""""""

披露內容首先通過電子郵件聯繫Linux內核硬體安全小組。此初始聯繫人應包含問題的
描述和任何已知受影響硬體的列表。如果您的組織製造或分發受影響的硬體，我們建議
您也考慮哪些其他硬體可能會受到影響。

硬體安全小組將提供一個特定於事件的加密郵件列表，用於與報告者進行初步討論、
進一步披露和協調。

硬體安全小組將向披露方提供一份開發人員（領域專家）名單，在與開發人員確認他們
將遵守本諒解備忘錄和文件化流程後，應首先告知開發人員有關該問題的信息。這些開發
人員組成初始響應小組，並在初始接觸後負責處理問題。硬體安全小組支持響應小組，
但不一定參與緩解開發過程。

雖然個別開發人員可能通過其僱主受到保密協議的保護，但他們不能以Linux內核開發
人員的身份簽訂個別保密協議。但是，他們將同意遵守這一書面程序和諒解備忘錄。

披露方應提供已經或應該被告知該問題的所有其他實體的聯繫人名單。這有幾個目的:

  - 披露的實體列表允許跨行業通信，例如其他作業系統供應商、硬體供應商等。

  - 可聯繫已披露的實體，指定應參與緩解措施開發的專家。

  - 如果需要處理某一問題的專家受僱於某一上市實體或某一上市實體的成員，則響應
    小組可要求該實體披露該專家。這確保專家也是實體反應小組的一部分。

披露
""""

披露方通過特定的加密郵件列表向初始響應小組提供詳細信息。

根據我們的經驗，這些問題的技術文檔通常是一個足夠的起點，最好通過電子郵件進行
進一步的技術澄清。

緩解開發
""""""""

初始響應小組設置加密郵件列表，或在適當的情況下重新修改現有郵件列表。

使用郵件列表接近於正常的Linux開發過程，並且在過去已經成功地用於爲各種硬體安全
問題開發緩解措施。

郵件列表的操作方式與正常的Linux開發相同。發布、討論和審查修補程序，如果同意，
則應用於非公共git存儲庫，參與開發人員只能通過安全連接訪問該存儲庫。存儲庫包含
針對主線內核的主開發分支，並根據需要爲穩定的內核版本提供向後移植分支。

最初的響應小組將根據需要從Linux內核開發人員社區中確定更多的專家。引進專家可以
在開發過程中的任何時候發生，需要及時處理。

如果專家受僱於披露方提供的披露清單上的實體或其成員，則相關實體將要求其參與。

否則，披露方將被告知專家參與的情況。諒解備忘錄涵蓋了專家，要求披露方確認參與。
如果披露方有令人信服的理由提出異議，則必須在五個工作日內提出異議，並立即與事件
小組解決。如果披露方在五個工作日內未作出回應，則視爲默許。

在確認或解決異議後，專家由事件小組披露，並進入開發過程。

協調發布
""""""""

有關各方將協商限制結束的日期和時間。此時，準備好的緩解措施集成到相關的內核樹中
並發布。

雖然我們理解硬體安全問題需要協調限制時間，但限制時間應限制在所有有關各方制定、
測試和準備緩解措施所需的最短時間內。人爲地延長限制時間以滿足會議討論日期或其他
非技術原因，會給相關的開發人員和響應小組帶來了更多的工作和負擔，因爲補丁需要
保持最新，以便跟蹤正在進行的上游內核開發，這可能會造成衝突的更改。

CVE分配
"""""""

硬體安全小組和初始響應小組都不分配CVE，開發過程也不需要CVE。如果CVE是由披露方
提供的，則可用於文檔中。

流程專使
--------

爲了協助這一進程，我們在各組織設立了專使，他們可以回答有關報告流程和進一步處理
的問題或提供指導。專使不參與特定問題的披露，除非響應小組或相關披露方提出要求。
現任專使名單:

  ============= ========================================================
  ARM
  AMD		Tom Lendacky <thomas.lendacky@amd.com>
  IBM
  Intel		Tony Luck <tony.luck@intel.com>
  Qualcomm	Trilok Soni <tsoni@codeaurora.org>

  Microsoft	Sasha Levin <sashal@kernel.org>
  VMware
  Xen		Andrew Cooper <andrew.cooper3@citrix.com>

  Canonical	John Johansen <john.johansen@canonical.com>
  Debian	Ben Hutchings <ben@decadent.org.uk>
  Oracle	Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
  Red Hat	Josh Poimboeuf <jpoimboe@redhat.com>
  SUSE		Jiri Kosina <jkosina@suse.cz>

  Amazon
  Google	Kees Cook <keescook@chromium.org>
  ============= ========================================================

如果要將您的組織添加到專使名單中，請與硬體安全小組聯繫。被提名的專使必須完全
理解和支持我們的過程，並且在Linux內核社區中很容易聯繫。

加密郵件列表
------------

我們使用加密郵件列表進行通信。這些列表的工作原理是，發送到列表的電子郵件使用
列表的PGP密鑰或列表的/MIME證書進行加密。郵件列表軟體對電子郵件進行解密，並
使用訂閱者的PGP密鑰或S/MIME證書爲每個訂閱者分別對其進行重新加密。有關郵件列表
軟體和用於確保列表安全和數據保護的設置的詳細信息，請訪問:
https://www.kernel.org/....

關鍵點
^^^^^^

初次接觸見 :ref:`tw_Contact`. 對於特定於事件的郵件列表，密鑰和S/MIME證書通過
特定列表發送的電子郵件傳遞給訂閱者。

訂閱事件特定列表
^^^^^^^^^^^^^^^^

訂閱由響應小組處理。希望參與通信的披露方將潛在訂戶的列表發送給響應組，以便
響應組可以驗證訂閱請求。

每個訂戶都需要通過電子郵件向響應小組發送訂閱請求。電子郵件必須使用訂閱伺服器
的PGP密鑰或S/MIME證書籤名。如果使用PGP密鑰，則必須從公鑰伺服器獲得該密鑰，
並且理想情況下該密鑰連接到Linux內核的PGP信任網。另請參見:
https://www.kernel.org/signature.html.

響應小組驗證訂閱者，並將訂閱者添加到列表中。訂閱後，訂閱者將收到來自郵件列表
的電子郵件，該郵件列表使用列表的PGP密鑰或列表的/MIME證書籤名。訂閱者的電子郵件
客戶端可以從簽名中提取PGP密鑰或S/MIME證書，以便訂閱者可以向列表發送加密電子
郵件。


code:
.. SPDX-License-Identifier: GPL-2.0

.. _tw_process_howto:

.. include:: ../disclaimer-zh_TW.rst

:Original: :ref:`Documentation/process/howto.rst <process_howto>`

譯者::

    英文版維護者： Greg Kroah-Hartman <greg@kroah.com>
    中文版維護者： 李陽  Li Yang <leoyang.li@nxp.com>
    中文版翻譯者： 李陽  Li Yang <leoyang.li@nxp.com>
                   時奎亮 Alex Shi <alex.shi@linux.alibaba.com>
    中文版校譯者:
                   鍾宇  TripleX Chung <xxx.phy@gmail.com>
                   陳琦  Maggie Chen <chenqi@beyondsoft.com>
                   王聰  Wang Cong <xiyou.wangcong@gmail.com>
                   胡皓文 Hu Haowen <src.res@email.cn>

如何參與Linux內核開發
=====================

這是一篇將如何參與Linux內核開發的相關問題一網打盡的終極祕笈。它將指導你
成爲一名Linux內核開發者，並且學會如何同Linux內核開發社區合作。它儘可能不
包括任何關於內核編程的技術細節，但會給你指引一條獲得這些知識的正確途徑。

如果這篇文章中的任何內容不再適用，請給文末列出的文件維護者發送補丁。

入門
----

你想了解如何成爲一名Linux內核開發者？或者老闆吩咐你「給這個設備寫個Linux
驅動程序」？這篇文章的目的就是教會你達成這些目標的全部訣竅，它將描述你需
要經過的流程以及給出如何同內核社區合作的一些提示。它還將試圖解釋內核社區
爲何這樣運作。

Linux內核大部分是由C語言寫成的，一些體系結構相關的代碼用到了彙編語言。要
參與內核開發，你必須精通C語言。除非你想爲某個架構開發底層代碼，否則你並
不需要了解（任何體系結構的）彙編語言。下面列舉的書籍雖然不能替代紮實的C
語言教育和多年的開發經驗，但如果需要的話，做爲參考還是不錯的：

 - "The C Programming Language" by Kernighan and Ritchie [Prentice Hall]
   《C程序設計語言（第2版·新版）》（徐寶文 李志 譯）[機械工業出版社]
 - "Practical C Programming" by Steve Oualline [O'Reilly]
   《實用C語言編程（第三版）》（郭大海 譯）[中國電力出版社]
 - "C:  A Reference Manual" by Harbison and Steele [Prentice Hall]
   《C語言參考手冊（原書第5版）》（邱仲潘 等譯）[機械工業出版社]

Linux內核使用GNU C和GNU工具鏈開發。雖然它遵循ISO C11標準，但也用到了一些
標準中沒有定義的擴展。內核是自給自足的C環境，不依賴於標準C庫的支持，所以
並不支持C標準中的部分定義。比如long long類型的大數除法和浮點運算就不允許
使用。有時候確實很難弄清楚內核對工具鏈的要求和它所使用的擴展，不幸的是目
前還沒有明確的參考資料可以解釋它們。請查閱gcc信息頁（使用「info gcc」命令
顯示）獲得一些這方面信息。

請記住你是在學習怎麼和已經存在的開發社區打交道。它由一羣形形色色的人組成，
他們對代碼、風格和過程有著很高的標準。這些標準是在長期實踐中總結出來的，
適應於地理上分散的大型開發團隊。它們已經被很好得整理成檔，建議你在開發
之前儘可能多的學習這些標準，而不要期望別人來適應你或者你公司的行爲方式。

法律問題
--------

Linux內核原始碼都是在GPL（通用公共許可證）的保護下發布的。要了解這種許可
的細節請查看原始碼主目錄下的COPYING文件。Linux內核許可準則和如何使用
`SPDX <https://spdx.org/>` 標誌符說明在這個文件中
:ref:`Documentation/translations/zh_TW/process/license-rules.rst <tw_kernel_licensing>`
如果你對它還有更深入問題請聯繫律師，而不要在Linux內核郵件組上提問。因爲
郵件組裡的人並不是律師，不要期望他們的話有法律效力。

對於GPL的常見問題和解答，請訪問以下連結：
	https://www.gnu.org/licenses/gpl-faq.html

文檔
----

Linux內核代碼中包含有大量的文檔。這些文檔對於學習如何與內核社區互動有著
不可估量的價值。當一個新的功能被加入內核，最好把解釋如何使用這個功能的文
檔也放進內核。當內核的改動導致面向用戶空間的接口發生變化時，最好將相關信
息或手冊頁(manpages)的補丁發到mtk.manpages@gmail.com，以向手冊頁(manpages)
的維護者解釋這些變化。

以下是內核代碼中需要閱讀的文檔：
  :ref:`Documentation/admin-guide/README.rst <readme>`
    文件簡要介紹了Linux內核的背景，並且描述了如何配置和編譯內核。內核的
    新用戶應該從這裡開始。

  :ref:`Documentation/process/changes.rst <changes>`
    文件給出了用來編譯和使用內核所需要的最小軟體包列表。

  :ref:`Documentation/translations/zh_TW/process/coding-style.rst <tw_codingstyle>`
    描述Linux內核的代碼風格和理由。所有新代碼需要遵守這篇文檔中定義的規
    范。大多數維護者只會接收符合規定的補丁，很多人也只會幫忙檢查符合風格
    的代碼。

  :ref:`Documentation/translations/zh_TW/process/submitting-patches.rst <tw_submittingpatches>`

    這兩份文檔明確描述如何創建和發送補丁，其中包括（但不僅限於)：
       - 郵件內容
       - 郵件格式
       - 選擇收件人

    遵守這些規定並不能保證提交成功（因爲所有補丁需要通過嚴格的內容和風格
    審查），但是忽視他們幾乎就意味著失敗。

    其他關於如何正確地生成補丁的優秀文檔包括：
    "The Perfect Patch"

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

    "Linux kernel patch submission format"

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

  :ref:`Documentation/translations/zh_TW/process/stable-api-nonsense.rst <tw_stable_api_nonsense>`
    論證內核爲什麼特意不包括穩定的內核內部API，也就是說不包括像這樣的特
    性：

       - 子系統中間層（爲了兼容性？）
       - 在不同作業系統間易於移植的驅動程序
       - 減緩（甚至阻止）內核代碼的快速變化

    這篇文檔對於理解Linux的開發哲學至關重要。對於將開發平台從其他操作系
    統轉移到Linux的人來說也很重要。

  :ref:`Documentation/admin-guide/security-bugs.rst <securitybugs>`
    如果你認爲自己發現了Linux內核的安全性問題，請根據這篇文檔中的步驟來
    提醒其他內核開發者並幫助解決這個問題。

  :ref:`Documentation/translations/zh_TW/process/management-style.rst <tw_managementstyle>`

    描述內核維護者的工作方法及其共有特點。這對於剛剛接觸內核開發（或者對
    它感到好奇）的人來說很重要，因爲它解釋了很多對於內核維護者獨特行爲的
    普遍誤解與迷惑。

  :ref:`Documentation/process/stable-kernel-rules.rst <stable_kernel_rules>`
    解釋了穩定版內核發布的規則，以及如何將改動放入這些版本的步驟。

  :ref:`Documentation/process/kernel-docs.rst <kernel_docs>`
    有助於內核開發的外部文檔列表。如果你在內核自帶的文檔中沒有找到你想找
    的內容，可以查看這些文檔。

  :ref:`Documentation/process/applying-patches.rst <applying_patches>`
    關於補丁是什麼以及如何將它打在不同內核開發分支上的好介紹

內核還擁有大量從代碼自動生成或者從 ReStructuredText(ReST) 標記生成的文檔，
比如這個文檔，它包含內核內部API的全面介紹以及如何妥善處理加鎖的規則。所有
這些文檔都可以通過運行以下命令從內核代碼中生成爲PDF或HTML文檔::

    make pdfdocs
    make htmldocs

ReST格式的文檔會生成在 Documentation/output. 目錄中。
它們也可以用下列命令生成 LaTeX 和 ePub 格式文檔::

    make latexdocs
    make epubdocs

如何成爲內核開發者
------------------
如果你對Linux內核開發一無所知，你應該訪問「Linux內核新手」計劃：

	https://kernelnewbies.org

它擁有一個可以問各種最基本的內核開發問題的郵件列表（在提問之前一定要記得
查找已往的郵件，確認是否有人已經回答過相同的問題）。它還擁有一個可以獲得
實時反饋的IRC聊天頻道，以及大量對於學習Linux內核開發相當有幫助的文檔。

網站簡要介紹了原始碼組織結構、子系統劃分以及目前正在進行的項目（包括內核
中的和單獨維護的）。它還提供了一些基本的幫助信息，比如如何編譯內核和打補
丁。

如果你想加入內核開發社區並協助完成一些任務，卻找不到從哪裡開始，可以訪問
「Linux內核房管員」計劃：

	https://kernelnewbies.org/KernelJanitors

這是極佳的起點。它提供一個相對簡單的任務列表，列出內核代碼中需要被重新
整理或者改正的地方。通過和負責這個計劃的開發者們一同工作，你會學到將補丁
集成進內核的基本原理。如果還沒有決定下一步要做什麼的話，你還可能會得到方
向性的指點。

在真正動手修改內核代碼之前，理解要修改的代碼如何運作是必需的。要達到這個
目的，沒什麼辦法比直接讀代碼更有效了（大多數花招都會有相應的注釋），而且
一些特製的工具還可以提供幫助。例如，「Linux代碼交叉引用」項目就是一個值得
特別推薦的幫助工具，它將原始碼顯示在有編目和索引的網頁上。其中一個更新及
時的內核源碼庫，可以通過以下地址訪問：

        https://elixir.bootlin.com/

開發流程
--------

目前Linux內核開發流程包括幾個「主內核分支」和很多子系統相關的內核分支。這
些分支包括：

  - Linus 的內核源碼樹
  - 多個主要版本的穩定版內核樹
  - 子系統相關的內核樹
  - linux-next 集成測試樹

主線樹
------
主線樹是由Linus Torvalds 維護的。你可以在https://kernel.org 網站或者代碼
庫中下找到它。它的開發遵循以下步驟：

  - 每當一個新版本的內核被發布，爲期兩周的集成窗口將被打開。在這段時間裡
    維護者可以向Linus提交大段的修改，通常這些修改已經被放到-mm內核中幾個
    星期了。提交大量修改的首選方式是使用git工具（內核的代碼版本管理工具
    ，更多的信息可以在 https://git-scm.com/ 獲取），不過使用普通補丁也是
    可以的。
  - 兩個星期以後-rc1版本內核發布。之後只有不包含可能影響整個內核穩定性的
    新功能的補丁才可能被接受。請注意一個全新的驅動程序（或者文件系統）有
    可能在-rc1後被接受是因爲這樣的修改完全獨立，不會影響其他的代碼，所以
    沒有造成內核退步的風險。在-rc1以後也可以用git向Linus提交補丁，不過所
    有的補丁需要同時被發送到相應的公衆郵件列表以徵詢意見。
  - 當Linus認爲當前的git源碼樹已經達到一個合理健全的狀態足以發布供人測試
    時，一個新的-rc版本就會被發布。計劃是每周都發布新的-rc版本。
  - 這個過程一直持續下去直到內核被認爲達到足夠穩定的狀態，持續時間大概是
    6個星期。

關於內核發布，值得一提的是Andrew Morton在linux-kernel郵件列表中如是說：
	「沒有人知道新內核何時會被發布，因爲發布是根據已知bug的情況來決定
	的，而不是根據一個事先制定好的時間表。」

子系統特定樹
------------

各種內核子系統的維護者——以及許多內核子系統開發人員——在原始碼庫中公開了他們
當前的開發狀態。這樣，其他人就可以看到內核的不同區域發生了什麼。在開發速度
很快的領域，可能會要求開發人員將提交的內容建立在這樣的子系統內核樹上，這樣
就避免了提交與其他已經進行的工作之間的衝突。

這些存儲庫中的大多數都是Git樹，但是也有其他的scm在使用，或者補丁隊列被發布
爲Quilt系列。這些子系統存儲庫的地址列在MAINTAINERS文件中。其中許多可以在
https://git.kernel.org/上瀏覽。

在將一個建議的補丁提交到這樣的子系統樹之前，需要對它進行審查，審查主要發生
在郵件列表上（請參見下面相應的部分）。對於幾個內核子系統，這個審查過程是通
過工具補丁跟蹤的。Patchwork提供了一個Web界面，顯示補丁發布、對補丁的任何評
論或修訂，維護人員可以將補丁標記爲正在審查、接受或拒絕。大多數補丁網站都列
在 https://patchwork.kernel.org/

Linux-next 集成測試樹
---------------------

在將子系統樹的更新合併到主線樹之前，需要對它們進行集成測試。爲此，存在一個
特殊的測試存儲庫，其中幾乎每天都會提取所有子系統樹：

        https://git.kernel.org/？p=linux/kernel/git/next/linux-next.git

通過這種方式，Linux-next 對下一個合併階段將進入主線內核的內容給出了一個概要
展望。非常歡冒險的測試者運行測試Linux-next。

多個主要版本的穩定版內核樹
-----------------------------------
由3個數字組成的內核版本號說明此內核是-stable版本。它們包含內核的相對較小且
至關重要的修補，這些修補針對安全性問題或者嚴重的內核退步。

這種版本的內核適用於那些期望獲得最新的穩定版內核並且不想參與測試開發版或
者實驗版的用戶。

穩定版內核樹版本由「穩定版」小組（郵件地址<stable@vger.kernel.org>）維護，一般
隔周發布新版本。

內核源碼中的 :ref:`Documentation/process/stable-kernel-rules.rst <stable_kernel_rules>`
文件具體描述了可被穩定版內核接受的修改類型以及發布的流程。

報告bug
-------

bugzilla.kernel.org是Linux內核開發者們用來跟蹤內核Bug的網站。我們鼓勵用
戶在這個工具中報告找到的所有bug。如何使用內核bugzilla的細節請訪問：

	http://test.kernel.org/bugzilla/faq.html

內核源碼主目錄中的:ref:`admin-guide/reporting-bugs.rst <reportingbugs>`
文件里有一個很好的模板。它指導用戶如何報告可能的內核bug以及需要提供哪些信息
來幫助內核開發者們找到問題的根源。

利用bug報告
-----------

練習內核開發技能的最好辦法就是修改其他人報告的bug。你不光可以幫助內核變
得更加穩定，還可以學會如何解決實際問題從而提高自己的技能，並且讓其他開發
者感受到你的存在。修改bug是贏得其他開發者讚譽的最好辦法，因爲並不是很多
人都喜歡浪費時間去修改別人報告的bug。

要嘗試修改已知的bug，請訪問 http://bugzilla.kernel.org 網址。

郵件列表
--------

正如上面的文檔所描述，大多數的骨幹內核開發者都加入了Linux Kernel郵件列
表。如何訂閱和退訂列表的細節可以在這裡找到：

	http://vger.kernel.org/vger-lists.html#linux-kernel

網上很多地方都有這個郵件列表的存檔(archive)。可以使用搜尋引擎來找到這些
存檔。比如：

	https://lore.kernel.org/lkml/

在發信之前，我們強烈建議你先在存檔中搜索你想要討論的問題。很多已經被詳細
討論過的問題只在郵件列表的存檔中可以找到。

大多數內核子系統也有自己獨立的郵件列表來協調各自的開發工作。從
MAINTAINERS文件中可以找到不同話題對應的郵件列表。

很多郵件列表架設在kernel.org伺服器上。這些列表的信息可以在這裡找到：

	http://vger.kernel.org/vger-lists.html

在使用這些郵件列表時，請記住保持良好的行爲習慣。下面的連結提供了與這些列
表（或任何其它郵件列表）交流的一些簡單規則，雖然內容有點濫竽充數。

	http://www.albion.com/netiquette/

當有很多人回覆你的郵件時，郵件的抄送列表會變得很長。請不要將任何人從抄送
列表中刪除，除非你有足夠的理由這麼做。也不要只回復到郵件列表。請習慣於同
一封郵件接收兩次（一封來自發送者一封來自郵件列表），而不要試圖通過添加一
些奇特的郵件頭來解決這個問題，人們不會喜歡的。

記住保留你所回復內容的上下文和源頭。在你回覆郵件的頂部保留「某某某說到……」
這幾行。將你的評論加在被引用的段落之間而不要放在郵件的頂部。

如果你在郵件中附帶補丁，請確認它們是可以直接閱讀的純文本（如
:ref:`Documentation/translations/zh_TW/process/submitting-patches.rst <tw_submittingpatches>`
文檔中所述）。內核開發者們不希望遇到附件或者被壓縮了的補丁。只有這樣才能
保證他們可以直接評論你的每行代碼。請確保你使用的郵件發送程序不會修改空格
和制表符。一個防範性的測試方法是先將郵件發送給自己，然後自己嘗試是否可以
順利地打上收到的補丁。如果測試不成功，請調整或者更換你的郵件發送程序直到
它正確工作爲止。

總而言之，請尊重其他的郵件列表訂閱者。

同內核社區合作
----------------

內核社區的目標就是提供盡善盡美的內核。所以當你提交補丁期望被接受進內核的
時候，它的技術價值以及其他方面都將被評審。那麼你可能會得到什麼呢？

  - 批評
  - 評論
  - 要求修改
  - 要求證明修改的必要性
  - 沉默

要記住，這些是把補丁放進內核的正常情況。你必須學會聽取對補丁的批評和評論，
從技術層面評估它們，然後要麼重寫你的補丁要麼簡明扼要地論證修改是不必要
的。如果你發的郵件沒有得到任何回應，請過幾天後再試一次，因爲有時信件會湮
沒在茫茫信海中。

你不應該做的事情：

  - 期望自己的補丁不受任何質疑就直接被接受
  - 翻臉
  - 忽略別人的評論
  - 沒有按照別人的要求做任何修改就重新提交

在一個努力追尋最好技術方案的社區里，對於一個補丁有多少好處總會有不同的見
解。你必須要抱著合作的態度，願意改變自己的觀點來適應內核的風格。或者至少
願意去證明你的想法是有價值的。記住，犯錯誤是允許的，只要你願意朝著正確的
方案去努力。

如果你的第一個補丁換來的是一堆修改建議，這是很正常的。這並不代表你的補丁
不會被接受，也不意味著有人和你作對。你只需要改正所有提出的問題然後重新發
送你的補丁。

內核社區和公司文化的差異
------------------------

內核社區的工作模式同大多數傳統公司開發隊伍的工作模式並不相同。下面這些例
子，可以幫助你避免某些可能發生問題：
用這些話介紹你的修改提案會有好處：

    - 它同時解決了多個問題
    - 它刪除了2000行代碼
    - 這是補丁，它已經解釋了我想要說明的
    - 我在5種不同的體系結構上測試過它……
    - 這是一系列小補丁用來……
    - 這個修改提高了普通機器的性能……

應該避免如下的說法：

    - 我們在AIX/ptx/Solaris就是這麼做的，所以這麼做肯定是好的……
    - 我做這行已經20年了，所以……
    - 爲了我們公司賺錢考慮必須這麼做
    - 這是我們的企業產品線所需要的
    - 這裡是描述我觀點的1000頁設計文檔
    - 這是一個5000行的補丁用來……
    - 我重寫了現在亂七八糟的代碼，這就是……
    - 我被規定了最後期限，所以這個補丁需要立刻被接受

另外一個內核社區與大部分傳統公司的軟體開發隊伍不同的地方是無法面對面地交
流。使用電子郵件和IRC聊天工具做爲主要溝通工具的一個好處是性別和種族歧視
將會更少。Linux內核的工作環境更能接受婦女和少數族羣，因爲每個人在別人眼
里只是一個郵件地址。國際化也幫助了公平的實現，因爲你無法通過姓名來判斷人
的性別。男人有可能叫李麗，女人也有可能叫王剛。大多數在Linux內核上工作過
並表達過看法的女性對在linux上工作的經歷都給出了正面的評價。

對於一些不習慣使用英語的人來說，語言可能是一個引起問題的障礙。在郵件列表
中要正確地表達想法必需良好地掌握語言，所以建議你在發送郵件之前最好檢查一
下英文寫得是否正確。

拆分修改
--------

Linux內核社區並不喜歡一下接收大段的代碼。修改需要被恰當地介紹、討論並且
拆分成獨立的小段。這幾乎完全和公司中的習慣背道而馳。你的想法應該在開發最
開始的階段就讓大家知道，這樣你就可以及時獲得對你正在進行的開發的反饋。這
樣也會讓社區覺得你是在和他們協作，而不是僅僅把他們當作傾銷新功能的對象。
無論如何，你不要一次性地向郵件列表發送50封信，你的補丁序列應該永遠用不到
這麼多。

將補丁拆開的原因如下：

1) 小的補丁更有可能被接受，因爲它們不需要太多的時間和精力去驗證其正確性。
   一個5行的補丁，可能在維護者看了一眼以後就會被接受。而500行的補丁則
   需要數個小時來審查其正確性（所需時間隨補丁大小增加大約呈指數級增長）。

   當出了問題的時候，小的補丁也會讓調試變得非常容易。一個一個補丁地回溯
   將會比仔細剖析一個被打上的大補丁（這個補丁破壞了其他東西）容易得多。

2）不光發送小的補丁很重要，在提交之前重新編排、化簡（或者僅僅重新排列）
   補丁也是很重要的。

這裡有內核開發者Al Viro打的一個比方：
	「想像一個老師正在給學生批改數學作業。老師並不希望看到學生爲了得
	到正確解法所進行的嘗試和產生的錯誤。他希望看到的是最乾淨最優雅的
	解答。好學生了解這點，絕不會把最終解決之前的中間方案提交上去。」

	內核開發也是這樣。維護者和評審者不希望看到一個人在解決問題時的思
	考過程。他們只希望看到簡單和優雅的解決方案。

直接給出一流的解決方案，和社區一起協作討論尚未完成的工作，這兩者之間似乎
很難找到一個平衡點。所以最好儘早開始收集有利於你進行改進的反饋；同時也要
保證修改分成很多小塊，這樣在整個項目都準備好被包含進內核之前，其中的一部
分可能會先被接收。

必須了解這樣做是不可接受的：試圖將未完成的工作提交進內核，然後再找時間修
復。

證明修改的必要性
----------------
除了將補丁拆成小塊，很重要的一點是讓Linux社區了解他們爲什麼需要這樣修改。
你必須證明新功能是有人需要的並且是有用的。

記錄修改
--------

當你發送補丁的時候，需要特別留意郵件正文的內容。因爲這裡的信息將會做爲補
丁的修改記錄(ChangeLog)，會被一直保留以備大家查閱。它需要完全地描述補丁，
包括：

  - 爲什麼需要這個修改
  - 補丁的總體設計
  - 實現細節
  - 測試結果

想了解它具體應該看起來像什麼，請查閱以下文檔中的「ChangeLog」章節：
  「The Perfect Patch」
  	 https://www.ozlabs.org/~akpm/stuff/tpp.txt

這些事情有時候做起來很難。要在任何方面都做到完美可能需要好幾年時間。這是
一個持續提高的過程，它需要大量的耐心和決心。只要不放棄，你一定可以做到。
很多人已經做到了，而他們都曾經和現在的你站在同樣的起點上。

感謝
----
感謝Paolo Ciarrocchi允許「開發流程」部分基於他所寫的文章
(http://www.kerneltravel.net/newbie/2.6-development_process)，感謝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的評審、建議和貢獻。沒有他們的幫助，這篇文檔是不可
能完成的。

英文版維護者： Greg Kroah-Hartman <greg@kroah.com>


code:
.. SPDX-License-Identifier: GPL-2.0

.. raw:: latex

	\renewcommand\thesection*
	\renewcommand\thesubsection*

.. include:: ../disclaimer-zh_TW.rst

:Original: :ref:`Documentation/process/index.rst <process_index>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>
             Hu Haowen <src.res@email.cn>

.. _tw_process_index:

與Linux 內核社區一起工作
========================

你想成爲Linux內核開發人員嗎？歡迎之至！在學習許多關於內核的技術知識的同時，
了解我們社區的工作方式也很重要。閱讀這些文檔可以讓您以更輕鬆的、麻煩更少的
方式將更改合併到內核。

以下是每位開發人員都應閱讀的基本指南：

.. toctree::
   :maxdepth: 1

   howto
   code-of-conduct
   code-of-conduct-interpretation
   submitting-patches
   programming-language
   coding-style
   development-process
   email-clients
   license-rules
   kernel-enforcement-statement
   kernel-driver-statement

其它大多數開發人員感興趣的社區指南：

.. toctree::
   :maxdepth: 1

   submit-checklist
   stable-api-nonsense
   stable-kernel-rules
   management-style
   embargoed-hardware-issues

這些是一些總體性技術指南，由於不大好分類而放在這裡：

.. toctree::
   :maxdepth: 1

   magic-number
   volatile-considered-harmful

.. only::  subproject and html

   目錄
   ====

   * :ref:`genindex`


code:
.. SPDX-License-Identifier: GPL-2.0

.. _zh_process_statement_driver:

.. include:: ../disclaimer-zh_TW.rst

:Original: :ref:`Documentation/process/kernel-driver-statement.rst <process_statement_driver>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>
             Hu Haowen <src.res@email.cn>

內核驅動聲明
------------

關於Linux內核模塊的立場聲明
===========================

我們，以下署名的Linux內核開發人員，認爲任何封閉源Linux內核模塊或驅動程序都是
有害的和不可取的。我們已經一再發現它們對Linux用戶，企業和更大的Linux生態系統
有害。這樣的模塊否定了Linux開發模型的開放性，穩定性，靈活性和可維護性，並使
他們的用戶無法使用Linux社區的專業知識。提供閉源內核模塊的供應商迫使其客戶
放棄Linux的主要優勢或選擇新的供應商。因此，爲了充分利用開源所提供的成本節省和
共享支持優勢，我們敦促供應商採取措施，以開源內核代碼在Linux上爲其客戶提供支持。

我們只爲自己說話，而不是我們今天可能會爲之工作，過去或將來會爲之工作的任何公司。

 - Dave Airlie
 - Nick Andrew
 - Jens Axboe
 - Ralf Baechle
 - Felipe Balbi
 - Ohad Ben-Cohen
 - Muli Ben-Yehuda
 - Jiri Benc
 - Arnd Bergmann
 - Thomas Bogendoerfer
 - Vitaly Bordug
 - James Bottomley
 - Josh Boyer
 - Neil Brown
 - Mark Brown
 - David Brownell
 - Michael Buesch
 - Franck Bui-Huu
 - Adrian Bunk
 - François Cami
 - Ralph Campbell
 - Luiz Fernando N. Capitulino
 - Mauro Carvalho Chehab
 - Denis Cheng
 - Jonathan Corbet
 - Glauber Costa
 - Alan Cox
 - Magnus Damm
 - Ahmed S. Darwish
 - Robert P. J. Day
 - Hans de Goede
 - Arnaldo Carvalho de Melo
 - Helge Deller
 - Jean Delvare
 - Mathieu Desnoyers
 - Sven-Thorsten Dietrich
 - Alexey Dobriyan
 - Daniel Drake
 - Alex Dubov
 - Randy Dunlap
 - Michael Ellerman
 - Pekka Enberg
 - Jan Engelhardt
 - Mark Fasheh
 - J. Bruce Fields
 - Larry Finger
 - Jeremy Fitzhardinge
 - Mike Frysinger
 - Kumar Gala
 - Robin Getz
 - Liam Girdwood
 - Jan-Benedict Glaw
 - Thomas Gleixner
 - Brice Goglin
 - Cyrill Gorcunov
 - Andy Gospodarek
 - Thomas Graf
 - Krzysztof Halasa
 - Harvey Harrison
 - Stephen Hemminger
 - Michael Hennerich
 - Tejun Heo
 - Benjamin Herrenschmidt
 - Kristian Høgsberg
 - Henrique de Moraes Holschuh
 - Marcel Holtmann
 - Mike Isely
 - Takashi Iwai
 - Olof Johansson
 - Dave Jones
 - Jesper Juhl
 - Matthias Kaehlcke
 - Kenji Kaneshige
 - Jan Kara
 - Jeremy Kerr
 - Russell King
 - Olaf Kirch
 - Roel Kluin
 - Hans-Jürgen Koch
 - Auke Kok
 - Peter Korsgaard
 - Jiri Kosina
 - Aaro Koskinen
 - Mariusz Kozlowski
 - Greg Kroah-Hartman
 - Michael Krufky
 - Aneesh Kumar
 - Clemens Ladisch
 - Christoph Lameter
 - Gunnar Larisch
 - Anders Larsen
 - Grant Likely
 - John W. Linville
 - Yinghai Lu
 - Tony Luck
 - Pavel Machek
 - Matt Mackall
 - Paul Mackerras
 - Roland McGrath
 - Patrick McHardy
 - Kyle McMartin
 - Paul Menage
 - Thierry Merle
 - Eric Miao
 - Akinobu Mita
 - Ingo Molnar
 - James Morris
 - Andrew Morton
 - Paul Mundt
 - Oleg Nesterov
 - Luca Olivetti
 - S.Çağlar Onur
 - Pierre Ossman
 - Keith Owens
 - Venkatesh Pallipadi
 - Nick Piggin
 - Nicolas Pitre
 - Evgeniy Polyakov
 - Richard Purdie
 - Mike Rapoport
 - Sam Ravnborg
 - Gerrit Renker
 - Stefan Richter
 - David Rientjes
 - Luis R. Rodriguez
 - Stefan Roese
 - Francois Romieu
 - Rami Rosen
 - Stephen Rothwell
 - Maciej W. Rozycki
 - Mark Salyzyn
 - Yoshinori Sato
 - Deepak Saxena
 - Holger Schurig
 - Amit Shah
 - Yoshihiro Shimoda
 - Sergei Shtylyov
 - Kay Sievers
 - Sebastian Siewior
 - Rik Snel
 - Jes Sorensen
 - Alexey Starikovskiy
 - Alan Stern
 - Timur Tabi
 - Hirokazu Takata
 - Eliezer Tamir
 - Eugene Teo
 - Doug Thompson
 - FUJITA Tomonori
 - Dmitry Torokhov
 - Marcelo Tosatti
 - Steven Toth
 - Theodore Tso
 - Matthias Urlichs
 - Geert Uytterhoeven
 - Arjan van de Ven
 - Ivo van Doorn
 - Rik van Riel
 - Wim Van Sebroeck
 - Hans Verkuil
 - Horst H. von Brand
 - Dmitri Vorobiev
 - Anton Vorontsov
 - Daniel Walker
 - Johannes Weiner
 - Harald Welte
 - Matthew Wilcox
 - Dan J. Williams
 - Darrick J. Wong
 - David Woodhouse
 - Chris Wright
 - Bryan Wu
 - Rafael J. Wysocki
 - Herbert Xu
 - Vlad Yasevich
 - Peter Zijlstra
 - Bartlomiej Zolnierkiewicz


code:
.. SPDX-License-Identifier: GPL-2.0

.. _tw_process_statement_kernel:

.. include:: ../disclaimer-zh_TW.rst

:Original: :ref:`Documentation/process/kernel-enforcement-statement.rst <process_statement_kernel>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>
             Hu Haowen <src.res@email.cn>

Linux 內核執行聲明
------------------

作爲Linux內核的開發人員，我們對如何使用我們的軟體以及如何實施軟體許可證有著
濃厚的興趣。遵守GPL-2.0的互惠共享義務對我們軟體和社區的長期可持續性至關重要。

雖然有權強制執行對我們社區的貢獻中的單獨版權權益，但我們有共同的利益，即確保
個人強制執行行動的方式有利於我們的社區，不會對我們軟體生態系統的健康和增長
產生意外的負面影響。爲了阻止無益的執法行動，我們同意代表我們自己和我們版權
利益的任何繼承人對Linux內核用戶作出以下符合我們開發社區最大利益的承諾:

    儘管有GPL-2.0的終止條款，我們同意，採用以下GPL-3.0條款作爲我們許可證下的
    附加許可，作爲任何對許可證下權利的非防禦性主張，這符合我們開發社區的最佳
    利益。

        但是，如果您停止所有違反本許可證的行爲，則您從特定版權持有人處獲得的
        許可證將被恢復：（a）暫時恢復，除非版權持有人明確並最終終止您的許可證；
        以及（b）永久恢復, 如果版權持有人未能在你終止違反後60天內以合理方式
        通知您違反本許可證的行爲，則永久恢復您的許可證。

        此外，如果版權所有者以某種合理的方式通知您違反了本許可，這是您第一次
        從該版權所有者處收到違反本許可的通知（對於任何作品），並且您在收到通知
        後的30天內糾正違規行爲。則您從特定版權所有者處獲得的許可將永久恢復.

我們提供這些保證的目的是鼓勵更多地使用該軟體。我們希望公司和個人使用、修改和
分發此軟體。我們希望以公開和透明的方式與用戶合作，以消除我們對法規遵從性或強制
執行的任何不確定性，這些不確定性可能會限制我們軟體的採用。我們將法律行動視爲
最後手段，只有在其他社區努力未能解決這一問題時才採取行動。

最後，一旦一個不合規問題得到解決，我們希望用戶會感到歡迎，加入我們爲之努力的
這個項目。共同努力，我們會更強大。

除了下面提到的以外，我們只爲自己說話，而不是爲今天、過去或將來可能爲之工作的
任何公司說話。

  - Laura Abbott
  - Bjorn Andersson (Linaro)
  - Andrea Arcangeli
  - Neil Armstrong
  - Jens Axboe
  - Pablo Neira Ayuso
  - Khalid Aziz
  - Ralf Baechle
  - Felipe Balbi
  - Arnd Bergmann
  - Ard Biesheuvel
  - Tim Bird
  - Paolo Bonzini
  - Christian Borntraeger
  - Mark Brown (Linaro)
  - Paul Burton
  - Javier Martinez Canillas
  - Rob Clark
  - Kees Cook (Google)
  - Jonathan Corbet
  - Dennis Dalessandro
  - Vivien Didelot (Savoir-faire Linux)
  - Hans de Goede
  - Mel Gorman (SUSE)
  - Sven Eckelmann
  - Alex Elder (Linaro)
  - Fabio Estevam
  - Larry Finger
  - Bhumika Goyal
  - Andy Gross
  - Juergen Gross
  - Shawn Guo
  - Ulf Hansson
  - Stephen Hemminger (Microsoft)
  - Tejun Heo
  - Rob Herring
  - Masami Hiramatsu
  - Michal Hocko
  - Simon Horman
  - Johan Hovold (Hovold Consulting AB)
  - Christophe JAILLET
  - Olof Johansson
  - Lee Jones (Linaro)
  - Heiner Kallweit
  - Srinivas Kandagatla
  - Jan Kara
  - Shuah Khan (Samsung)
  - David Kershner
  - Jaegeuk Kim
  - Namhyung Kim
  - Colin Ian King
  - Jeff Kirsher
  - Greg Kroah-Hartman (Linux Foundation)
  - Christian König
  - Vinod Koul
  - Krzysztof Kozlowski
  - Viresh Kumar
  - Aneesh Kumar K.V
  - Julia Lawall
  - Doug Ledford
  - Chuck Lever (Oracle)
  - Daniel Lezcano
  - Shaohua Li
  - Xin Long
  - Tony Luck
  - Catalin Marinas (Arm Ltd)
  - Mike Marshall
  - Chris Mason
  - Paul E. McKenney
  - Arnaldo Carvalho de Melo
  - David S. Miller
  - Ingo Molnar
  - Kuninori Morimoto
  - Trond Myklebust
  - Martin K. Petersen (Oracle)
  - Borislav Petkov
  - Jiri Pirko
  - Josh Poimboeuf
  - Sebastian Reichel (Collabora)
  - Guenter Roeck
  - Joerg Roedel
  - Leon Romanovsky
  - Steven Rostedt (VMware)
  - Frank Rowand
  - Ivan Safonov
  - Anna Schumaker
  - Jes Sorensen
  - K.Y. Srinivasan
  - David Sterba (SUSE)
  - Heiko Stuebner
  - Jiri Kosina (SUSE)
  - Willy Tarreau
  - Dmitry Torokhov
  - Linus Torvalds
  - Thierry Reding
  - Rik van Riel
  - Luis R. Rodriguez
  - Geert Uytterhoeven (Glider bvba)
  - Eduardo Valentin (Amazon.com)
  - Daniel Vetter
  - Linus Walleij
  - Richard Weinberger
  - Dan Williams
  - Rafael J. Wysocki
  - Arvind Yadav
  - Masahiro Yamada
  - Wei Yongjun
  - Lv Zheng
  - Marc Zyngier (Arm Ltd)