為什麼 Linux 模組 API 不向後兼容?
為什麼 Linux 模組 API 不向後兼容?更新 Linux 核心後找到更新的驅動程序讓我很沮喪。
我有一個需要專有驅動程序的無線適配器,但製造商在大約 7 年前就已停止使用該設備。由於程式碼非常古老並且是為 Linux 2.6.0.0 編寫的,因此它不能使用最新的 Linux 核心進行編譯。我使用過許多 Linux 發行版,但同樣的問題無處不在。雖然有一個隨 Linux 核心分發的開源驅動程序,但它不起作用。一些人試圖修改舊的專有程式碼以使其與最新的 Linux 核心兼容,但是當新的 Linux 核心發佈時,需要幾個月的時間才能使程式碼與之兼容。在此期間,發布了另一個新版本。由於這個原因,我無法升級到新的 Linux 核心;有時我什至無法升級我的發行版。
Greg Kroah-Hartman 在這裡寫過這個主題:https ://www.kernel.org/doc/html/v4.10/process/stable-api-nonsense.html
除了一些關於編譯 C 程式碼的技術細節外,他還提出了一些基本的軟體工程問題來做出決定。
Linux 核心始終是一項正在進行的工作。發生這種情況的原因有很多:
- 新的要求隨之而來。人們希望他們的軟體做得更多,這就是我們大多數人升級的原因,我們想要最新最好的功能。這些可能需要對現有軟體進行返工。
- 發現需要修復的錯誤,有時錯誤與設計本身有關,如果不進行大量返工就無法修復
- 軟體世界中出現了新的想法和習語,人們找到了更簡單/優雅/有效的做事方式。
大多數軟體都是如此,任何不維護的軟體都會緩慢而痛苦地死去。您要問的是為什麼舊的未維護程式碼仍然無法工作?
為什麼不維護舊介面?
為了確保向後兼容性,需要維護舊的(通常是“損壞的”和不安全的)介面。當然,理論上可以做到這一點,除非它確實帶來了巨大的成本。
Greg Kroah-Hartman 寫道
如果 Linux 必須確保它將保留一個穩定的源介面,就會創建一個新介面,並且隨著時間的推移必須維護舊的、損壞的介面,從而導致額外的工作
$$ developers $$. 由於所有的 Linux$$ developers $$在自己的時間做他們的工作,要求程序員無償地做額外的工作,免費的,是不可能的。
儘管 Linux 是開源的,但仍然只有有限的開發時間來維護它。所以人力還是可以用“成本”來討論的。開發人員必須選擇他們如何度過時間:
- 花大量時間維護舊的/損壞的/緩慢的/不安全的介面。這有時可能是在第一個實例中編寫介面所花費的時間的兩倍到三倍。
- 拋棄舊界面並期望其他軟體維護者*$$ do their job and $$*維護自己的軟體。
總的來說,分箱介面確實具有成本效益*(對於核心開發人員)*。如果您想知道為什麼開發人員不花費數月和數年的時間來為其他人支付 10 美元購買新的 wifi 適配器…這就是原因。請記住,這對核心開發人員來說是時間/成本效益,對您或製造商來說不一定是成本效益。
儘管我為 Linux 核心貢獻了一些(非常小的)更新檔,但我並不認為自己是核心開發人員。但是,這就是我所知道的:
為核心版本 2.6.0.0 編寫的驅動程序早於消除核心版本 2.6.39 中發生的大核心鎖 (BKL) 。
BKL 是在 Linux 還是單處理器(單核、單執行緒)作業系統時創建的。一旦添加了 SMP 支持,開發人員就意識到 BKL 在某個時候會成為一個很大的瓶頸,但只要係統中總共只有幾個核心/執行緒,這在某種程度上是可以容忍的。但對於在超級電腦中使用 Linux 的人來說,它首先成為一個真正的問題,因此這項工作開始用更細粒度的鎖定機製或盡可能用無鎖方法替換所有需要 BKL 的東西。
在現代電腦上,在普通台式機和大功率筆記型電腦上可能具有兩位數的核心數,更不用說伺服器了,2.6.0 向後兼容的核心模組 API 也需要實現 BKL。
如果遺留模組說“我想使用 BKL”,核心的其餘部分不知道該模組打算用它做什麼,因此向後兼容機制將不得不使用所有替換 BKL 的鎖只是為了涵蓋所有的可能性。那將是一個很大的性能打擊。並且新的無鎖方法還需要檢查遺留鎖——這首先破壞了無鎖的意義。因此,即使沒有實際載入遺留模組,向後兼容機制的存在也會降低系統性能。
最近,Spectre/Meltdown 安全更新檔對跨越核心/使用者空間邊界時需要發生的事情進行了重大更改。在 Spectre/Meltdown 修復實施之前編譯的任何模組對於後 Specre/Meltdown 核心都可能不可靠。
就在兩週前,我正在對一台舊伺服器進行故障排除,該伺服器在通過自動化應用安全更新時需要手動重啟。這種情況以前發生過多次,並且可以重現。我發現它
megasr
在 Spectre/Meltdown 更新檔之前有一個非常舊的專有儲存驅動程序版本,它不包含在自動更新中。將驅動程序更新到目前版本後,問題就消失了。順便說一句,這是在一個普通的 RHEL 6.10 系統上。我還看到伺服器在載入帶有後 Spectre/Meltdown 核心的專有 pre-Spectre/Meltdown 硬體監控驅動程序時崩潰。基於這一經驗,我完全相信 Spectre/Meltdown 修復需要被視為一個分水嶺事件:核心和模組需要全部為修復前版本,或全部為修復後版本;混合和匹配只會導致待命系統管理員的悲痛和午夜喚醒電話。
而且由於 Spectre 是CPU 設計級別的問題,它是“不斷給予的禮物”:有些人會找到新的方法來利用這些弱點,然後核心開發人員需要想辦法阻止這些漏洞利用。
這些只是兼容 2.6.0.0 的遺留核心模組 API 需要解決的兩個大問題。我敢肯定還有很多其他人。
然後還有更哲學的一面。想一想:是什麼讓 Linux 成為可能?
其中很大一部分是開放的硬體規範。如果硬體規範是開放的,任何人都可以參與。由於作業系統的原始碼是開放的,任何人都可以為每個人的利益做出貢獻。如果您的驅動程式碼是開源的,您就不能將硬體程式規範作為您的商業機密。
Linux 核心開發人員傾向於相信開源模型。這就是他們做出設計和開發選擇的原因,因此硬體製造商參與的首選方式是開源驅動程序,將其合併到主核心原始碼分發中,然後(並且只有這樣)您將讓整個核心開發者社區受益於維護它。
這為硬體設計人員和製造商提供了一些動力,使之成為可能。如果您想保密,請努力將其封裝到 ASIC 中,或者如果必須的話,也可以封裝到簽名韌體中。(如果是後者,請授予他人重新分發韌體包的權限。)
但由於核心是開源的,核心開發人員無法完全阻止其他人單獨維護專有驅動程序。但他們也沒有動力去關心他們。
事實上,專有二進制驅動程序在核心調試中帶來的額外麻煩是核心開發人員不關心專有驅動程序開發的誘因:“它們使我的工作更加困難,為什麼我應該做一些特別的事情來使他們的工作更容易?”
因此,核心開發人員通常會做對他們作為一個團體/社區最有利的事情。如果這包括一些模組 API 更改,那就這樣吧。第三方驅動程序甚至沒有進入等式。