162306a36Sopenharmony_ci.. SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci.. _tw_stable_api_nonsense:
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci.. include:: ../disclaimer-zh_TW.rst
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci:Original: :ref:`Documentation/process/stable-api-nonsense.rst
862306a36Sopenharmony_ci           <stable_api_nonsense>`
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci譯者::
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci        中文版維護者: 鍾宇  TripleX Chung <xxx.phy@gmail.com>
1362306a36Sopenharmony_ci        中文版翻譯者: 鍾宇  TripleX Chung <xxx.phy@gmail.com>
1462306a36Sopenharmony_ci        中文版校譯者: 李陽  Li Yang <leoyang.li@nxp.com>
1562306a36Sopenharmony_ci                      胡皓文 Hu Haowen <src.res.211@gmail.com>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ciLinux 內核驅動接口
1862306a36Sopenharmony_ci==================
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci寫作本文檔的目的,是爲了解釋爲什麼Linux既沒有二進位內核接口,也沒有穩定
2162306a36Sopenharmony_ci的內核接口。這裡所說的內核接口,是指內核里的接口,而不是內核和用戶空間
2262306a36Sopenharmony_ci的接口。內核到用戶空間的接口,是提供給應用程式使用的系統調用,系統調用
2362306a36Sopenharmony_ci在歷史上幾乎沒有過變化,將來也不會有變化。我有一些老應用程式是在0.9版本
2462306a36Sopenharmony_ci或者更早版本的內核上編譯的,在使用2.6版本內核的Linux發布上依然用得很好
2562306a36Sopenharmony_ci。用戶和應用程式作者可以將這個接口看成是穩定的。
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci執行綱要
2962306a36Sopenharmony_ci--------
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci你也許以爲自己想要穩定的內核接口,但是你不清楚你要的實際上不是它。你需
3262306a36Sopenharmony_ci要的其實是穩定的驅動程序,而你只有將驅動程序放到公版內核的原始碼樹里,
3362306a36Sopenharmony_ci才有可能達到這個目的。而且這樣做還有很多其它好處,正是因爲這些好處使得
3462306a36Sopenharmony_ciLinux能成爲強壯,穩定,成熟的作業系統,這也是你最開始選擇Linux的原因。
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci入門
3862306a36Sopenharmony_ci-----
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci只有那些寫驅動程序的「怪人」才會擔心內核接口的改變,對廣大用戶來說,既
4162306a36Sopenharmony_ci看不到內核接口,也不需要去關心它。
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci首先,我不打算討論關於任何非GPL許可的內核驅動的法律問題,這些非GPL許可
4462306a36Sopenharmony_ci的驅動程序包括不公開原始碼,隱藏原始碼,二進位或者是用原始碼包裝,或者
4562306a36Sopenharmony_ci是其它任何形式的不能以GPL許可公開原始碼的驅動程序。如果有法律問題,請咨
4662306a36Sopenharmony_ci詢律師,我只是一個程式設計師,所以我只打算探討技術問題(不是小看法律問題,
4762306a36Sopenharmony_ci法律問題很實際,並且需要一直關注)。
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci既然只談技術問題,我們就有了下面兩個主題:二進位內核接口和穩定的內核源
5062306a36Sopenharmony_ci代碼接口。這兩個問題是互相關聯的,讓我們先解決掉二進位接口的問題。
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci二進位內核接口
5462306a36Sopenharmony_ci--------------
5562306a36Sopenharmony_ci假如我們有一個穩定的內核原始碼接口,那麼自然而然的,我們就擁有了穩定的
5662306a36Sopenharmony_ci二進位接口,是這樣的嗎?錯。讓我們看看關於Linux內核的幾點事實:
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci    - 取決於所用的C編譯器的版本,不同的內核數據結構里的結構體的對齊方
5962306a36Sopenharmony_ci      式會有差別,代碼中不同函數的表現形式也不一樣(函數是不是被inline
6062306a36Sopenharmony_ci      編譯取決於編譯器行爲)。不同的函數的表現形式並不重要,但是數據
6162306a36Sopenharmony_ci      結構內部的對齊方式很關鍵。
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci    - 取決於內核的配置選項,不同的選項會讓內核的很多東西發生改變:
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci      - 同一個結構體可能包含不同的成員變量
6662306a36Sopenharmony_ci      - 有的函數可能根本不會被實現(比如編譯的時候沒有選擇SMP支持
6762306a36Sopenharmony_ci        一些鎖函數就會被定義成空函數)。
6862306a36Sopenharmony_ci      - 內核使用的內存會以不同的方式對齊,這取決於不同的內核配置選
6962306a36Sopenharmony_ci        項。
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci    - Linux可以在很多的不同體系結構的處理器上運行。在某個體系結構上編
7262306a36Sopenharmony_ci      譯好的二進位驅動程序,不可能在另外一個體系結構上正確的運行。
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci對於一個特定的內核,滿足這些條件並不難,使用同一個C編譯器和同樣的內核配
7562306a36Sopenharmony_ci置選項來編譯驅動程序模塊就可以了。這對於給一個特定Linux發布的特定版本提
7662306a36Sopenharmony_ci供驅動程序,是完全可以滿足需求的。但是如果你要給不同發布的不同版本都發
7762306a36Sopenharmony_ci布一個驅動程序,就需要在每個發布上用不同的內核設置參數都編譯一次內核,
7862306a36Sopenharmony_ci這簡直跟噩夢一樣。而且還要注意到,每個Linux發布還提供不同的Linux內核,
7962306a36Sopenharmony_ci這些內核都針對不同的硬體類型進行了優化(有很多種不同的處理器,還有不同
8062306a36Sopenharmony_ci的內核設置選項)。所以每發布一次驅動程序,都需要提供很多不同版本的內核
8162306a36Sopenharmony_ci模塊。
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci相信我,如果你真的要採取這種發布方式,一定會慢慢瘋掉,我很久以前就有過
8462306a36Sopenharmony_ci深刻的教訓...
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci穩定的內核原始碼接口
8862306a36Sopenharmony_ci--------------------
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci如果有人不將他的內核驅動程序,放入公版內核的原始碼樹,而又想讓驅動程序
9162306a36Sopenharmony_ci一直保持在最新的內核中可用,那麼這個話題將會變得沒完沒了。
9262306a36Sopenharmony_ci內核開發是持續而且快節奏的,從來都不會慢下來。內核開發人員在當前接口中
9362306a36Sopenharmony_ci找到bug,或者找到更好的實現方式。一旦發現這些,他們就很快會去修改當前的
9462306a36Sopenharmony_ci接口。修改接口意味著,函數名可能會改變,結構體可能被擴充或者刪減,函數
9562306a36Sopenharmony_ci的參數也可能發生改變。一旦接口被修改,內核中使用這些接口的地方需要同時
9662306a36Sopenharmony_ci修正,這樣才能保證所有的東西繼續工作。
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci舉一個例子,內核的USB驅動程序接口在USB子系統的整個生命周期中,至少經歷
9962306a36Sopenharmony_ci了三次重寫。這些重寫解決以下問題:
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci    - 把數據流從同步模式改成非同步模式,這個改動減少了一些驅動程序的
10262306a36Sopenharmony_ci      複雜度,提高了所有USB驅動程序的吞吐率,這樣幾乎所有的USB設備都
10362306a36Sopenharmony_ci      能以最大速率工作了。
10462306a36Sopenharmony_ci    - 修改了USB核心代碼中爲USB驅動分配數據包內存的方式,所有的驅動都
10562306a36Sopenharmony_ci      需要提供更多的參數給USB核心,以修正了很多已經被記錄在案的死鎖。
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci這和一些封閉原始碼的作業系統形成鮮明的對比,在那些作業系統上,不得不額
10862306a36Sopenharmony_ci外的維護舊的USB接口。這導致了一個可能性,新的開發者依然會不小心使用舊的
10962306a36Sopenharmony_ci接口,以不恰當的方式編寫代碼,進而影響到作業系統的穩定性。
11062306a36Sopenharmony_ci在上面的例子中,所有的開發者都同意這些重要的改動,在這樣的情況下修改代
11162306a36Sopenharmony_ci價很低。如果Linux保持一個穩定的內核原始碼接口,那麼就得創建一個新的接口
11262306a36Sopenharmony_ci;舊的,有問題的接口必須一直維護,給Linux USB開發者帶來額外的工作。既然
11362306a36Sopenharmony_ci所有的Linux USB驅動的作者都是利用自己的時間工作,那麼要求他們去做毫無意
11462306a36Sopenharmony_ci義的免費額外工作,是不可能的。
11562306a36Sopenharmony_ci安全問題對Linux來說十分重要。一個安全問題被發現,就會在短時間內得到修
11662306a36Sopenharmony_ci正。在很多情況下,這將導致Linux內核中的一些接口被重寫,以從根本上避免安
11762306a36Sopenharmony_ci全問題。一旦接口被重寫,所有使用這些接口的驅動程序,必須同時得到修正,
11862306a36Sopenharmony_ci以確定安全問題已經得到修復並且不可能在未來還有同樣的安全問題。如果內核
11962306a36Sopenharmony_ci內部接口不允許改變,那麼就不可能修復這樣的安全問題,也不可能確認這樣的
12062306a36Sopenharmony_ci安全問題以後不會發生。
12162306a36Sopenharmony_ci開發者一直在清理內核接口。如果一個接口沒有人在使用了,它就會被刪除。這
12262306a36Sopenharmony_ci樣可以確保內核儘可能的小,而且所有潛在的接口都會得到儘可能完整的測試
12362306a36Sopenharmony_ci(沒有人使用的接口是不可能得到良好的測試的)。
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci要做什麼
12762306a36Sopenharmony_ci--------
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci如果你寫了一個Linux內核驅動,但是它還不在Linux原始碼樹里,作爲一個開發
13062306a36Sopenharmony_ci者,你應該怎麼做?爲每個發布的每個版本提供一個二進位驅動,那簡直是一個
13162306a36Sopenharmony_ci噩夢,要跟上永遠處於變化之中的內核接口,也是一件辛苦活。
13262306a36Sopenharmony_ci很簡單,讓你的驅動進入內核原始碼樹(要記得我們在談論的是以GPL許可發行
13362306a36Sopenharmony_ci的驅動,如果你的代碼不符合GPL,那麼祝你好運,你只能自己解決這個問題了,
13462306a36Sopenharmony_ci你這個吸血鬼<把Andrew和Linus對吸血鬼的定義連結到這裡>)。當你的代碼加入
13562306a36Sopenharmony_ci公版內核原始碼樹之後,如果一個內核接口改變,你的驅動會直接被修改接口的
13662306a36Sopenharmony_ci那個人修改。保證你的驅動永遠都可以編譯通過,並且一直工作,你幾乎不需要
13762306a36Sopenharmony_ci做什麼事情。
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci把驅動放到內核原始碼樹里會有很多的好處:
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci    - 驅動的質量會提升,而維護成本(對原始作者來說)會下降。
14262306a36Sopenharmony_ci    - 其他人會給驅動添加新特性。
14362306a36Sopenharmony_ci    - 其他人會找到驅動中的bug並修復。
14462306a36Sopenharmony_ci    - 其他人會在驅動中找到性能優化的機會。
14562306a36Sopenharmony_ci    - 當外部的接口的改變需要修改驅動程序的時候,其他人會修改驅動程序
14662306a36Sopenharmony_ci    - 不需要聯繫任何發行商,這個驅動會自動的隨著所有的Linux發布一起發
14762306a36Sopenharmony_ci      布。
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci和別的作業系統相比,Linux爲更多不同的設備提供現成的驅動,而且能在更多不
15062306a36Sopenharmony_ci同體系結構的處理器上支持這些設備。這個經過考驗的開發模式,必然是錯不了
15162306a36Sopenharmony_ci的 :)
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci感謝
15462306a36Sopenharmony_ci----
15562306a36Sopenharmony_ci感謝 Randy Dunlap, Andrew Morton, David Brownell, Hanna Linder,
15662306a36Sopenharmony_ciRobert Love, and Nishanth Aravamudan 對於本文檔早期版本的評審和建議。
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci英文版維護者: Greg Kroah-Hartman <greg@kroah.com>
15962306a36Sopenharmony_ci
160