RFC-0257:storage-host:將上層儲存驅動程式的元件化

RFC-0257:storage-host:將上層儲存空間驅動程式元件化
狀態已接受
區域
  • 儲存空間
說明

將上層儲存空間驅動程式 (GPT、FVM 等) 移至新的儲存空間主機元件。

問題
Gerrit 變更
作者
審查人員
提交日期 (年-月-日)2024-07-08
審查日期 (年-月-日)2024-08-13

摘要

目前,區塊裝置是以分層方式在驅動程式架構中實作。實際與硬體互動的低層級驅動程式 (例如 sdmmc、virtio) 會實作內部 fuchsia.hardware.block.driver 通訊協定,而高層級驅動程式 (例如 GPT、FVM、zxcrypt) 會與這個通訊協定互動,並在這些驅動程式 (包括公開的 fuchsia.hardware.blockfuchsia.hardware.block.partition 通訊協定) 上提供更高層級的功能。我們建議將所有上層區塊驅動程式移至新元件「storage-host」,只在驅動程式架構中保留低階驅動程式。

提振精神

這項異動的主要目標,是將儲存空間堆疊與 Devfs 和驅動程式庫程式架構分離,支援驅動程式架構團隊移除 Devfs 的工作 (更廣泛地說,是將驅動程式庫堆疊遷移至 Driver Framework V2)。

目前儲存空間堆疊廣泛依賴 Devfs,以探索及拓撲存取區塊裝置。如要移除這項依附元件,需要大量重構儲存空間堆疊,才能使用 Devfs 的替代機制 (撰寫本文時,這項機制尚未設計完成)。由於需要建立新的 API,且儲存空間堆疊也必須變更才能使用這些 API,因此現在是重新考量這些 API 實際實作位置的絕佳時機。

可以說,GPT 等上層區塊裝置並非真正意義上的裝置驅動程式,因為這類裝置不會與硬體互動,而是與下層區塊裝置互動。換句話說,驅動程式庫架構是針對不同用途進行最佳化,而非這些上層區塊裝置。儲存空間堆疊一直是驅動程式架構的異常用戶端 (例如我們在 Devfs 中大量使用拓撲路徑),而且無論是驅動程式架構或儲存空間團隊,似乎都無法從維護這種不相容性中獲益。

