RFC-0005:Blobfs 快照

RFC-0005:Blobfs 快照
狀態已遭拒
區域
  • 儲存空間
說明

支援在升級期間使用 Blobfs 快照。

變更
  • 424179
作者
審查人員
提交日期 (年/月)2020-09-06
審查日期 (年/月)2020-09-21

摘要

這個 RFC 說明一種簡單的快照機制,可提高升級過程中錯誤的彈性。對 Fuchsia 磁碟區管理員 (FVM) 所做的變更,允許接收 Blobfs 分區的快照,可在升級期間的任何階段還原。

提振精神

在寫入時,如果升級導致 Blobfs 分區損毀,可能會導致裝置處於難以復原的狀態。目前,復原分區無法還原裝置處於此狀態,因此在這些情況下,還原的唯一方法是透過系統啟動載入程式,使用對使用者來說較不方便的程序。

快照機制可降低我們達到這個狀態的風險。

設計

基本概念是支援 FVM 中的原始快照機制,可在升級期間顯示兩個分區,但可在分區之間共用資料。

目前 FVM 是簡易的磁碟區管理員,它能將切片從任意切片對齊的邏輯偏移對應到基礎裝置上的特定偏移,並且保持不同分區的對應。

Blobfs 由下列不同的區域組成:

區域
超級封鎖
分配點陣圖
節點
日誌
資料

為支援本提案,我們可在 FVM1 中允許使用不同配量類型。這些類型適用於配量的「延伸」

類型 說明
A/B 配量 若切片中有備用副本,就很適合採用這個範圍。
A/B 點陣圖2 若配量有備用的點陣圖,就代表共用資料範圍中的配置。
分享的資料 這應該是配置由 A/B 點陣圖範圍管理的切片範圍。
分享 這情況是在兩個分區之間共用的範圍,但一次只能寫入一個分區。

透過這些配量類型,FVM 便可顯示「兩個」分區,顯示範圍的 A/B 變化版本。回到 Blobfs 區域,我們可以得出:

區域 類型
超級封鎖 A/B 配量
分配點陣圖 A/B 點陣圖
節點 A/B 配量
日誌 已分享3
資料 分享的資料

在多數情況下,只有其中一個分區會處於有效狀態,且系統會照常顯示。

在升級期間,第二個分區可以啟用,此時第一個分區會「鎖定」且不再允許寫入,但會繼續提供讀取。您可以準備第二個分區,方法可能與目前相同,但在整個升級期間,您隨時可以改回使用第一個分區,這樣保證將保持不變。

從 A/B 範圍中,您可以輕鬆瞭解第一個分區資料的保留方式;第二個分區將看不到第一個分區的資料。在日誌中,共用地區 — 只有可寫入的分區才能寫入其中 (即第二個分區)。如果是共用資料地區,點陣圖會指出可寫入區塊的區塊。標示為第一個分區使用的區塊似乎對這兩個分區顯示為唯讀狀態。

為促進這項配置,第二個分區也必須能讀取替代點陣圖,讓使用者知道可以分配哪些區塊,因此為了允許這種情況,這個配置會顯示在目前未使用偏移的邏輯位址空間中。「strawman」提案是所有替代 A/B 範圍都會顯示在相同的位移,但頂端位元組合 (唯讀)。

下圖希望說明每個分區的顯示方式:

分區排列

圖 1:分區排列方式。

注意:

  • 我們採用了簡單的 A/B 分區方法,但並不是全部,反而能享有部分韌性。
  • 我們可以保留目前的漸進式更新方法 (也就是僅更新已變更的 blob),但最終不會產生可預測的版面配置。在使用者建構中,我們可以選擇完全重寫所有 blob,但我們還是需要片段化。
  • 這麼做會增加 FVM 的複雜度。

新版升級流程

必須修改升級流程,以利建立快照互動。目前的流程如圖 2 所示,圖 3 中建議的替代方案。新的 API 和互動會以不同顏色顯示。

目前的 OTA

圖 2:目前的升級實作 (高階)

無線更新 (OTA)

圖 3:提議的升級實作 (高階)

新 FVM 作業

您必須在軟體推送 (SWD) 堆疊中實作數個新的 FVM 作業,並將其整合到此堆疊中。這些 API 可用於驅動狀態機器 (圖 4),最終在分區之間切換系統。

快照狀態機器

圖 4:用於建立快照的狀態機器。

TakeSnapshot

