RFC-0225:Fxblob:將 blob 儲存在 Fxfs

RFC-0225:Fxblob:將 blob 儲存成 Fxfs
狀態已接受
區域
  • 儲存空間
說明

提供 Fxfs 的 blob,移除系統中的 Blobfs 和 FVM。

問題
變更
作者
審查人員
提交日期 (年/月)2023-07-25
審查日期 (年/月)2023 年 9 月 5 日

摘要

以 Fuchsia 的新一代檔案系統 Fxfs 取代 Fuchsia 的磁碟區管理員 (FVM) 和 blob 儲存檔案系統 (Blobfs)。系統 blob (包括程式庫、二進位檔和靜態設定) 會儲存在 Fxfs 磁碟區中,並具有與 Blobfs 相同的屬性 (可視內容、已驗證和不可變動)。

提振精神

Fxfs 是 Fuchsia 的新一代檔案系統,專為效能、更新性和豐富功能集而設計。事實證明,這是 Storage 團隊可以順暢運作的穩固基礎,日益增加的工程工作量,更是以強化 Fxfs 為中心。Blobfs 和 FVM 是在 Fuchsia 初期建立,專為特定用途建構而成:

  • Blobfs 的設計宗旨是提供已驗證、不可變更且可定址的儲存空間。
  • FVM 的設計宗旨是讓 Blobfs 和 Minfs (一般可變動的檔案系統) 共用單一區塊裝置,並在分區增加時從裝置動態分配。

隨著 Fuchsia 的發展,這些系統扮演了重要角色,但已成為儲存團隊目標 (效能、可更新性和可維護性) 的限制因素。

提升效能

改善 Fuchsia 儲存空間堆疊效能的簡單果實已足夠,現在的改善必須要仰賴更複雜的檔案系統變更。

舉例來說,Blobfs 的寫入效能受限於單一執行緒實作,為檔案系統新增多執行緒支援並不困難,而且需要大幅變更。

Blobfs 的格式與我們合作,致力於改善效能,因為高寫入量過大。數個儲存在不同位置中的中繼資料結構必須更新才能編寫檔案,進而大幅提高寫入量。此外,Blobfs 日誌採用區塊式 (相較於 Fxfs 等邏輯日誌),在多數情況下的效率較低。

每個維護的檔案系統都必須重複執行這些工作,因此會大幅增加擁有不同檔案系統的成本。能夠將心力集中在單一檔案系統 (Fxfs),這是本提案的主要動機。

Fxfs 的效能優勢已歸功於 Fxblob 原型。在 Intel NUC 上,Fxblob 是:

  • 對 blob 中的分頁處理速度較快 55-80%
  • 編寫單一 blob 的速度快 17%
  • 並行寫入多個 blob 的速度比 Blobfs 高出 130%。

我們還會持續改善成效。

可更新性

Fxfs 的其中一項主要設計原則是可更新,我們設計了 Fxfs 來配合日後的儲存格式變更。詳情請參閱 RFC-0136:Fxfs

設計 FVM 和 Blobfs 時,並不是考量這點,而目前若要對 FVM 或 Blobfs 進行任何重大變更,則無法進行格式和實作。

如果需要新增功能,或是需要對磁碟資料儲存方式進行效能最佳化,將非常難以使用 FVM 和 Blobf。此舉已有幾個範例:

  • RFC-0005:Blobfs Snapshots,提議對 FVM 的格式變更,改善 Fuchsia 提升軟體更新的彈性。這個 RFC 因為系統認為變更 FVM 格式的風險過高,且在技術上非常複雜,所以才撤銷。
  • Blobfs 中的精簡的 Merkle 樹;這是 2021 年實作的節省空間功能,由於推出功能的複雜性,並未全面推出。C++ Blobfs 仍支援精簡和舊版版面配置。

相較之下,Fxfs 的磁碟機格式會定期以最精簡的方式變更。在撰寫這份 RFC (2023 年 7 月) 時,Fxfs 使用的是 31 版,自上次破壞性變更 (2022-06-14 版建立為第 21 版) 之後,已進行 10 種格式變更。(應注意的是,即使這項破壞性變更能以回溯相容性的方式完成,但基於務實的理由,我們決定不這麼做)。

