RFC-0236:VMO 快照-修改的本機副本

RFC-0236:VMO 快照修改本機副本
狀態已接受
區域
  • 核心
說明

目標是推出新的 VMO 子項類型,讓您能夠擷取快照,捕捉 pager 支援 VMO 中的任何修改頁面。

問題
Gerrit 變更
作者
審查人員
提交日期 (年-月-日)2023-07-20
審查日期 (年-月-日)2023-12-12

摘要

目標是推出新的 VMO 子項類型,讓您可以擷取 pager 支援 VMO 子項中任何已修改的頁面快照。

提振精神

目前核心支援兩種 VMO 複本 (也稱為子 VMO):真正的快照,在複製作業完成後,兩個 VMO 都不會看到彼此的變更;以及快照-至少在寫入時複製,在作業完成後,子項可以看到父項 VMO 的變更,但已寫入子項的頁面除外。

複製作業可在 VMO 複本上重複執行,建立子 VMO 的階層。為了簡化實作方式,Zircon 核心不允許混合階層;您可以建立真實快照的階層,或建立寫入時快照的 VMOs 階層。

隨著 Starnix 的發明,Fuchsia 必須有效支援 fork()。分支作業需要將父項程序的整個位址空間複製到子項程序,其中包括匿名記憶體,以及分頁器支援的資料和程式碼 VMOs。

問題是因為核心只支援匿名記憶體的真實快照,而對於分頁器支援的 VMO,它只支援寫入時快照的克隆。因此,fork() 合約無法滿足複製要求:因此 Starnix 必須強制實作急切副本和/或其他 CPU 和記憶體密集的因應措施。

相關人員

誰會受到這項 RFC 是否通過的影響?(此為選用部分,但建議您填寫)。

csuter@google.com、jamesr@google.com

協助人員:

davemoore@google.com

審查者:

rashaeqbal@google.com、jamesr@google.com

諮詢:

列出應審查 RFC 但不需要核准的人員。

csuter@google.com、adanis@google.com、cpu@google.com、mvanotti@google.com、lindkvist@google.com

社會化:

我們與 Zircon 團隊和 starnix 的部分成員分享設計文件,並將 CL 工作進度與利益相關者分享,以便進行基準測試。

需求條件

  • 針對同時具備分頁器支援的 VMOs 和匿名 VMOs 的複製作業空間提供高效支援。
  • 在父項或子項 VMOs 的情況下,如果處理程序無法存取 VMO (最後一個句柄已關閉),則不應浪費記憶體,也就是以下兩種情況:
vmo = create_vmo();
   loop {
      child = create_snapshot_modified(vmo)
      child.write(...)
      vmo = child  // old vmo is dropped
   }
vmo = create_vmo();
   loop {
      vmo.write(...)
      child = create_snapshot_modified(vmo)
      // child is dropped
   }

設計

ZX_VMO_CHILD_SNAPSHOT_MODIFIED 是一種新的 VMO 複本,可用於建立快照修改子類型。

這個標記會建立子項,保留任何頁面的快照,這些頁面是由 pager 支援的 VMO 子項修改。從語意上來說,這就像是在父項中執行對任何未由分頁器支援的頁面執行立即複製作業。由分頁器支援的父項中的頁面,至少會將「寫入時複製」語義導入複本。這與原始快照語意不同,後者會在 VMO 的所有頁面上建立急迫副本。

首次在 pager 支援的 VMO 上使用時,語意會以使用 SNAPSHOT_AT_LEAST_ON_WRITE 的方式運作。系統會建立複本的句柄,該句柄最初與父項相同,但可對複本進行修改,導致複本與父項分歧。

當用於任何匿名 VMO 時,SNAPSHOT_MODIFIED 複本會升級為含有快照語意的複本,類似於 SNAPSHOT_AT_LEAST_ON_WRITE 使用的現有複本類型升級語意。

這個標記不適用於複製具有固定區域、切片或 zx_vmo_create_physical()zx_vmo_create_contiguous() 的 VMOs。

保護殼

在 pager 支援的 VMO 上使用快照修改

建立 SNAPSHOT_MODIFIED 的單一複本,其行為就如同建立單一 SNAPSHOT_AT_LEAST_ON_WRITE 複本一樣。執行複製作業時,新 VMO 會與父項相同。

在複本上執行另一個 SNAPSHOT_MODIFIED 之前,複本仍可修改。複本中任何未修改的網頁都至少會使用寫入時複製的語意。

在至少在寫入後或快照修改後修改

的 pager-backed VMO

由於 SNAPSHOT_MODIFIEDSNAPSHOT_AT_LEAST_ON_WRITE 在 pager-backed VMO 上的行為相同,因此在 pager-backed 的複本上呼叫 SNAPSHOT_MODIFIED 的兩種情況都會產生相同的語意。任何不再由分頁器支援的網頁都會有快照,而由分頁器支援的網頁則至少會有寫入時複製的語義。

快照後修改的快照

在這種情況下,語意會升級為快照,類似於 snapshot-at-least-on-write。

不支援的情況

以下情況目前不支援,如果嘗試複製 SNAPSHOT_MODIFIED,系統會傳回 ZX_ERR_NOT_SUPPORTED

快照修改後的至少在寫入時快照鏈結

快照修改功能可能會擴充,以便在快照至少在寫入時鏈結的結尾使用。不過,這可能會導致結果混淆,因為複製的 VMO 中未分支的網頁可以透過單向 VMO 鏈結查看修改內容,而最接近的親屬就是讀取的網頁。這會與原始承諾產生不一致性,因為原始承諾指出可為任何已修改的網頁建立快照。

