為提供 Fuchsia 檔案系統存取權的端對端樣貌, 就會深入介紹執行特定動作時使用的每一層 就像開啟檔案一樣簡單請特別注意,這些圖層都位於 userspace;即使與檔案系統伺服器和驅動程式互動 只用來在元件之間傳遞訊息
通話對象:
open(“foobar”);
存取要求的位置
標準程式庫:開啟位置的定義
「開啟」呼叫是由標準程式庫提供的函式。適用對象
C/C++ 程式,這通常會在 unistd.h
中宣告,且其具備
libfdio 中的備份定義。
就 Go 程式而言,Go 中會提供相同 (但截然不同的) 實作項目
標準程式庫。開發人員可以選擇針對每種語言和執行階段選擇應用程式 ID
在單體式核心中,open
是系統周圍的輕量墊片
呼叫,因此核心可能會處理路徑剖析、重新導向等作業。
因此核心需要根據外部 IP 位址
調整資源存取權
有關來電者的知識不過,Zircon 核心
並未刻意設定
以及這類系統呼叫而應改為透過管道存取檔案系統 --
程序初始化時,會提供「命名空間」。
計算的是「絕對路徑」資料表->「把手」對應。所有已存取的路徑
處理程序中,透過此命名空間向要求開啟
對應。
但在本例中,要求開啟「foobar」(相對路徑) 因此系統可能無法透過代表 目前的工作目錄 (本身以絕對路徑表示) 和帳號代碼)。
標準程式庫負責處理帳號代碼 (或多個帳號代碼) 並使它們看起來像檔案描述元因此,「 「描述元表格」是存在於用戶端程序中 ( 選擇使用自訂執行階段時,他們只看得到 帳號代碼,可視需要選擇「檔案描述元」包裝)。
但這引發了一個問題:針對檔案、通訊端, 管道等等,標準程式庫要如何製作所有這些資源 功能是否一樣呢?客戶如何得知要傳送哪些訊息 可以使用這些控制代碼嗎?
Fdio
名為 fdio 的程式庫
負責提供整合式介面給各種資源
檔案、通訊端、服務、管道等這個資料層會定義
可能會用到的函式,例如讀取、寫入、開啟、關閉、跳轉等
由各種通訊協定支援的檔案描述元。每個支援的通訊協定都是
負責提供用戶端程式碼
互動。例如,通訊端為用戶端提供多個控制代碼;One
和控制層一樣相較之下,「檔案」
通常只會使用一個管道來控管資料和資料 (除非進行額外工作,否則
才能要求進行記憶體對應)。雖然通訊端和檔案可能
接收對 open
或 write
的呼叫,因此需要解讀這些指令
有差異。
為方便說明,在本文中,我們會以主要通訊協定 檔案系統用戶端所用的 ID:FIDL。
FIDL
呼叫 open("foo")
的程式會呼叫標準程式庫。
找到與目前工作目錄相對應的「fdio」物件,
則需要向遠端伺服器傳送要求,才能「請打開 foo」我們要怎麼做
如何完成?這項計畫提供下列工具:
- 一或多個代表 CWD 連線的處理常式
- zx_channel_write: 可傳送位元組和處理 (透過管道) 的系統呼叫
- zx_channel_read: 可接收位元組和處理 (透過管道) 的系統呼叫
- zx_object_wait_one: 可等待帳號代碼可讀取 / 寫入的系統呼叫
用戶端可以利用這些基元,撰寫訊息至檔案系統伺服器 CWD 控點上,伺服器可以讀取並回應 回信給客戶「成功」或「失敗訊息」。伺服器的同時 釐清該開放哪些元素 因為在嘗試讀取狀態訊息之前,可能不會選擇等候。
用戶端和伺服器必須就這些協議 傳送或接收訊息時,N 個位元組和 N 會處理:如果有 否則可能遭到捨棄 (更糟的是, 或非預期的行為)。此外,如果這個通訊協定允許用戶端 且完全掌控伺服器,通訊層就會成熟 加以利用
FIDL IO 通訊協定
是指這些位元組和處理代碼的實際意義
會發生這種情形這個通訊協定會說明
「預計的帳號代碼數量」、「列舉作業」和「資料」。在這個範例中
open("foo")
會建立 Open
訊息並設定 FIDL 的「資料」欄位
訊息傳送給「foo」字串此外,如果將任何旗標傳遞至
開啟 (例如 O_RDONLY, O_RDWR, O_CREAT
等) 就會放在
FIDL 結構的「arg」欄位。不過,如果作業已變更
(例如 write
),則這則訊息的解讀方式會是
變造。
這層須確切的位元組協議很重要,因為這能讓通訊 相差甚遠的執行階段:瞭解 FIDL 可以 在 C、C++、Go、Rust 和 Dart 程式等之間輕鬆通訊 公開透明。
libfidl 包含 C/C++ 的用戶端和伺服器端程式碼 並負責自動驗證輸入內容 兩端的輸出內容
就 open
作業而言,FIDL 通訊協定會預期
用戶端會建立一個管道,並將一端 (做為控制代碼) 傳遞至伺服器。一次
交易完成後,這個管道可能會用來做為
與開啟的檔案進行通訊
與「CWD」控制代碼通訊
設計通訊協定,讓 FIDL 用戶端提供控點,而非伺服器, 這種通訊更適合引導線FIDL 物件的存取權可能 非同步;可將要求傳送至 FIDL 物件的要求,然後再傳送 會有什麼影響?這種行為十分重要 功能 代管者 元件 - 元件 (預設為) 延遲啟動 當能力要求 (透過公開呼叫完成) 時。而不是 封鎖元件,並在元件完成啟動程序並開始 這個模型可讓用戶端開始傳送要求 然後,系統會在元件就緒時做出回應。詳情請見 開啟通訊協定的生命週期。 能力轉送
總結來說,「開放式」呼叫會通過標準程式庫,以
「CWD」fdio 物件,用來將要求轉換成 FIDL 訊息,
則會透過 zx_channel_write
系統呼叫傳送至伺服器。客戶可以
您可以選擇使用 zx_object_wait_one
等待伺服器回應,也可以繼續操作
以非同步的方式處理資料不論是哪一種方式,管道都已經建立完成
其中一個端在用戶端運作,另一端會傳送至
「server」。
檔案系統:伺服器端
調度
客戶端發送訊息之後 都存在於管道的伺服器端等待讀取。伺服器是 只要「握手握在管道另一端的帳號代碼」 就能識別出這個帳號代碼 可能會與用戶端處於相同 (或不同) 程序,因此使用相同的 (或 執行階段不同,並以相同 (或不同的) 執行階段寫入 語言) 而非用戶端。只要使用商定的傳輸格式, 處理序間依附元件的瓶頸,在於該通訊層 而非管道
在未來某個時間點,這個 CWD 帳號的伺服器端將需要 讀取用戶端傳輸的訊息。這項程序不會自動進行 -- 伺服器需要刻意等待 接收控制代碼,在本例中為「目前工作目錄」 控制代碼。開啟伺服器物件 (檔案、目錄、服務等) 時, 其控制方式是透過伺服器端的 Zircon 通訊埠註冊, 其基礎控制代碼設為「可讀取」 (表示郵件已送達) 或 已關閉 (代表使用者永遠不會再收到訊息)。這個物件 將傳入要求分派到適當帳號代碼,稱為「調度工具」。 負責將傳入訊息重新導向至回呼函式。 以及先前提供的「iostate」代表開放式連線
針對使用 libfs 的 C++ 檔案系統,系統會呼叫這個回呼函式
vfs_handler
,然後會接收下列幾項重要資訊:
- FIDL 訊息,由用戶端提供 (或人為建構) 如果帳號代碼關閉,伺服器將顯示為「關閉」訊息)
- 代表目前與帳號代碼連線的 I/O 狀態 (以 之前提到的「iostate」欄位)
vfs_handler
可以解讀 I/O 狀態來推斷其他資訊:
- 檔案內的搜尋指標 (如果已使用 readdir,就會位於 目錄中)
- 用來開啟基礎資源的旗標
- 代表基礎物件的 Vnode 檔案 (可在兩個節點之間共用) 多個用戶端或多個檔案描述元)
這項處理常式功能可以與
「switch/case」表格,將 FIDL 訊息重新導向至適當的函式
則視用戶端提供的「Operation」欄位而定在未解決的情況下,
系統會留意 Open
序數做為作業,因此 (1) 預期的是控制代碼,
(2)「data」欄位 (「foo」) 會被解讀為路徑。
VFS 層
在 Fuchsia 中,「VFS 層」是與檔案系統無關的程式碼程式庫, 可能會分派及解讀伺服器端訊息,以及在 基礎檔案系統值得一提的是 選用) 表示檔案系統伺服器不想連結至此程式庫。 沒有義務使用檔案系統伺服器 只瞭解 FIDL 線路格式。因此 相同語言中的任意數量的「VFS」導入作業。目前有這些 實作:
- In-tree C++ VFS:供 Fuchsia 的「main」使用檔案系統的 Minf blobfs。這個平台目前具備所有 VFS 導入作業中最多的功能,但也可能是 難以使用
- In-tree Rust VFS:部分 Rust 檔案系統會使用這項目,包括 Fat32 實作練習此為更新版本,目前提供的功能比 C++ 少 。
- SDK C++ VFS:簡化版的「樹狀結構內」版本C++ 版本 這項工具專為 SDK 使用者設計最常用於較簡單的用途,例如服務探索。
VFS 層會定義可轉送至 基礎檔案系統,包含:
- 讀取/寫入 Vnode
- 從父項 Vnode 查詢/建立/取消連結 Vnode (按照名稱)
- 依名稱重新命名/連結 Vnode
- 其他應用程式
實作檔案系統 (假設開發人員想使用共用 VFS) 只需定義實作這個介面與連結的 Vnode 即可 與 VFS 層相比的結果即可啟用「步行路徑」和 可以輕鬆「掛接檔案系統」,而且幾乎不會出現重複的程式碼。在 要維持各檔案系統通用,VFS 層沒有明確的概念 檔案系統使用的基礎儲存空間:檔案系統可能需要存取權 封鎖裝置、網路或記憶體來儲存資料,但 VFS 層 只處理處理路徑、資料的位元組陣列和 V 節點的介面。
路徑步行
為開啟伺服器端資源,系統會提供伺服器一些起點
(由呼叫的控制代碼表示) 和字串路徑。這個路徑會分割成
「/」字元來「查詢」每個元件
提供給基礎檔案系統的回呼。如果查詢成功傳回
並偵測到另一個「/」區段,然後程序會繼續進行,直到
(1) lookup
找不到元件,(2) 路徑處理程序到達最後一個部分
或 (3) lookup
會找出「掛接元件」,
具有附加「remote」控制代碼的 vnode。目前我們會忽略掛接點
但是在檔案系統的相關章節中討論過節點
掛接功能。
假設 lookup
已成功找到「foo」Vnode。檔案系統伺服器
將繼續呼叫 VFS 介面「開啟」,
您可以先使用提供的旗標存取資源,再呼叫「GetHandles」
詢問基礎檔案系統是否還需要其他控制代碼
與 Vnode 互動假設客戶要求 "foo" 物件
同步 (在預設的 POSIX 公開呼叫中即為隱含)
與「foo」互動所需的額外控制代碼已封裝至小型 FIDL 中
說明物件並傳回給用戶端。或是「foo」擁有
無法開啟,系統仍會傳回 FIDL 說明物件,但帶有
將「status」欄位設為錯誤代碼,表示失敗。假設
都能成功開啟檔案伺服器會繼續建立「iostate」物件
「foo」並向調度工具註冊。如此一來,日後對「foo」發出的呼叫
完全由伺服器處理「Foo」已開啟,客戶現在可以
再提出要求
就客戶而言,在「開放式」呼叫開始時, CWD 控制代碼已傳輸至遠端檔案系統。 伺服器由於呼叫是同步的,因此用戶端繼續等候 回應。正確找到伺服器、開啟並初始化後 這個檔案的 I/O 狀態,傳回了「成功」的 FIDL 說明物件。這個 物件便會被用戶端讀取,表示呼叫已完成 此時,用戶端可以建立 fdio 物件 代表「foo」的控制代碼,以檔案中的項目參照 然後將 Fd 傳回給命名為原始「開放」的人員 函式。此外,如果客戶想傳送其他請求 (例如「讀」或「寫」) 到「foo」,就可以直接與 下載至檔案系統伺服器 日後的要求,都必須透過「CWD」轉送
開放式的生命週期:圖表
+----------------+
| Client Program |
+----------------+
| fd: x | fd: y |
| Fdio (FIDL)| Fdio (FIDL)|
+-------------------------+
| '/' Handle | CWD Handle |
+-------------------------+
^ ^
| |
Zircon Channels, speaking FIDL State BEFORE open(‘foo’)
| |
v v
+-------------------------+
| '/' Handle | CWD Handle |
+-------------------------+
| I/O State | I/O State |
+-------------------------+
| Vnode A | Vnode B |
+-------------------------+
| Filesystem Server |
+-------------------+
+----------------+
| Client Program |
+-------------------------+
| fd: x | fd: y |
| Fdio (FIDL)| Fdio (FIDL)|
+-------------------------+
| '/' Handle | CWD Handle | **foo Handle x2**
+-------------------------+
^ ^
| |
Zircon Channels, speaking FIDL Client Creates Channel
| |
v v
+-------------------------+
| '/' Handle | CWD Handle |
+-------------------------+
| I/O State | I/O State |
+-------------------------+
| Vnode A | Vnode B |
+-------------------------+
| Filesystem Server |
+-------------------+
+----------------+
| Client Program |
+-------------------------+
| fd: x | fd: y |
| Fdio (FIDL)| Fdio (FIDL)|
+-------------------------+--------------+
| '/' Handle | CWD Handle | ‘foo’ Handle |
+-------------------------+--------------+
^ ^
| |
Zircon Channels, speaking FIDL Client Sends FIDL message to Server
| | Message includes a ‘foo’ handle
v v (and waits for response)
+-------------------------+
| '/' Handle | CWD Handle |
+-------------------------+
| I/O State | I/O State |
+-------------------------+
| Vnode A | Vnode B |
+-------------------------+
| Filesystem Server |
+-------------------+
+----------------+
| Client Program |
+-------------------------+
| fd: x | fd: y |
| Fdio (FIDL)| Fdio (FIDL)|
+-------------------------+--------------+
| '/' Handle | CWD Handle | ‘foo’ Handle |
+-------------------------+--------------+
^ ^
| |
Zircon Channels, speaking FIDL Server dispatches message to I/O State,
| | Interprets as ‘open’
v v Finds or Creates ‘foo’
+-------------------------+
| '/' Handle | CWD Handle |
+-------------------------+
| I/O State | I/O State |
+-------------------------+-------------+
| Vnode A | Vnode B | Vnode C |
+------------------------------+--------+
| Filesystem Server |
+-------------------+
+----------------+
| Client Program |
+-------------------------+
| fd: x | fd: y |
| Fdio (FIDL)| Fdio (FIDL)|
+-------------------------+--------------+
| '/' Handle | CWD Handle | ‘foo’ Handle |
+-------------------------+--------------+
^ ^ ^
| | |
Zircon Channels, FIDL | Server allocates I/O state for Vnode
| | | Responds to client-provided handle
v v v
+-------------------------+--------------+
| '/' Handle | CWD Handle | ‘foo’ Handle |
+-------------------------+--------------+
| I/O State | I/O State | I/O State |
+-------------------------+--------------+
| Vnode A | Vnode B | Vnode C |
+------------------------------+---------+
| Filesystem Server |
+-------------------+
+----------------+
| Client Program |
+-----------------------------+----------+
| fd: x | fd: y | fd: z |
| Fdio (FIDL)| Fdio (FIDL)| Fdio (FIDL) |
+-------------------------+--------------+
| '/' Handle | CWD Handle | ‘foo’ Handle |
+-------------------------+--------------+
^ ^ ^
| | |
Zircon Channels, speaking FIDL | Client recognizes that ‘foo’ was opened
| | | Allocated Fdio + fd, ‘open’ succeeds.
v v v
+-------------------------+--------------+
| '/' Handle | CWD Handle | ‘foo’ Handle |
+-------------------------+--------------+
| I/O State | I/O State | I/O State |
+-------------------------+--------------+
| Vnode A | Vnode B | Vnode C |
+------------------------------+---------+
| Filesystem Server |
+-------------------+