將使用中分區的中繼資料擷取至先前清除的替代分區 (請參閱「DeleteSnapshot」)。使用中的分區就會變成唯讀狀態,所有後續寫入作業現在都必須移至已停用的分區。

  • FVM 將使用中的分區設為唯讀。
    • 必須清除待處理的日誌項目。
  • FVM 會建立非使用中的分區。
  • FVM 會複製有效 -> 非使用分區的中繼資料。

在這個多步驟程序的期間,您無法寫入新的 blob,而且必須捨棄半寫入的 blob,而且由於負責寫入 blob 的元件應是負責要求快照的相同元件,因此不應受到限制。

CancelSnapshot

取消 TakeSnapshot 建立的快照填入作業,清除無效分區,並允許建立其他快照。

  • 目前,必須關閉已停用分區的所有讀取連線。
  • FVM 刪除未使用的分區。使用中的分區會再次寫入。

SetWritablePartition

切換可寫入分區的切換按鈕。

  • 您必須在這個時間點清除日誌 (所有待處理作業都必須完成)。上圖中的 fsync 呼叫可以達成這個目的,但理想做法是將日誌清除與此作業的其餘部分一起進行,以免新的寫入作業會「短暫進入」。

這可能很少使用,因為 TakeSnapshot 會自動切換可寫入的分區,但如果需要傳回並將使用中的分區進行寫入 (例如為了收集未使用的 blob),您可以使用這個 API。

SetBootPartition

變更可啟動分區的變更。

一般而言,可開機分區會視啟用的 ZBI 運算單元而變更,但也可以另外切換哪個分區可啟動。這可能很少用到。

DeleteSnapshot

將替代分區標示為「已清除」。FVM 可選擇刪除其中的中繼資料。

ListSnapshotPartitions

針對為建立快照的分區查詢 FVM。

QuerySnapshotPartition

查詢 FVM,取得支援快照的分區相關資訊。

  • 用於識別 A/B 分區的狀態,例如啟用中。

故障模式

系統可能會從州級機器中描述的任何狀態發生失敗。本節說明系統發生錯誤時可採取的適當行動。

請注意,失敗可能是自願因素 (即系統主動決定取消進行中的更新) 或非自願 (因為系統因外部因素而失敗,例如失去電力)。這兩個情況都必須列入考量。

請注意,blobfs 具備日誌機制,可在修改期間發生非自願故障時,避免中繼資料損毀。您無須進行額外作業,就能讓 blobfs 完善可靠,進而在修改期間發生非自願失敗情形。

應視情況進行 FVM 中的所有新中繼資料作業,以免 FVM 在修改期間發生非自願失敗,因而損毀。

狀態 1:TakeSnapshot 前

此狀態中的失敗處理不需要變更;行為與目前的系統行為相同。

狀態 2:TakeSnapshot 之後,重新啟動前

  • 如果是非自願故障,您可以叫用 cancelSnapshot API 刪除非使用中的分區,並將系統回復為狀態 1。
  • 如果是非自願的失敗,系統在恢復連線時可決定直接取消更新 (叫用 cancelSnapshot),或是選擇嘗試繼續更新。

狀態 3:重新啟動後 (TakeSnapshot 之前)

等同於狀態 1。

支援臨時套件

臨時套件是指未包含在指定系統版本的基礎套件組合中的套件。

本提案針對臨時套件設有幾項額外限制;下方的「建立新檔案的轉送路徑」一節將說明 OTA 期間,任何狀態仍可繼續支援暫時套件,其中需注意的是,如果在準備新的基礎分區期間取消快照,便必須刪除臨時套件。

臨時套件可能會一直存在,因為在更新到有效分區之前寫入的套件會在呼叫 TakeSnapshot 時複製到已停用的分區,且所有臨時套件都會寫入新的分區,而新的分區可以讀取及寫入系統 (更新完成後會成為新的有效分區)。

轉送新建立的檔案

在決定新檔案安裝位置時,必須考慮三個情況。為了簡化討論,假設分區 A 處於啟用狀態,而 B 分區為停用狀態。

案例 1:TakeSnapshot 之前

  • 基本套件:未寫入。
  • 臨時套件:寫入分區 A.

案例 2:TakeSnapshot 之後,重新啟動前

  • 基本套件:寫入分區 B。
  • 臨時套裝方案:寫入分區 B。請注意,如果取消快照,系統就會在嘗試下一個快照前刪除這些套件。

