RFC-0204:VMO 參照子項 | |
---|---|
狀態 | 已接受 |
區域 |
|
說明 | 用於追蹤參照的 VMO 子項類型。 |
問題 | |
變更 | |
作者 | |
審查人員 | |
提交日期 (年/月) | 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 本機副本的參照計數策略適用於不可變更的檔案系統,但在套用至可變動的檔案系統時 (例如 fxfs
或 minfs
) 會中斷。在可變動的檔案系統中,對用戶端檔案參照所做的任何變更都應反映在原始檔案中。換句話說,在 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 的參照,因此 offset
和 length
參數並不重要,而且兩者都必須設為 0
。參照子項一律會參照父項 VMO 的完整類型。另一個做法是讓呼叫端將 offset
指定為 0
和 length
做為 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_RESIZE
與 ZX_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_WRITE
和 ZX_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 是可調整大小)。