除了加速驅動程式架構團隊淘汰 Devfs 的工作,將這些上層區塊裝置遷移至 storage-host 還有許多其他優點:

  • 簡化及整合技術堆疊,改用熟悉的語言 (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

已諮詢:

  • 我們已諮詢 Driver Framework 團隊。

社交:

這項 RFC 已在發布前與 Driver Framework 團隊討論。

需求條件

這項變更必須對其餘 Fuchsia 保持透明,我們預期這項工作不會帶來任何功能變更。

這項變更「不應」導致效能、記憶體或儲存空間用量大幅回歸。

設計

儲存空間主機元件會管理實體區塊裝置的分割區和巢狀區塊裝置。並以 Rust 實作。

為說明起見,我們將介紹具有 GPT 格式化區塊裝置的系統啟動流程。儲存空間主機將能以類似方式處理其他分割區配置,例如 MBR 和 FVM。

Fshost 目前會監聽 Driver Framework 的區塊裝置、偵測格式,並判斷要繫結哪個區塊裝置驅動程式庫。舉例來說,系統偵測到 GPT 格式的裝置時,fshost 會啟動 gpt 裝置驅動程式。fshost 的變更很簡單:fshost 會將裝置交給 storage-host,而不是啟動 gpt 裝置驅動程式庫。

storage-host 會從 GPT 中剖析分區表,並為每個分區匯出 fuchsia.hardware.block.partition.Partition 服務。這些服務會儲存在由儲存空間主機匯出的 partitions 目錄中。這個目錄可取代 Devfs 中的開發拓撲路徑,方便您以階層式方式探索及存取巢狀分割區。

Fshost 會監控發布到 partitions 的裝置,並執行一般比對作業,可能包括啟動檔案系統。巢狀分區有效 (例如 GPT 中的 FVM),在這種情況下,fshost 只會要求 storage-host 掛接並取消巢狀結構指定的分區。

檔案系統和其他用戶端用來執行區塊 I/O 的通訊協定不需要變更,因為儲存空間主機會實作與驅動程式相同的通訊協定。不過,我們可能會基於其他原因 (例如提升效能) 變更這些通訊協定。

目前使用 Devfs 探索及連線至區塊裝置的用戶端,需要移植至使用 partitions。許多用途已由 fshost 或分區映像檔安裝工具仲介,因此將長尾客戶移至透過 fshost 仲介存取,可能較為合理,這樣我們就能更嚴格控管區塊裝置的使用情形。舉例來說,我們可以在 fshost 中公開 API,存取特定分割區,而不是全面存取所有區塊裝置。partitions 目錄只會樹狀結構內使用,且用戶端數量有限,因此我們可視需要變更。

fshost 和 storage-host 之間的來回關係 (fshost 將區塊裝置傳遞至 storage-host,storage-host 繫結至分割區,並將巢狀區塊裝置傳遞回 fshost) 可能看似不尋常,但有兩項優點。從實務角度來看,由於 fshost 幾乎不需要變更,因此可加快儲存空間主機的實作速度。此外,這項功能也維持責任劃分:fshost 會實作儲存空間政策 (要繫結的檔案系統、要掛接的區塊裝置等),而 storage-host 則會代管巢狀區塊裝置,協助執行該政策。如果之後有意義,可以重新架構循環關係。

請注意,早期啟動 (即從 ZBI 載入啟動檔案系統) 不會有任何變更。啟動序列的這部分會在啟動 fshost 之前執行,因此不會受到這項提案影響。

多個儲存主機執行個體

雖然目前不需要,但我們會避免在系統中假設有單一儲存空間主機執行個體。舉例來說,我們可能需要為內嵌儲存裝置和可插拔的 USB 裝置分別建立儲存空間主機執行個體,以維持兩個儲存空間堆疊之間的某種程度隔離,進而提升安全性。或者,我們可能想讓不同的儲存主機執行個體執行不同格式 (例如 GPT 和 FVM),以提升隔離效果。

目前架構

圖 1:目前架構。

建議架構

圖 2:建議架構。

實作

隨著我們遷移各種驅動程式,這項變更可以逐步完成,並以每個開發板為單位進行。

舉例來說,vim3 設定只需要遷移 GPT 驅動程式庫,因此我們可以先實作該設定,並在 GPT 驅動程式庫移植完成後,在 vim3 上啟用儲存空間主機。智慧產品需要 FVM 和 zxcrypt,這些將在稍後實作。

我們需要確保用戶端可以暫時從 devfs 或 storage-host 存取區塊裝置,這很簡單,因為我們打算使用類似目錄導向的介面進行探索。

我們會透過 fuchsia.fshost.StorageHost 設定能力限制儲存空間主機的使用,並在特定產品/主機板設定準備好切換時啟用。

所有用法都切換完畢且穩定後,我們就能移除過渡邏輯,完成遷移作業。

storage-host 會實作為單體式 Rust 二進位檔。如有必要 (例如為了減少二進位檔膨脹),我們可以將功能 (例如 zxcrypt) 分成程式庫,並視需要以產品為單位動態連結,但為了簡化作業,我們會先從單一二進位檔開始。

請注意,由於儲存空間主機和對應的 Driver Framework 實作項目之間沒有功能差異,因此如果發生問題,可以安全地還原這些變更。

請注意,FVM 和 GPT 也會附上各種主機工具。我們不打算將這些項目移植到 Rust,因為這些項目穩定、獨立於驅動程式,且目前沒有變更的動機。

效能

我們相信,對於不依賴 FVM 和 zxcrypt 的設定,這項變更對效能不會造成影響。雖然檔案系統和區塊裝置驅動程式庫之間現在有新的元件,但只要進行一些簡單的 API 變更,這個元件就能讓路 (例如,storage-host 可以將基礎區塊裝置的視窗化檢視畫面中介給檔案系統,而檔案系統隨後可以直接與基礎區塊驅動程式庫通訊)。

如果是 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 優先順序,這會需要變更整個堆疊。如果儲存空間的程式碼庫整合到我們能快速作業的語言和環境中,這項作業就會變得更加輕鬆。

回溯相容性

由於我們只修改樹狀結構內的程式碼和 API,因此這項異動不會造成回溯相容性問題。

安全性考量

由於 zxcrypt 是安全相關服務,因此重新實作時需要進行安全審查。

這項異動也會透過以下幾種方式提升安全性:

  • 驅動程式將以 Rust 而非 C++ 實作,可減輕記憶體毀損漏洞。
  • 我們將有機會稽核並減少透過 /dev/class/block 或 dev-topological 封鎖裝置的存取權,因為所有這些用法都需要遷移。

請注意,這項提案會對現有的安全網域進行一些變更。我們可以將託管在相同程序中的元件視為位於單一安全網域中;如果其中一個元件遭到入侵,另一個也會受到影響。透過 FIDL 或其他 IPC 機制相互通訊的元件,彼此間的隔離程度較高 (但這並不代表不會受到攻擊)。這項提案會提高隔離程度 (將儲存裝置管理與其他共置驅動程式分開),但我們認為,如果為了提升效能而必須共置軟體片段,則決定適當的隔離界線時,仍應保持彈性。請參閱「設計」部分的圖表。

隱私權注意事項

不適用。

測試

現有的 fshost 測試套件可做為堅實的基礎,協助我們驗證這些變更,因為這些測試會執行偵測及繫結至封鎖裝置的端對端流程。

我們應把握這個機會,開發更穩健的區塊堆疊測試,用來驗證兩種實作方式的行為是否相同。

說明文件

儲存空間的底層文件向來較少,因此這是個好機會,可以提供一些高層級的架構文件。儲存空間通常對終端開發人員來說是不透明的,但對於系統開發人員和其他與儲存空間整合的 Fuchsia 團隊來說,儲存空間是他們感興趣的項目。

缺點、替代方案和未知事項

缺點

在這項變更中,我們無法將這些上層驅動程式與最低層級的儲存空間驅動程式共置,因為最低層級的驅動程式會留在驅動程式架構中。不過,我們認為這不是問題,因為我們只移動了儲存空間堆疊在驅動程式架構中的邊界,而這個邊界不太可能包含整個儲存空間堆疊 (包括檔案系統),因此在儲存空間堆疊中,位於 DF 的部分和不在 DF 的部分之間,永遠都會有邊界。

這項變更會增加實作 OOT 儲存空間驅動程式的難度,但我們本來就不打算支援這類驅動程式;我們預期在可預見的未來,所有儲存空間相關程式碼都會保留樹狀結構內。

我們一開始會使用所有可用格式靜態編譯儲存空間主機,而舊版驅動程式架構會動態載入驅動程式,且只會納入產品使用的驅動程式。如上所述,我們認為這不是問題,如果需要,稍後可以使用動態連結解決。

替代方案

顯而易見的替代方案是不要進行這項變更,讓上層驅動程式留在驅動程式架構中。但請注意,這並不代表沒有工作要做。我們仍需:

  • 將上層區塊驅動程式遷移至 DFv2。
  • 與驅動程式架構團隊合作,設計新的介面,方便使用者探索及連線至區塊裝置。
  • 將所有用戶端改為使用這個新介面,而非 dev-topological。

換句話說,這兩種情況下的整合工作具有相同的廣度和範圍。這項提案需要額外的工作,就是以 Rust 重新實作驅動程式,而不是將驅動程式移植到 DFv2。這些驅動程式都不特別複雜,我們大約在一週內就建立出可用的 GPT 原型,因此額外成本不高,而且還能享有上述優點。

另一種做法是等待 Driver Framework 導入以 Rust 為基礎的驅動程式,然後將現有驅動程式移植到 Rust,並保留在 Driver Framework 中。不過,這與時程不符。Devfs 預計於 2024 年底淘汰,且 Rust 驅動程式的穩定版支援時間表尚未確定,因此我們無論如何都必須處理 Devfs 淘汰問題;不妨同時享有上述 storage-host 的其他優點。

既有技術和參考資料

不適用。