案例 3:重新掛接後 (NB:相當於「Before TakeSnapshot」)

  • 基本套件:未寫入。
  • 臨時套裝方案:寫入分區 B。

FVM 中繼資料異動

FVM 的中繼資料結構如下:

區域 說明
超級封鎖 您期望的事
分區表 項目陣列,每個分區各一個,內含分區名稱、類型等項目。
配量分配 項目陣列,每個可分配的切片各有一個項目,指出其分配到哪個分區 (如有) 和該分區內的邏輯偏移。

為了促進提案,我們需要額外的中繼資料來記錄程度的切片類型,因此必須將下列內容儲存在某處:

enum class uint32_t SliceType {
  kNormal,
  kAB,
  kABBitmap,
  kSharedData,
  kShared,
};

struct {
  uint32_t slice_offset;  // Offset within the partition
  SliceType slice_type;   // The slice type
} extents[8];

這個中繼資料可以新增至每個分區項目。更好的做法是新增包含此中繼資料的單獨分區 (即快照中繼資料分區)。本文不會討論這項中繼資料的精確位置和結構,並僅做為實作詳細資料。

採用這個結構後,Blobfs 的程度將為:

[
  /* super block: */       { 0,                    SliceType::kAB },
  /* allocation bitmap: */ { 0x10000 / kSliceSize, SliceType::kABBitmap },
  /* inodes: */            { 0x20000 / kSliceSize, SliceType::kAB },
  /* journal: */           { 0x30000 / kSliceSize, SliceType::kShared },
  /* data: */              { 0x40000 / kSliceSize, SliceType::kSharedData }
]

必須提供某些狀態,藉此指出兩個分區中哪些是目前可寫入,且兩個分區是否有效 (或只有一個),以及哪個分區應視為可開機4

配量分配不需要變更,但需要分配不同偏移量的配量。

超級區塊可能還有其他小幅變更 (例如版本中碰到的問題)。

支援 blobfs 格式演進

本提案大幅簡化了 blobfs 格式的演進,因為替代分區可以完全刪除並重新建立,而且每次更新時耗用少許費用。

即便如此,調整本提案中的 blobfs 格式時,還是要克服兩項挑戰。

  • 區塊配置地圖無法變更,因為該結構是有效/無效分區之間共用的結構。(由於配置圖很簡單,這似乎是可接受的做法)。
  • 使用中的分區無法覆寫非使用中分區所分配的任何範圍。但是,這就非常簡單:如果某些資料的內部格式需要變更,那麼在 TakeSnapshot 呼叫期間,系統就可以分配新的範圍並移動資料。

實作

實作需要進行下列變更,而這些變更大致取決於這些變更前的變更:

  1. FVM 和分區設定變更。
  2. 對 Blobfs 分配進行變更。
  3. 早期啟動程式碼的變更。
  4. 升級程序變更為使用新 API。

大部分的異動都是由 #1 和 #4 要求。#1 涉及變更磁碟機格式,且透過清除安裝來遷移。如要還原,您還必須安裝全新安裝。這是涉及多數風險的關鍵步驟,但請注意,只需要變更格式;所有使用新 FVM 中繼資料的程式碼都可能會停滯,直到後續階段為止。

其他步驟全都可在不需安裝全新的情況下完成,且同樣可以還原。

效能

這樣做並不會對效能造成影響。升級期間可能會因為建立快照所需的費用而產生些微影響,不過相較於其他升級活動,這可能微不足道。在這段時間內,應該不會有任何變更。

聊天室需求

空間需要保留給 Blobfs 區域的額外副本:Superblock、Inode 資料表和點陣圖。具體金額取決於裝置的設定,但相較於 Blobf 的可用空間總量,實際成效應相對較少。

安全性考量

無。

隱私權注意事項

無。

測試

Google 會採用標準 Fuchsia 測試做法。現有的系統測試應已用於測試升級作業。我們會進一步納入這些測試,包括確實損毀新的 Blobfs 分區,以及嘗試破壞快照分區的測試。

說明文件

我們會在「Fuchsia」>「概念」>「Filesystem Architecture」下方說明 FVM 的新架構和功能。

缺點、替代方案和未知

完整 A/B 提案