可維護性

Fxfs 經證實是經過完整測試且俱生產力的環境,適合工程師處理。此程式庫可在 Rust 中實作,且具有廣泛的單元、整合和模糊測試的涵蓋範圍,並且封裝了更細微或困難的問題 (例如圖層合併、日誌記錄、交易和鎖定等)。此外,Fxfs 的層檔案建立後不可變更,且中繼資料更新加到記憶體內層檔案 (和日誌),而不是將中繼資料寫入磁碟,因此要處理並行問題也變得簡單許多。

相較之下,FVM 有大量的技術債、缺乏健全的測試涵蓋範圍,且這種格式較不封裝 (Fchsia 中有大量軟體解讀 FVM 格式),而這使得系統難以變更。

如「效能改善」一文所述,我們維護的每個檔案系統實作項目都必須複製大部分改善項目,而這會產生改善成本。這也適用於維護費用。要維護的軟體減少,開發人員則可減少耗費的工程心力。

請注意,由於現有產品目前仰賴 FVM 和 Blobfs,因此我們無法完全淘汰 FVM 和 Blobfs。不過,我們預期 FVM 和 Blobfs 能夠在現有產品上維持一定的穩定性,而這對於維護成本來說是可以忽略的。

相關人員

講師:

abarth@google.com

審查者:

顧問:

社群媒體化:

此設計先與相關利害關係人進行社交互動 (我們很早就推出軟體推送服務,等到最初的原型設計更全面地發展出安全性/核心技術之後),

相關規定

  • Fxblob「必須」提供與 Blobfs 語意完全相符的檔案系統 API。也就是:
    • Fxblob 必須允許建立靜態檔案 (寫入一次、讀取多次)。
    • Fxblob「必須」含有可做為內容定址的檔案名稱 (亦即檔案名稱必須是其內容的 Merkle 根)。
    • 為確保可攜權順利進行遷移,應使用 Blobfs Blob 的相同 Merkle 樹狀演算法 (也就是說,Blobfs 中的檔案名稱應與 Fxblob 中的檔案名稱相符)。
    • Fxblob「必須」確保檔案內容與 Merkle 根雜湊相符,才能允許用戶端讀取這些檔案。
    • Fxblob「必須」向包含系統每個 blob 的 pkg-cache 呈現平面目錄結構。
    • Fxblob 必須支援執行檔和分頁。
  • Fxblob「必須」支援 RFC-0207 中指定的「交付 blob」線格式。
  • Fxblob「應」在所有維度中達到與 Blobf 相等或更佳的效能。
    • 在延遲和處理量方面,Fxblob「應該」比 Blobfs 更佳的讀取和寫入效能。
    • Fxblob「應」擁有與 Blobfs 相近的磁碟用量和記憶體用量。
  • Fxblob 必須具有精確的會計機制,以便根據系統已知的其他 blob 在可用空間上預先決定儲存空間預算,並合理縮小範圍。
  • Fxblob 應盡量減少擴充可信程式碼集 (TCB),亦即所有程式碼的組合,都必須符合 Fuchsia 驗證執行作業的安全性屬性。Fxfs「不應」要求受信任的作業,並將受信任的作業委派給其他位置。

設計

從架構的角度來看,目標是從圖 1 移至圖 2:

舊架構

圖 1: Fuchsia 裝置目前的儲存空間架構。

新建架構

圖 2: Fuchsia 裝置的 Fxblob 儲存架構。

Fxfs 中的「blob」磁碟區是模擬 blobf 屬性的特殊磁碟區 (內容可視性、不變性等)。對系統較高層來說,這項變更是透明的,儘管在系統的許多較低層級部分需要變更,但變更是透明的:

  • 系統組合和建構工具
  • 裝置啟動軟體和工具 (填充和閃爍)、
  • 復原軟體
  • Fshost
  • Fxfs,以支援新 blob 分區的特殊屬性
  • Pkg-cache 和 pkg-解析器,以使用一組新的 API 來讀取及寫入 blob。

Fxfs 變更

