RFC-0257:storage-host:將上層儲存空間驅動程式分割為元件 | |
---|---|
狀態 | 已接受 |
區域 |
|
說明 | 將上層儲存空間驅動程式 (GPT、FVM 等) 移至新的儲存空間主機元件。 |
問題 | |
Gerrit 變更 | |
作者 | |
審查人員 | |
提交日期 (年-月-日) | 2024-07-08 |
審查日期 (年-月-日) | 2024-08-13 |
摘要
目前,區塊裝置是以分層方式在 Driver Framework 中實作。實際與硬體互動的低階驅動程式 (例如 sdmmc、virtio) 會實作內部 fuchsia.hardware.block.driver
通訊協定,而較高層級的驅動程式 (例如 GPT、FVM、zxcrypt) 會與此通訊協定互動,並在這些驅動程式 (包括公開的 fuchsia.hardware.block
和 fuchsia.hardware.block.partition
通訊協定) 上提供較高層級的功能。我們建議將所有上層區塊驅動程式移至新的元件 (storage-host),只在 Driver Framework 中保留低階驅動程式。
提振精神
這項變更的主要目標,是將儲存空間堆疊與 Devfs 和驅動程式庫程式架構解耦合,以支援驅動程式架構團隊移除 Devfs 的努力 (以及更廣泛地將驅動程式庫堆疊遷移至驅動程式架構 V2)。
目前,儲存空間堆疊大量依賴 Devfs 來探索及存取區塊裝置的拓樸結構。如要移除這個依附元件,就必須大幅重構儲存體系結構,以便使用 Devfs 的替代機制 (在撰寫本文時,尚未設計此機制)。由於您需要建立新的 API,並且必須變更儲存體系結構才能使用這些 API,因此不妨順便重新考慮這些 API 實際實作的所在位置。
可以說,上層區塊裝置 (例如 GPT) 並非真正的裝置驅動程式,因為它們不會與硬體互動,而是與下層區塊裝置互動。換句話說,驅動程式庫架構針對不同用途進行最佳化調整,而非這些上層區塊裝置。儲存體堆疊一直是 Driver Framework 的異常用戶端 (例如在 Devfs 中大量使用拓樸路徑),且 Driver Framework 或儲存體團隊似乎都沒有維護這種不相符情形的任何好處。
除了加快驅動程式架構團隊淘汰 Devfs 的努力之外,將這些上層區塊裝置遷移至儲存空間主機,還有許多其他好處:
- 將技術堆疊簡化並整合至熟悉的語言 (Rust) 和架構 (一般非驅動程式庫元件),以提升儲存空間團隊的工程速度
- 啟用需要跨堆疊作業的效能最佳化功能 (例如可能與上層區塊驅動程式共定位的檔案系統,或 API 變更,例如 I/O 優先順序所需的變更)。
- 允許儲存空間團隊控管哪些元件可存取區塊裝置,這些元件應由儲存空間政策進行調解 (而非存取 /dev/class/block)。
- 我們可省下將這些驅動程式移植至 Driver Framework V2 的工作。
相關人員
協助人員:
- hjfreyer@google.com
審查者:
- garratt@google.comm
- csuter@google.com
- curtisgalloway@google.com
- surajmalhotra@google.com
諮詢:
- 我們諮詢了驅動程式架構團隊。
社會化:
這份 RFC 在發布前已與驅動程式架構團隊進行交流。
需求條件
這項變更必須對 Fuchsia 的其他部分公開;我們預期這項工作不會帶來任何功能變更。
這項變更不應導致效能、記憶體或儲存空間使用量出現任何重大倒退。
設計
儲存主機元件會管理實體區塊裝置的區隔和巢狀區塊裝置。這項功能將以 Rust 實作。
為方便說明,我們將以 GPT 格式的區塊裝置為例,說明啟動流程。儲存空間主機將能夠以類似方式處理其他分割區方案,例如 MBR 和 FVM。
Fshost 目前會從驅動程式架構中監聽區塊裝置、偵測其格式,並決定要繫結哪個區塊裝置驅動程式庫。舉例來說,當系統偵測到以 GPT 格式設定的裝置時,fshost 就會啟動 gpt
裝置驅動程式庫。fshost 的變更很簡單:fshost 不會啟動 gpt
裝置驅動程式庫,而是將裝置交給儲存空間主機。
storage-host 會從 GPT 解析分區表,並為每個分區匯出 fuchsia.hardware.block.partition.Partition
服務。這些服務會在由 storage-host 匯出的 partitions
目錄中提供。這個目錄可取代 Devfs 中的開發人員拓樸路徑,可讓您以階層方式探索及存取巢狀區隔。
Fshost 會監控發布至 partitions
的裝置,並執行一般比對作業,其中可能會啟動檔案系統。巢狀分區是有效的 (例如 GPT 中的 FVM),在這種情況下,fshost 只會要求儲存主機掛載並取消巢狀化指定的分區。
儲存體主機會實作與驅動程式相同的通訊協定,因此檔案系統和其他用戶端用於執行區塊 I/O 的通訊協定,不必在這方面進行變更。不過,我們可能會基於其他原因 (例如改善效能) 選擇變更這些通訊協定。
目前使用 Devfs 來探索及連線至區塊裝置的用戶端,必須轉移至使用 partitions
。許多用途已透過 fshost 或分區映像檔安裝工具進行調解,因此將大量用戶端移至透過 fshost 使用調解存取權的做法可能會比較合理,這樣我們就能更嚴密地控管區塊裝置的用途。舉例來說,我們可以在 fshost 中公開 API,以便存取特定區隔,而非對所有區塊裝置提供全面存取權。partitions
目錄只會用於樹狀結構內,且應有有限的用戶端,因此我們可以視需要靈活變更。
fshost 和儲存空間主機之間的來回關係 (fshost 將區塊裝置傳遞給儲存空間主機、儲存空間主機繫結至分區,並將巢狀區塊裝置傳回 fshost) 可能看起來不尋常,但有兩個好處。實際上,由於 fshost 幾乎不需要變更,因此可加快儲存空間主機的實作速度。它還會維持責任分離:fshost 會實作儲存空間政策 (要繫結哪些檔案系統、要掛接哪些區塊裝置等),而儲存空間主機則可透過代管巢狀區塊裝置,協助執行該政策。循環關係可在日後視情況重新設計。
請注意,系統不會變更早期啟動程序,也就是從 ZBI 載入啟動檔案系統。這個部分的啟動序列會在啟動 fshost 之前執行,因此不會受到這項提案的影響。
多個儲存空間主機執行個體
雖然目前並無此必要,但我們會避免在系統中假設有單一儲存空間主機執行個體。舉例來說,我們可能會為嵌入式儲存裝置和可插入式 USB 裝置建立獨立的儲存主機例項,以便在兩個儲存堆疊之間維持一定程度的隔離,進而提升安全性。或者,我們可能會想使用不同的格式 (例如 GPT 和 FVM) 執行個別的儲存空間主機例項,以強化隔離功能。
圖 1:目前架構。
圖 2:建議架構。
實作
我們會逐步將各種驅動程式遷移至新版,並依照每個主機板進行這項變更。
舉例來說,vim3 設定只需要遷移 GPT 驅動程式庫,因此我們可以先實作這項作業,然後在 GPT 驅動程式庫移植完成後,在 vim3 上啟用儲存空間主機。智慧型產品需要 FVM 和 zxcrypt,這些功能會在稍後實作。
我們需要確保用戶端可以從 devfs 或儲存空間主機暫時存取區塊裝置,這很簡單,因為我們打算使用類似的以目錄為導向介面進行探索。
我們會在 fuchsia.fshost.StorageHost
設定能力上限制儲存空間主機的用途,並在特定產品/電路板設定準備好切換時啟用。
一旦所有用途都已切換並視為穩定後,我們就可以移除轉換邏輯,完成遷移作業。
storage-host 會以單體 Rust 二進位檔實作。如有需要 (例如減少二進位檔膨脹),我們可以將功能 (例如 zxcrypt) 分離至程式庫,並視需要根據個別產品動態連結,但為了簡化,我們會從單體二進位檔開始。
請注意,由於儲存空間主機和同等的 Driver Framework 實作方式之間沒有功能差異,因此如果發生問題,這些變更可以安全地還原。
請注意,FVM 和 GPT 也提供各種主機工具。我們不打算將這些函式移植至 Rust,因為這些函式穩定且不受驅動程式影響,而且目前沒有改變這些函式的動機。
成效
我們認為,這項變更對不依賴 FVM 和 zxcrypt 的設定而言,不會對效能造成影響。雖然現在在檔案系統和區塊裝置驅動程式庫之間有一個新的元件,但這個元件可以透過一些簡單的 API 變更來移除 (例如,儲存空間主機可以將底層區塊裝置的視窗檢視畫面轉交給檔案系統,而檔案系統則可直接與底層區塊驅動程式庫通訊)。
針對 FVM 和 zxcrypt,儲存空間主機需要攔截每項要求,並在傳輸期間修改,這會導致延遲時間增加,相較於目前的 Driver Framework 實作。對於 FVM,這是將虛擬偏移量對應至實體偏移量的必要步驟;對於 zxcrypt,這是加密的必要步驟。
這會導致延遲時間增加,因為儲存空間主機需要從區塊 FIFO 中拉出要求,並在基礎 FIFO 中重新排入佇列。請注意,驅動程式架構實作仍需要攔截、修改及重新排序每項要求,但驅動程式庫與驅動程式庫之間的通訊會透過 Banjo 通訊協定 (fuchsia.hardware.block.driver.Block) 進行,該通訊協定會在兩個驅動程式同時位於同一位置時,使用更有效率的傳輸機制。換句話說,延遲時間是因為透過儲存空間主機的額外程序跳躍所造成。
我們認為可以透過幾種方式解決這個問題 (使用儲存空間主機可簡化或實現這類解決方案):
- 在 Rust 中導入並行處理功能更容易,因此我們可以透過管線或平行處理工作來提高吞吐量。
- Blobfs 會使用外部解壓縮器來提升安全性,這會為檔案讀取作業增加往返行程。這可以移至儲存空間主機,並與 I/O 要求一併執行,藉此取消儲存空間主機引進的額外中繼。(如果是這種情況,Blobfs 從安全性角度來看不會更糟,因為 Blobfs 不會假設區塊裝置本身可信任;從安全性角度來看,主要目標是避免在程序中進行解壓縮,這可能會危及 Blobfs 程序。其他檔案系統 (例如 Minfs) 無法像 Blobfs 一樣驗證資料,因此如果儲存空間主機遭到入侵,資料就可能遭到竄改;我們必須權衡這項最佳化功能的效能和安全性取捨。
未來,我們預計將更輕鬆地在儲存空間主機中進行變更,這有助於我們在日後進行效能最佳化。舉例來說,我們可能最終需要引入 I/O 優先順序,這需要在整個堆疊中進行變更。這樣一來,Storage 就能以我們更快速作業的語言和環境,使用整合的程式碼集來執行這項作業。
回溯相容性
由於我們只修改樹狀結構內程式碼和 API,因此這項變更不會造成回溯相容性問題。
安全性考量
由於 zxcrypt 是安全性敏感的服務,因此重新實作 zxcrypt 時必須進行安全性審查。
這項異動會從幾個方面強化安全性:
- 驅動程式將以 Rust 而非 C++ 實作,以減輕記憶體毀損漏洞。
- 我們將有機會透過 /dev/class/block 或 dev-topological 稽核並減少對區塊裝置的存取權,因為所有這些用途都需要遷移。
請注意,這項提案會對目前的安全性網域進行一些變更。我們可以將在同一個程序中代管的元件視為位於單一安全性網域中,如果其中一個元件遭到入侵,就表示另一個元件也遭到入侵。透過 FIDL 或其他 IPC 機制彼此通訊的元件,彼此之間的隔離程度較高 (這並不表示不會受到攻擊)。這項提案可提高隔離性 (將儲存裝置管理與其他共置的驅動程式分開),但我們認為,如果效能需要將部分軟體共置,那麼靈活決定適當的隔離界線就很有價值。請參閱「設計」部分的圖表。
隱私權注意事項
不適用。
測試
現有的 fshost 測試套件可做為驗證這些變更的穩固基礎,因為這些測試會執行偵測及繫結至區塊裝置的端對端流程。
我們應該把握這個機會,同時開發更強大的區塊堆疊測試,以便驗證兩個實作項目之間的行為是否相同。
說明文件
儲存空間的較低層級歷來缺乏文件說明,這是改善這個問題的好機會,您可以透過一些高層級架構文件說明來改善。對於終端開發人員而言,儲存空間通常是不明確的,但對於系統開發人員和其他與儲存空間整合的 Fuchsia 團隊來說,這項功能相當實用。
缺點、替代方案和未知事項
缺點
在這個變更中,我們無法將這些較高層級的驅動程式與最低層級的儲存空間驅動程式並置,因為最低層級的驅動程式會正確地保留在 Driver Framework 中。不過,我們認為這並非問題,因為我們只移動了儲存體系結構在 Driver Framework 中所處的邊界,而該邊界不太可能包含整個儲存體系結構 (包括檔案系統),因此在 Driver Framework 中和不在 Driver Framework 中的儲存體系結構部分之間,總是會有某些邊界。
這項異動會使 OOT 儲存空間驅動程式更難實作,但這並非我們打算支援的內容;我們預期所有儲存空間相關程式碼都會在可預見的未來保留樹狀結構內。
我們一開始會使用所有可用的格式,以靜態方式編譯儲存體主機,但在舊版的驅動程式架構中,驅動程式會以動態方式載入,且只會納入產品使用的驅動程式。如上所述,我們認為這不是問題,如果需要,我們可以稍後透過動態連結解決。
替代方案
顯而易見的替代做法是直接不進行這項變更,讓上層驅動程式留在 Driver Framework 中。不過,請注意,這並不代表沒有任何工作要做。我們仍需要:
- 將上層區塊驅動程式遷移至 DFv2。
- 與驅動程式架構團隊合作,設計新的介面,用於探索及連線至區塊裝置。
- 將所有用戶端移植至使用這個新介面,而非開發人員拓樸。
換句話說,兩種情況下的整合工作具有相同的廣度和範圍。這個提案需要額外的工作,是重新實作 Rust 中的驅動程式,而不是將驅動程式移植至 DFv2。這些驅動程式都不會太複雜,我們大約花了一個星期就製作出可運作的 GPT 原型,因此這項額外費用不會太高,而且還能帶來上述好處。
另一個做法是等待 Driver Framework 導入以 Rust 為基礎的驅動程式,然後將現有驅動程式移植至 Rust,並保留在 Driver Framework 中。不過,時程表並未配合這項作業。Devfs 的淘汰目標日期是 2024 年年底,且沒有任何承諾的時間表可支援 Rust 驅動程式的穩定版本,因此我們還是必須處理 Devfs 淘汰問題;同時,我們也能獲得上述儲存空間主機的其他優點。
既有技術與參考資料
不適用。