RFC-0204:VMO 參考資料子項

RFC-0204:VMO 參照子項
狀態已接受
區域
  • 核心
說明

用於追蹤參照的 VMO 子項類型。

問題
  • 81316
變更
作者
審查人員
提交日期 (年/月)2023-01-04
審查日期 (年/月)2023-01-03

摘要

本文件的目標在於導入新的 VMO 子項類型,以便明確追蹤 VMO 的參照。

提振精神

使用 VMO 表示記憶體中檔案的檔案系統,必須追蹤何時可以對這些 VMO 進行垃圾收集。這可能包括將已修改的 VMO 內容清除至磁碟、從使用者分頁服務卸離 VMO、拆解 VMO 本身、釋出頁面,以及釋出檔案系統用於追蹤開啟檔案所用的任何內部中繼資料。

檔案系統可透過多種方式與用戶端共用檔案 VMO。並將重複的控點傳送到 VMO,讓用戶端直接用來讀取及寫入 VMO 中的頁面。用戶端也可以使用 zx_vmar_map() 的 VMO 控制代碼建立 VM 對應、捨棄 VMO 控制代碼,然後繼續透過 VM 對應中的位址存取 VMO 頁面。檔案系統也可以搭配 zx_stream_create(),使用 VMO 建立串流,並將串流控點傳送給用戶端。您需要統一的參照計數機制,才能追蹤所有類型的參照。

Blobfs 是不可變更的檔案系統,在 Fuchsia 上提供執行檔,會嘗試建立檔案 VMO 的副本 (ZX_VMO_CHILD_SNAPSHOT_AT_LEAST_ON_WRITE) 副本來解決這個參照計數問題。blobfs 會持有檔案 VMO 的唯一控制代碼,每當用戶端要求檔案時,系統就會用來建立 CoW 副本。它是 blobfs 釋出的本機副本控制,而非原始 VMO。然後,參照計數會對應用於追蹤未解決本機副本的數量,而 blobfs 可以等待 ZX_VMO_ZERO_CHILDREN 信號在原始 VMO 上啟用,以便在本機副本數量下降到零時進行垃圾收集作業。這也適用於 VM 對應,因為即使已捨棄 VMO 控制代碼,VMO 也會在內部保留 VMO。Blobfs 目前不會發布串流內容。

這種使用 CoW 本機副本的參照計數策略適用於不可變更的檔案系統,但在套用至可變動的檔案系統時 (例如 fxfsminfs) 會中斷。在可變動的檔案系統中,對用戶端檔案參照所做的任何變更都應反映在原始檔案中。換句話說,在 CoW 本機副本中執行的任何寫入作業,都應將其存回父項 VMO。這違反 CoW 語意,因為當核心在 CoW 複製作業中編寫頁面時,核心會在本機副本中建立父項頁面的副本;本機副本的變更一律不會顯示在父項中。此外,快照副本 (ZX_VMO_CHILD_SNAPSHOT) 也存在類似問題。子項中的更新永遠不會顯示在父項中,反之亦然。

這樣就沒有 ZX_VMO_CHILD_SLICE VMO 子項類型。在表面上,切片可能會在這裡顯示,因為切片為父項頁面提供直接視窗,所以需要在這裡顯示。不過,配量有其限制,您無法針對可調整大小的 VMO 建立配量,也無法自行調整大小。可變動的檔案系統希望允許用戶端調整其檔案 VMO 大小。因此,目前可用的三個 VMO 子項類型在使用 VMO 子項的參照計數配置中都不足。

相關人員

講師:

  • cpu@google.com

審查者:

  • adanis@google.com、godtamit@google.com

顧問:

  • brettw@google.com、cdrllrd@google.com、csuter@google.com、travisg@google.com

社群媒體化:

這款設計與 Zircon 團隊進行了溝通,並於核心演進工作小組討論。

設計