Fxfs 已經經過精心安排,可因應這個架構、擁有對磁碟區原生支援,並且採用專為彈性設計且可以隨時間變更的格式。

已完成原型實作 (請參閱 //src/storage/fxfs/platform/src/fuchsia/fxblob),這個程式庫實作符合 blob 儲存空間屬性的特殊磁碟區。磁碟區有一個根目錄,其中沒有任何檔案或目錄無法使用 fuchsia.io 通訊協定建立。該磁碟區提供特殊的 BlobWriter 通訊協定,pkg-cache 將用來將新的 blob 安裝到磁碟區。

這個磁碟區中的檔案可以使用 blobf 使用的 Merkle 樹狀演算法 (檔案名稱為根雜湊) 來定址。安裝 blob 和 Fxfs 時會產生 Merkle 樹狀結構,以確保在保留檔案之前,Merkle 根層級符合檔案名稱。每當從磁碟讀取檔案區段時,Fxfs 都會根據檔案的根樹驗證內容,從而提供完整性。

Fshost 的變更

Fshost 是一種低階元件,可偵測區塊裝置並掛接其內含的檔案系統,藉此將 /blob 和 /data 連線至系統的其他部分。

透過靜態設定將 Fshost 設為預期 Fxblob 格式的系統時,會將 /blob 目錄連結至 Fxfs 執行個體中的 blob 磁碟區,以及 /資料目錄和 Fxfs 執行個體中的資料磁碟區。Fshost 也將繼續支援 FVM+Blobfs 的舊版設定。

系統組裝和建構工具的變更

系統組合是 Fuchsia 建構的最後一個步驟,其中構件會組合為一組映像檔和資訊清單,而該映像檔和資訊清單是由 Fuchsia 系統映像檔組成。

系統組合的其中一個輸出是 FVM+Blobfs 映像檔,其中包含系統中一組 blob。我們將調整系統組合,根據建構時間設定,發出包含這些 blob 的 Fxfs 格式圖片。

我們也會以「稀疏」格式發出 Fxfs 圖片,這樣在傳輸至裝置時更有效率。使用的 Sparse 格式為 Android Sparse 格式,由於 Fastboot 支援這個格式,因此相當自然。

裝置啟動程序變更 (儲存及刷新)

雖然裝置 Bootstrap (RFC-0075:淘汰 Zedboot 式的鋪面) 已正式淘汰貼上功能,但其用途仍廣泛使用,因此我們選擇將 Fxfs 圖片支援功能新增至設定工作流程。

刷新是新型裝置啟動工作流程,這種工作流程採用 Fastboot 通訊協定。與貼上 (會解讀接收的 FVM 映像檔) 相比,這個通訊協定相對簡單,因此明顯的變更。(Fastboot 不會解讀其收到的原始映像檔,因此刷新 FVM 與 Fxfs 映像檔並沒有差異;相較之下,複製 FVM 映像檔會解讀 FVM 映像檔,所以必須新增自訂邏輯,才能將 Fxfs 圖片處理至分區映像檔安裝工具。

上述的稀疏圖片格式可用來貼上及刷新,以減少傳輸到裝置的位元組數,並減少記憶體用量。

套件安裝和 OTA 路徑異動

與 blobf 不同,Fxblob 不支援 fuchsia.io 寫入路徑 (含有重大效能問題)。而是支援新的寫入 API,這個 API 會將共用 VMO 用於資料層 (而非 FIDL),進而減少寫入 blob 所需的 FIDL 往返行程總數。

新的 API 分為兩個通訊協定:fuchsia.fxfs.BlobCreator 和 fuchsia.fxfs.BlobWriter。BlobCreator 是可探索的通訊協定,pkg_cache 可用來建立新 blob (如果不存在),而 BlobWriter 是一種私人通訊協定,用於協助將 blob 資料串流至 Fxfs。

共用 VMO 會整理成環形緩衝區,讓我們能夠管道寫入要求。Pkg_cache 會填滿環形緩衝區的某個部分,然後使用 BlobWriter.BytesReady FIDL 方法通知 Fxfs 的可用位元組。Fxfs 會等待顯示通知、從環形緩衝區載入部分資料、計算該資料的 Merkle 雜湊,然後將資料串流至磁碟。

將最終 BytesReady 要求傳送至 Fxfs 時,Fxfs 會封鎖該要求,直到根據收到的內容完整計算及驗證為止。如果雜湊和內容不符,Fxfs 就會失敗這項要求,並顯示 ZX_ERR_IO_DATA_INTEGRITY。最終呼叫完成後,Fxfs 會確保其檔案可供檢視 (也就是 fuchsia.io.Directory.ReadDirents)。

建立用戶端程式庫來封裝環形緩衝區管理。

流程大致如下:

Blob 安裝路徑

Merkle 樹狀結構驗證、解壓縮和 VMEX 處理變更

Blobfs 目前擁有 VMEX 能力,負責視需要挖掘可執行的 VMO,以及在讀取時解壓縮 blob 內容。由於 VMEX 可任意執行程式碼,因此 blobfs 也仰賴使用沙箱的解壓縮器在讀取時解壓縮 blob 內容。(Blob 內容是由外部提供,因此可視為不受信任的資料)。與解壓縮相關的其他躍點和內容切換鈕會產生極大的效能費用。

使用 Fxblob 的目標是最佳化分頁路徑的效能,這需要執行其他方面的提升,將解壓縮至 Fxfs 程序本身。不過,將更多功能加入高信任的元件,可能會造成安全疑慮。我們相信,移除 Fxfs 的信任,就能解決這些問題。

我們必須將兩個受信任的作業移出 Fxfs 以達成此目標:

  1. 對照 Merkle 樹狀結構驗證檔案內容
  2. 使用 VMEX 資源挖掘可執行頁面。

為了避免需要使用 Fxfs 來保留 VMEX 能力,pkg-cache 會接手這個責任。由於 pkg-cache 必須信任,才能從 blob 名稱對應至雜湊,這不會大幅影響指派給該元件的信任範圍,也因此可避免將 Fxfs 視為高信任元件。

我們還還需要將 VMEX 資源提供給 /bootstrap/base_resolver,因為這個元件會另外提供基礎組合的套件。這與 pkg-cache 類似 (實際上大部分商業邏輯都使用相同的程式庫)。

為了讓 Fxfs 完全不受信任,我們也需要將 Merkle 的驗證遷移至其他位置 (雖然 Fxfs 仍會儲存及提供 Merkle 樹內容)。這裡提供幾個選項:

  1. 建立高度信任的獨立元件,僅用於驗證資料。
  2. 建議您將這項功能移至高度信任的核心。

請注意,開啟 blob 時,pkg-cache 必須直接與信任的驗證器通訊,或者必須能夠直接查詢這個受信任的驗證器,以便比較驗證器使用的根雜湊與特定 blob 的預期雜湊。如此一來,即使遭駭的 Fxfs 會完全變更資料和 Merkle 樹狀結構 (讓驗證器看到竄改的資料正確),pkg-cache 將能夠偵測竄改檔案內容,並拒絕檔案內容。

選擇進行 Merkle 驗證時,必須選擇在安全性和效能之間權衡,並且值得進行詳細探索。因此,我們會在個別的 RFC 中處理這個問題,而目前驗證作業會在 Fxfs 處理。

請注意,Fusia 日後需要支援兩種其他功能,而這些功能也依賴於黑克樹:Fs-verity 和 dm-verity。部分 Linux 應用程式會分別使用這兩個功能,用來取得檔案和映像檔完整性。Fuchsia 希望在「RFC-0082:在 Fuchsia 上執行未經修改的 Linux 程式」中同時支援這兩項功能。此外,在設計非程序外的 Merkle 驗證時,也必須將這些用途納入考量。

實作

我們已採取實作功能原型的方法,並在測試和開發環境中啟用這些原型,而這個做法的執行效果相當不錯。我們打算在日後的工作和未完成的功能中繼續這麼做 (請參閱「安全性」一節,瞭解關於 Merkle 驗證的工作)。

在建構期間啟用功能旗標後,功能仍會受到管制。舉例來說,pkg-cache 會偵測新的 Fxblob 讀取和寫入 API 是否存在,並會在可用情況下主動使用這些 API,否則會改回使用一般的 fuchsia.io 機制。

效能

針對原型進行基準測試的初步結果,顯示讀取和寫入效能有所改善。在 Intel NUC 上,Fxblob 是:

  • 對 blob 中的分頁處理速度較快 55-80%
  • 編寫單一 blob 的速度快 17%
  • 並行寫入多個 blob 的速度比 Blobfs 高出 130%。

其他重要的效能面向包括記憶體耗用和儲存空間用量。正在分析這些商情項目,並解決 Blobfs 和 Fxblob 之間的重大落差。一般而言,Rust 元件通常較消耗記憶體,但 Blobfs 中的大部分記憶體用量都是源自快取頁面,而 Fxblob 的費用也相同。

Fxfs 的儲存空間使用量比 Blobfs 更加複雜,因為 Fxfs 會以一系列資料層檔案中的變更來儲存中繼資料更新,而不是針對雜訊、範圍等項目進行固定配置,而這不僅是為了移除 FVM 的格式,進而改善內部切片的格式,進而改善內部格式的儲存效能。在編寫這個 RFC 時,我們的原型實作會使用與磁碟空間相近的磁碟空間,將相等的 blob 儲存為 Blobf。

人體工學

這些變化對大部分的 Fuchsia 元件都能公開透明。目前只有 pkg-cache 會與 Blobfs 直接互動。

回溯相容性

我們會繼續支援舊版設定 (FVM + Blobfs) 的系統,並支援已發布的產品。在相關產品終止服務之前,我們會繼續支援舊版設定 (以及適當的測試基礎架構)。

所有未來的 Fuchsia 產品都會使用這項新設定,包括大多數開發人員。

未規劃遷移路徑;裝置將使用 Fxblob 或舊版設定。

安全性考量

Blobfs 是 Fuchsia 中高度信任的元件,由於 Blobfs 驗證了系統中絕大多數其他元件的完整性,因此在 Fuchsia 的已驗證的執行中扮演重要角色。(儲存在啟動檔案系統中的低階元件會透過不同方式驗證)。此外,blobfs 能夠建立可執行頁面,且其他系統元件會信任 blobfs 提供的內容,因此 blobfs 可將任意程式碼插入任何元件的位址空間,讓 blobfs 能夠模擬依賴 Blobfs 執行可執行程式碼的任何元件功能。

為降低 Blobfs 存在這些風險,我們採取的策略是,沙箱的特定作業。例如,由於剖析不受信任的輸入內容存在風險,解壓縮已移至另一個程序。如果採用沙箱機制的解壓縮器遭駭,最糟的情況就是阻斷服務,因為 Blobfs 會拒絕任何從解壓縮器傳回的無效資料。我們認為在 Fxf 的讀取路徑上,不需要採用同樣的策略,因為本機攻擊的風險較低,但我們會探討如何在寫入路徑上實作類似的沙箱策略,以防範遠端攻擊。

雖然從 Blobfs 安全性的角度來看,Fxfs 在安全性方面有一些優勢 (例如,是在 Rust 中實作在記憶體安全語言中),但情況仍比 C++ Blobfs 複雜,複雜程度也高,因此較需要緩解。

我們在上方的「設計」一節中說明瞭我們建議的因應做法。

安全性團隊注意到,共用記憶體型處理序間通訊 (IPC) 機制 (也就是用於 blob 寫入的環形緩衝區) 需要特別留意,確保讀取器和寫入器能與不合作的對等點穩定運作,特別是當共用記憶體對應時。我們會謹慎設計這些通訊協定,並視需要與安全性團隊討論。

打擊 Fxfs 的結果

由於本提案擴大了 Fxfs 的受攻擊面,因此應記錄能夠入侵 Fxfs 的攻擊者能夠做些什麼 (以及他們無法做什麼)。

Fxfs 在這個提案中不會有 Vmex 資源,雖然 Fxblob 會為系統中大多數套件的二進位檔和程式庫提供 (可執行) 內容,因為內容將由其他元件 (核心或某些使用者空間元件) 獨立驗證,因此 Fxfs 無法推論執行檔頁面,且 Fxfs 無法執行其他執行檔。

因此,威脅模型涵蓋 Fxf 可直接存取的內容:

  • Fxf 可以任意讀取及寫入資料檔案內容。這可能會導致使用者資料的機密資訊外洩,也可能遭其他元件中錯誤 (因為這些元件不會驗證儲存的資料) 外洩。
  • Fxfs 可刪除 blob 內容,這會是其他元件的阻斷服務。
  • Fxfs 可能會拒絕 blob 寫入,導致系統無法進行系統更新。
  • Fxfs 可以與封鎖的裝置驅動程式互動,並可能會惡意利用其中的安全漏洞,取得驅動程式所沒有的功能。

隱私權注意事項

以上選項皆不適用,

測試

我們實作了這個提案的原型,可啟動 Fuchsia 並執行所有一般系統功能。這個原型會在 CQ 的建構工具上啟用,該工具會執行一般系統測試套件,確保我們能實際使用並涵蓋原型。

之後,我們會進一步在更多情境中使用這項元素 (例如啟用特定產品,這會導致開發人員自然使用,並在 CQ/CI 中增加使用率)。在任何使用者裝置上使用這個架構前,預計需要長時間的浸泡時間。

單元測試、整合測試和 e2e 測試的常見測試金字塔也已新增至相關功能。我們也實作了自動化基準,以追蹤從 Fxblob 讀取和寫入的效能,並與 blobf 的效能進行比較。

說明文件

部分儲存空間說明文件需要在本提案中更新。舉例來說,「檔案系統架構」文件也應更新。

缺點、替代方案和未知

缺點:裝置磚塊的風險

就舊版架構而言,Minfs 中的錯誤只會影響 minfs。由於系統的重要部分 (二進位檔、程式庫、設定等) 會儲存在 blobf 中,因此即使資料分區已重設,系統仍會將子狀態維持在功能狀態。

將 blob 與資料合併到單一檔案系統中,表示 Fxfs 中的錯誤可能會構成裝置磚,因此這裡沒有相同的安全網路。

我們認為 Fxfs 非常強大,足以做為 Fuchsia 重要基礎架構的一環,自 2021 年起就通過廣泛測試及使用。檔案系統損毀的可能性很低。

如果發生損毀,最佳處理方式與其他作業系統類似:提供可將裝置還原至功能狀態的復原路徑。透過復原 (fxrev.dev/563864) 執行 OTA 的能力是可以克服這個問題的好方法,因此作者提供支援 (因為這可以讓他們從更多問題的角度來維修裝置)。

請注意,這並不是 Fuchsia 的唯一風險,其他大多數作業系統都有單一全域檔案系統,能儲存所有資料 (不一定有必要)。

替代做法:依賴 zx::streams 加快 blob 寫入速度

專為 Fxblob 建立的自訂寫入 API 與 zx::streams 有點相似,後者使用 VMO 做為共用資料緩衝區,並使用頁面錯誤做為控制機制。不過,串流經過精心設計,可處理更廣泛的用途 (一般檔案 I/O),並提供更多行李功能,例如內容大小追蹤、頁面錯誤負擔、減少批次處理 I/O (因為錯誤是以頁面精細的方式處理)。用途建立的 API 比較簡單且效能更佳。

Blob 寫入效能十分重要 (因為這是系統 OTA 和安裝大型套件的主要瓶頸),而且與一般檔案 I/O 相比,擁有足夠的具體限制,因此我們決定採用自訂介面。我們除了展現極佳的效能結果,也證明瞭這個做法。

先前的圖片和參考資料

既然如此,本提案讓 Fuchsia 更接近大多數以一般用途檔案系統達成更廣泛用途的作業系統,並提供內容可定性和透過其他機制進行驗證等特殊功能。雖然我們正在為這個提案新增一些特殊功能至 Fxfs,但大多數工作都是在 Fxfs 的外部層進行,核心檔案系統則維持不變。

例如,在 Linux 上,一般用途檔案系統可與 dm-verity 或 fs-verity 合併,分別提供圖片和特定檔案的內容驗證作業。