在快照至少在寫入時鏈結中進行快照修改

快照修改功能絕對不能用於含有子項的 VMO (也就是位於快照至少在寫入鏈結中間),因為這可能會建立不一致的階層。

命名法

zx_vmo_create_child() 中現有的複製類型標記命名慣例旨在以描述所提供語義的方式命名標記。這個標記目前的名稱為 SNAPSHOT_MODIFIED,因為它總結了複本中經過修改的網頁快照行為。類似的選項是 SNAPSHOT_MODIFICATIONS。其他考慮的標記是 SNAPSHOT_MIXED,雖然可以描述語意,但不夠明確。SNAPSHOT_PAGER_MODIFICATIONS 是另一個考量,但將 VMO 與 pager 配對並不理想。

實作

快照修改會影響 Zircon 中的多個檔案,但可分解為 CL,在選項標記新增至系統呼叫之前,在核心內部新增對新快照類型的支援。

我們會新增一些核心內測試,以便在第一階段驗證新結構的正確行為,並在引入選項旗標時加入更複雜的核心測試。

成效

在大多數情況下,系統只會在建立新的快照修改複本時呼叫新加入的程式碼,因此現有程式碼的效能不會發生非預期的變化。唯一的例外狀況是,建立 SNAPSHOT_AT_LEAST_ON_WRITE 子項時,簡單方法會額外取得 VMO 鎖定,但如果這會導致效能受損,則重構複製選取程式碼即可輕鬆避免這種情況。

安全性考量

快照修改作業不太可能引入任何安全漏洞,因為它是使用現有的 Zircon 原語元建構,且不會引入任何新功能。

測試

核心單元測試和核心測試會與相關 CL 一併提供。

說明文件

我們將發布一份針對 Zircon 開發人員的詳細設計文件。這份文件將概述新的資料結構、支援和不支援的案例、程式碼變更、挑戰和替代方案。

系統會在 zx_vmo_create_child() 中新增標記,並附上說明:

ZX_VMO_CHILD_SNAPSHOT_MODIFIED - 建立子項,讓其行為就像在父項中執行了對任何未由分頁器支援的頁面執行的急迫複製作業,也就是由分頁器支援的 VMO 子項修改的頁面。使用 Pager 的頁面至少會具有寫入時複製的語意。這個標記可能不適用於使用 zx_vmo_create_physical()、zx_vmo_create_contiguous() 建立的 VMOs、含有釘選頁面的 VMOs,或這些 VMOs 的後代。對於使用 SNAPSHOT_AT_LEAST_ON_WRITE 建立的任何 VMOs,如果其子項不是非切片,或是非 pager 支援的 VMO 子項,則也不支援此標記。

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

使用現有的 Zircon VMO 基本元素,為 pager 支援的 VMO 建立快照語意並非易事。使用者分頁器會透過服務單一 VMO 的頁面要求運作,目前其子項會形成單一單向鏈結,並採用「寫入時複製」語意。

可在匿名 VMO 上使用的快照標記會建立隱藏的 VmCowPages,這是目標 VMO 和新快照的共同祖系。由於沒有任何指向隱藏 VmCowPages 的項目,因此無法修改其頁面,因此該頁面是不可變動的。這個隱藏的 VmCowPages 會保留目標 VMO 中的頁面,子項中的修改會採用「寫入時複製」語意。因此,在這個階層中搜尋網頁時,系統會向上瀏覽樹狀結構,並在隱藏的根目錄結束。

由於根 VMO 一律會隱藏,而原始 VMO 會成為左側子項,因此很難使用現有的快照資料結構供分頁器使用。如果分頁器仍指向原始 VMO (現在有隱藏的父項),則分頁器作業必須向上傳播至隱藏的根目錄,以便根據子項的要求提供頁面。這會導致不一致性,因為頁面會新增至未運作的節點。

最簡單的解決方案是建立混合階層,其中根層級是可見的,且有一個隱藏的子項,可做為快照樹狀結構的隱藏根層。

向使用者說明提供的語意有許多種方式。RFC 中的說明概略說明瞭與翻頁器相關的提供行為,但另一種定義方式是僅針對頁面進行修改和複製。舉例來說:

「這個標記會建立子項,保留父項中任何已修改的頁面快照。如果根 vmo 在快照發生後寫入未修改的頁面,則快照修改的子項會看到變更。這與原始快照語意不同,後者會以建立急迫複本的方式運作。」

這個說明正確無誤,但需要進一步說明這個行為的附註,即這個行為需要使用分頁器,因為在匿名 VMO 上使用時,標記會升級為快照語義。

是否可以使用 SNAPSHOT_MODIFIED 取代 SNAPSHOT_AT_LEAST_ON_WRITE?

由於兩種本機副本類型的語意不同,因此逐步淘汰「至少在寫入時快照」並以「快照修改」取代,這項作業可能會導致意料之外的行為。雖然兩種複本類型都提供「至少寫入時複製」語意,但快照修改類型可在同一個 VMO 中混合使用快照和至少寫入時複製的網頁。此外,變更需要進行效能測試。如果 VMO 是分頁器支援的,則「至少在寫入時建立快照」會為每個建立的複本分配較少的記憶體,因為不會建立隱藏的共同祖系。因此,如果將所有使用影像擷取的用途都遷移,在某些用途下可能會導致效能倒退。

不過,還是值得考慮替換 SNAPSHOT_AT_LEAST_ON_WRITE,因為這樣可以簡化 zx_vmo_create_child() 的 API,因為大多數 fdio 輔助程式都保證語義與 SNAPSHOT_MODIFIED 相容。

既有技術與參考資料

zx_vmo_create_child()