考慮完整的 A/B 提案。雖然這個提案的概念很簡單 但有一些缺點

  • 每個分區只能使用 50% 的可用磁碟空間。
    • 這目前是我們系統更新的「軟」限制,預算預算只使用 50% 的可用 Blobfs 空間,但 A/B 提案則會造成嚴格限制。
    • 工程版本已超出 50% 的預算,因此不支援修改許多檔案的升級作業。工程師極度仰賴進行漸進式小規模更新的能力,因此破壞這個工作流程是一項非起步。
  • 分區之間沒有共用檔案的機制,因此每次更新都會重新寫入每個檔案。
    • 進而造成額外的閃光燈穿戴和升級速度變慢。每次更新 基本上都是每次更新

完整 FVM 快照功能

開發完整的 FVM 快照功能可能會遇到困難。傳統的快照機制通常屬於動態性質,也就是說,中繼資料必須在寫入時更新。此外,FVM 的配量大小 (目前為 1 MiB,即將達到 32 KiB) 和 Blobfs 的區塊大小 (8 KiB) 不符。要解決這個問題,FVM 的複雜度會大幅增加,而且也有可能導致空間用盡的情況。也許可以開發使用靜態對應方式的配置,但配置太長,最後提案就會與這裡呈現的提案不同。總而言之,這種做法可能需要更長的時間才能完成實作,也可能有嚴重的缺點 (寫入增強、複雜性),而且無法提供我們近期需要的明確好處。完整的快照功能有可能長期有助於,因此 FVM 的中繼資料的精確設計應提供擴充空間,以支援未來的相關用途。

先前的圖片和參考資料

可靠且有彈性的升級是常見的問題,通常可以透過以下方式解決:

  1. A/B 副本:保留功能相同的副本,並視需要在副本之間切換。簡單但成本空間。
  2. A/R 副本:保留復原副本,這種精簡版本僅支援還原軟體。較複雜且空間不足,使用者體驗會稍微降低。
  3. A/B/R:#1 和 #2 的組合。
  4. 一則 + 數據匯報:在多數情況下,只有一個副本。升級時,請拍攝 A 的快照,然後對快照套用更新。您隨時可以提供復原至快照的選項。通常很複雜但有彈性。

作者認為 Android 使用第 3 名、iOS 和 macOS 的第 2 名及第 4 名。

本 RFC 是 #4 的簡化版。

解除權的理由

我們決定停止對這個 RFC 工作,在此 RFC 的開發作業持續了數個月。這項決策包含多項因素,主要考量如下:

  • FVM 程式碼集內的技術債導致進度緩慢,且有風險的變更。因為缺少 FVM 格式配置的測試涵蓋範圍、長期錯誤和廣泛的假設 (由於缺少 FVM 格式封裝) 是主要的障礙。

  • FVM 沒有充足記錄,且團隊難以理解 FVM 內容。有關 FVM 的機構知識隨著時間逐漸下降,最初假設 FVM 會是相對簡單且適合用於建構這項功能的位置,並不正確。

  • 這項功能的推出成效高於原先所理解的,因為這項功能需要 FVM 主要格式修訂版本,而此版本會對工程工作造成嚴重干擾 (因為需要重新製作裝置,而且推出 Zedboot 版本,因此會造成嚴重干擾)。

由於這項功能開發的風險很高,且很有可能對日漸成長的 Fuchsia 開發人員社群造成影響,所以現在我們決定不採用這項功能。因此,儲存團隊將重點放在改善測試涵蓋範圍和自動化作業,以降低這項 RFC 動機帶來的風險,並繼續重寫 FVM 主機工具 (意即非預期的複雜性來源),並評估降低對特定 FVM/Zedboot 版本的依賴程度,降低對開發人員的依賴性,從而在需要更動時,降低對開發人員造成的影響。


  1. 請注意,這些額外的配量類型不需要新增至 FVM 格式;有多種方式表示這項中繼資料,而精確的格式會以實作詳細資料的形式保留。 

  2. 為了可能的簡化,我們排除 A/B 點陣圖和共用的資料類型,並且信任 Blobf 的行為正確。但是,在 FVM 內加入這個部分,有助於我們防範 Blobfs 實作中的錯誤。您也可以選擇離開聊天室,並在後續階段新增這項資訊。 

  3. 可分享日誌的區域。啟用第二個分區時,可清除日誌,屆時不再需要鎖定的唯讀分區時,只需要避免可寫入的分區不一致的情況。 

  4. 此可開機狀態可能會儲存在其他位置,並在繫結時傳送至 FVM,但僅將此狀態儲存在 FVM 中較容易。