ZX_VMO_CHILD_REFERENCE 是一種新的 VMO 子項類型,可用於追蹤 VMO 的長期參照。意圖是每當檔案系統為用戶端需要新的檔案 VMO 參照時,都會建立參照子項,並將其視為原始的 VMO。串流會根據參照子項 (而非原始 VMO) 建立。同樣地,系統也會為參照子項建立 VM 對應。如此一來,核心就能利用現有的 VMO 子項追蹤機制,追蹤 VMO 的參照次數。檔案系統可以使用 ZX_VMO_ZERO_CHILDREN 信號來判斷是否保留任何參照,並且可以放心刪除 VMO。

請注意,重複使用 ZX_VMO_ZERO_CHILDREN 信號表示只要「任何」類型的子項存在,而不只是參照子項,檔案系統就無法拆解原始 VMO。然而,這沒有問題,且允許檔案系統根據需求混用不同的子項類型。舉例來說,blobfs 可繼續使用 CoW 本機副本處理需要限制用戶端寫入的資料區隔,並將參照子項 (使用 ZX_VMO_CHILD_NO_WRITE 建立唯讀) 用於文字區隔。但還是可以使用 ZX_VMO_ZERO_CHILDREN 信號進行統一參考計數配置。

參照子項建立作業

zx_vmo_create_child() Syscall 將支援新的選項標記 ZX_VMO_CHILD_REFERENCE。從概念上來說,這是父項 VMO 的參照,因此 offsetlength 參數並不重要,而且兩者都必須設為 0。參照子項一律會參照父項 VMO 的完整類型。另一個做法是讓呼叫端將 offset 指定為 0length 做為 VMO 的目前大小,但這會讓呼叫端隨時知道父項 VMO 大小 (可能需要呼叫 zx_vmo_get_size() 呼叫) 負荷多大的負擔。在檔案系統用戶端持續變更 VMO 大小的情況下 (例如附加至檔案),檔案系統可能必須發出多次 zx_vmo_get_size() 呼叫,直到看到穩定大小為止。

參照 ZX_VMO_ZERO_CHILDREN 信號的規則也會套用至現有子項類型。建立參照子項將會停用信號 (如果先前為啟用),刪除最後一個子項將啟用信號。

大小調整

只有在父項 VMO 是使用 ZX_VMO_RESIZABLE 建立時,才能使用 ZX_VMO_CHILD_RESIZABLE。您可以建立無法調整大小的參照,或是可調整大小的 VMO 參照。不過,您無法針對無法調整大小的 VMO 建立可調整大小的參照;只能將參照子項視為父項 VMO 的參照,而且如果父項 VMO 無法調整大小,參照子項就沒有任何方法能夠調整大小。

參照會繼承父項的 ZX_VMO_RESIZABLE 選項。透過參照控點本身進行可調整的情況將由控點上的新的 ZX_RIGHT_RESIZE 決定,只有在使用 ZX_VMO_CHILD_RESIZABLE 建立參照時才會新增。無法調整大小的參照仍可由父項調整大小;這裡無法調整大小,只是限制透過參考直接調整大小的功能。將 ZX_RIGHT_RESIZEZX_VMO_RESIZABLE 選項標記分開,即可掌握此差異。

推出新的 ZX_RIGHT_RESIZE 時,需要將其整合至所有現有的 VMO API (如適用)。方法是使用 ZX_VMO_RESIZABLE 旗標 (如果是 VMO 子項) 建立 VMO 控制代碼的預設權限集,或為 VMO 子項新增 ZX_VMO_CHILD_RESIZABLE

為參照可調整大小的 VMO 而建立的所有 VM 對應都必須使用 ZX_VM_ALLOW_FAULTS 旗標,無論參照處理常式本身是否具有 ZX_RIGHT_RESIZE 都一樣。

與 VMO 配量的差異

參照子項提供的許多功能都與 ZX_VMO_CHILD_SLICE 重疊。兩者之間有一些主要差異:

  • Slice 可以為 VMO 中的子範圍提供視窗。參照一律會橫跨整個 VMO。
  • 無法為可調整大小的 VMO 建立 Slice,也無法自行調整大小。系統可能會為可調整大小的 VMO 建立參照,且可自行調整大小 (如果父項可調整大小)。

支援 VMO 類型

您可以為所有使用 zx_vmo_create()zx_pager_create_vmo() 和此類 VMO 子系建立的 VMO 建立參照子項。這會排除使用 zx_vmo_create_contiguous()zx_vmo_create_physical() 建立的 VMO,但不會完全排除這些用途。連續和實體 VMO 都無法調整大小,因此使用者可以改為針對整個 VMO 建立配量,藉此取得相等的行為。

與 VMO 作業互動

參照的所有 VMO 作業只會轉送至父項。例如:

  • VMO 的讀取和寫入作業就像直接在父項 VMO 上執行一樣。
  • 修訂和解除修訂也會轉寄給父項。
  • 針對參照子項建立 VM 對應時,會對應父項中的對應頁面。

建立參照的子項

建立參照子項的功能將受到與父項 VMO 上子項建立作業相同的一組規則所控管。舉例來說,如果父項 VMO 是支援分頁功能的 VMO,因此不支援 ZX_VMO_CHILD_SNAPSHOT,其參照子項也不支援 ZX_VMO_CHILD_SNAPSHOT

根據參照建立子項時,子項的 parent_koid 會指向參照,即使在概念上,子項可以視為原始 VMO 的子項。這麼做的用意是準確呈現子系 VMO 的建立鏈;如果使用巢狀配量,這個行為會與子項建立時的現有行為一致。

網頁歸因

由於參照中的所有頁面都會參照父項 VMO 中的頁面,因此父項會繼續歸因於所有頁面,如 committed_bytes (zx_object_get_info()) 所回報。參照不會直接存放任何頁面,且頁面歸因計數一律為零。這與 VMO 頁面歸因的現有模型一致,而每個頁面只會歸因於一個 VMO。

調整參照大小

調整參照大小時,系統會調整父項 VMO 的大小。同樣地,父項 VMO 的大小調整作業也會反映在參照內容中。參照也會遵循父項 VMO 的內容大小,而且可以使用類似 VMO 大小來存取及操控其內容。

核心異動

以下是 VMO 核心實作需要的廣泛變更。

  • 參照子項會指向與父項相同的頁面容器 (VmCowPages)。對轉送至父項的參照作業而言,這是期望的成效,因為兩者都會針對相同的內部物件執行。
  • 系統會在父項子項清單中追蹤參照,允許在父項上使用 ZX_VMO_ZERO_CHILDREN 信號。
  • 父項 VMO 也會維護包含所有參照子項的新清單。這對特定作業而言,像是將更新傳播至 VM 對應等,而這些作業會在頁面容器外追蹤。
  • 參照也會共用與父項相同的 ContentSizeManager,以便正確更新內容大小,這些大小用於在針對 VMO 建立的串流上讀取及寫入。
  • 參照不會保留父項 VMO。當父項離開後,參照可以繼續存取共用網頁容器。由於參照仍指向該容器,因此該容器將持續運作。參照子項會重新歸類至祖系 (如有),如同現有子項類型的情況。系統會將父項的參考清單移至其中一個參照,讓 VM 對應更新繼續正常運作。這可確保使用者觀察到的行為與現今配量時的行為一致。

實作

參照可在幾個小型 CL 中進行實作,以便在 VMO 核心內部支援新子項類型,然後透過 zx_vmo_create_child() 系統呼叫公開新的類型標記。

建立時,新的 ZX_RIGHT_RESIZE 會新增至可調整大小的 VMO 預設權限組合中。因此,在 zx_vmo_set_size() 中強制執行右側程序,不應導致現有使用者因可調整大小的 VMO 而中斷。我們可以從要求 ZX_RIGHT_WRITEZX_RIGHT_RESIZE 著手,以簡單的方式開始。然後執行稽核,找出會移除 ZX_RIGHT_WRITE 以防止調整大小的現有案例,並改為移除 ZX_RIGHT_RESIZE,或除了 ZX_RIGHT_WRITE 以外。日後,zx_vmo_set_size() 只能檢查 ZX_RIGHT_RESIZE

效能

對參照作業的作業就像直接在父項 VMO 上執行一樣。而在核心中共用同一個內部頁面容器,就能達到這個目的。因此,使用參照而非原始 VMO,應該不會對大多數作業造成任何可觀察的效能影響。系統會寫入 VM Microbenchmark,以驗證這項資訊。

安全性考量

對參照子項執行的所有作業都可以在父項 VMO 上執行,建立參照所需的控制代碼。參照將只取代原始 VMO 的特定用法,因此不用參照也能執行這些作業。

測試

將為參考子項新增核心單元測試和核心測試。

說明文件

zx_vmo_create_child() Syscall 說明文件將更新為 ZX_VMO_CHILD_REFERENCE。您必須更新其他 VMO 系統呼叫的說明文件,在適用情況下加入 ZX_RIGHT_RESIZE

缺點、替代方案和未知

計數控點

另一個替代方案是導入一般的計數配置,在只剩一個控點時,在物件上啟用信號。不過,VMO 控點無法準確呈現未解決的參照數量。您可透過 VM 對應和串流保留 VMO 的參照,而不必保留用於建立 VMO 的控制代碼。我們也必須將 VM 對應、串流,以及日後可能保留 VMO 參照的任何新物件納入考量。這很快就會變得複雜,並未擴充。此外,帳號代碼本質本身即有不良行為,而且除了偵錯外,我們不建議將其用於其他用途。

參照子項方法較能擷取檔案系統和用戶端之間的關係,而這種做法其實是階層式。檔案系統對 VMO 的參照可以視為主要參照,而傳送至用戶端的所有其他參照則是次要參照。父項和子項關係代表這一點。另一方面,帳號代碼具對稱性;在此情況下,我們不僅關心還有一個參照,還希望要將剩餘的參照做為檔案系統保留的參照。

參照權杖

我們可以獲取,檔案系統除了 VMO 或串流之外,也可以發送新的參照權杖物件。這可以是核心提供的新物件,或檔案系統實作的項目。但是,這需要變更檔案系統 API 介面,以便支援傳遞可能不適用的新參照權杖。參照子項可與 VMO 交互使用,因此在保留現有的檔案系統 API 時,會更容易支援這些子項。此外,在 VMO 以外採用參照計數的外部概念也會容易遭到錯誤,因為這樣可能會意外捨棄權杖。

調整切片大小

參照子項與配量的唯一主要方式是調整大小的功能。因此,可以改為在配量的結構定義中定義調整大小的語意,而非建立新的 VMO 子項類型。然而,Slice 可以橫跨父項中的子範圍,因此重新調整大小的理由會大很多。

舉例來說,請考慮將切片大小調整為大於其建立大小的情況。如果配量現在能找出先前看不到的上層頁面,可能就會感到驚訝。另一方面,切片不會直接擁有任何頁面,因此如果是在延伸範圍內為零個網頁建立分支,就會發生問題。如果父項放大到更大,也會發生類似問題。由於激勵用途需要調整父項和子項之間的大小,因此您也必須調整所有配量的大小,這也可能導致意外情況發生。

調整右側大小

VMO 大小調整功能目前是由 ZX_RIGHT_WRITE 控管。日後有獨立的 ZX_RIGHT_RESIZE 時,將能提供更嚴格的違規處置機會。例如,可讓使用者建立無法調整大小的 VMO 控制代碼來與用戶端共用。目前無法建立這類 VMO 控制代碼;可寫入的 VMO 控制代碼也可以調整大小 (如果 VMO 是可調整大小)。

先前的圖片和參考資料

zx_vmo_create_child()

zx_vmar_map()

zx_stream_create()