虛擬檔案系統

最後更新: 2021-04-17 01:39:12 +0800 +0800
原文以英文撰寫。您正在閱讀AI翻譯版本。

Linux 同時使用檔案系統介面處理儲存資料與即時核心狀態。虛擬檔案系統切換(VFS)透過共用系統呼叫讓這些物件可存取,而 procfs 與 sysfs 等虛擬檔案系統則從核心物件產生其內容。相似的路徑語法不會賦予虛擬檔案磁碟檔案的持久性或 I/O 語意。

VFS 作為核心抽象層 #

VFS 是 open、read、write、stat 與 mount 等操作背後的核心層。它透過共用物件型別表示已掛載的檔案系統:

  • superblock 表示檔案系統實例,而掛載點會將該實例附加至某個掛載命名空間中的位置;
  • inode 表示物件及其中繼資料;
  • dentry 將名稱與 inode 關聯,並參與路徑名稱查詢;
  • file 表示已開啟的實例及其目前位置;
  • address space 將可快取檔案內容連接至頁面快取。

檔案系統實作會為相關物件提供操作表。ext4 可以將讀取映射至持久區塊,NFS 可以發出網路請求,而 procfs 可以格式化核心結構。呼叫者仍然會取得檔案描述元,並使用相同的系統呼叫邊界。

因此,「虛擬檔案系統」一詞有歧義。VFS 指抽象層;虛擬檔案系統是其中一種檔案系統實作,其物件不對應儲存磁碟區上的持久檔案。tmpfs 也由記憶體支援,但它提供一般可變檔案語意,且每個掛載點有不同資料。procfs 與 sysfs 則公開專門設計的核心介面。

Procfs 程序與系統檢視 #

Procfs 慣例上掛載於 /proc。數字目錄公開程序,而非數字項目則公開全系統狀態與控制介面:

text
/proc/1234/status      formatted state for process 1234
/proc/1234/fd/         links for its open file descriptors
/proc/self/            the reading process's own proc directory
/proc/meminfo          memory-accounting snapshot
/proc/sys/             sysctl parameters

/proc/<pid> 下的檔案會根據程序憑證、ptrace 存取規則、能力、掛載選項與安全性模組進行檢查。在某個內容中 root 可讀的路徑,不代表非特權程序可以公開存取。

實例、PID 命名空間與掛載命名空間 #

Procfs 輸出受命名空間影響。與 PID 命名空間關聯的 procfs 掛載會顯示該命名空間可見的工作;/proc/self 與 /proc/thread-self 也會相對於呼叫者解析。建立或進入另一個 PID 命名空間的程序,必須使用適當的 procfs 掛載,才能取得相符的程序檢視。

掛載命名空間會獨立控制該 procfs 實例掛載的位置與是否掛載。因此,容器可以在共用相同核心時擁有不同的 /proc 掛載點、唯讀設定與可見性選項。hidepid 等選項會限制對其他使用者程序目錄的存取,而支援的核心可以透過 subset=pid 隱藏與工作無關的頂層項目。

Procfs 不應建模為一個由路徑名稱快取的全域目錄樹。同一路徑對不同呼叫者、命名空間、憑證或時間點可能解析至不同資訊。已死亡程序的開啟描述元不會成為之後重複使用相同 PID 的程序控制代碼。

Sysfs 與驅動程式物件模型 #

Sysfs 慣例上掛載於 /sys,會匯出核心的物件模型。已註冊的 kobject 會在其父項下取得目錄,因此目錄階層表達物件關係並控制生命週期。Linux 裝置模型在該基礎結構上建立裝置、驅動程式、匯流排與類別:

  • /sys/devices 顯示裝置的實體或韌體探索拓撲。
  • /sys/bus/<bus>/devices 連結至參與匯流排的裝置。
  • /sys/bus/<bus>/drivers 顯示已註冊的驅動程式與其繫結。
  • /sys/class/<class> 依功能分組裝置,例如網路或區塊裝置。

/sys/devices 外的許多項目是相同底層裝置物件的符號連結檢視。指令碼應解析文件化的屬性,而不是從方便的類別路徑推論實體拓撲。

Sysfs attribute 將小型檔案連接至子系統定義的 show 與 store 回呼。核心會配置頁面大小的緩衝區,要求 show 產生值,或將一個寫入緩衝區傳給 store。屬性應包含一個 ASCII 值,或相同型別的值陣列,因為簡單文字形式容易檢查,也能避免嵌入臨時結構化協定。無法遵循該慣例的資料可使用二進位屬性,二進位屬性具有分開的回呼。

將文字檔視為 ABI 端點 #

文字不代表非正式。文件化的 procfs 或 sysfs 檔案是具有檔案特定語法的使用者空間 ABI:

  • 讀取完整值,並只剖析其 ABI 文件承諾的形式。
  • 寫入慣例文字屬性時,包含預期的換行。
  • 不要依賴未文件化的空白、欄位位置、目錄順序或僅供測試的介面是否存在。
  • 檢查寫入錯誤與短寫入;成功 open 不代表提出的值會被接受。

模式位元與檔案權限只是其中一層存取控制。能力、所有權、命名空間、鎖定原則與 Linux Security Module 都可以拒絕操作。刻意不鼓勵可由所有人寫入的 sysfs 屬性,因為寫入通常會變更即時裝置或驅動程式狀態。

核心的 Documentation/ABI 樹會將介面分類為 stable、testing、obsolete 或 removed。繫結至 testing 屬性的軟體,接受的相容性承諾與使用 stable 屬性的軟體不同。功能偵測應檢查文件化路徑,並以 ENOENT 處理不存在;核心版本比較無法涵蓋供應商回移與設定選擇。

讀取是快照,而非交易 #

許多虛擬檔案會在讀取時產生。核心狀態可能在開啟、讀取與剖析檔案之間變更,也可能在讀取兩個相關檔案之間變更。即使是一份大型 procfs 報告,也可能總結在略有不同時間觀察的欄位。將 sysfs 屬性倒回 offset 零可能再次呼叫其 show 回呼並回傳新值。

因此,除非特定 ABI 保證,否則多次讀取不會提供原子系統快照。健全的取用者應:

  1. 對小型屬性使用一次讀取操作或讀取迴圈;
  2. 容忍程序與裝置以 ENOENT、ENODEV 或相關錯誤消失;
  3. 在對先前讀取的狀態採取行動時,再次驗證識別碼;
  4. 一致性跨越多個物件時,使用專用交易 API。

當子系統呼叫 sysfs 通知機制時,某些 sysfs 屬性支援 poll/select 通知。這種通知是每個屬性選擇性提供的功能,不是 /sys 下每個檔案的特性。一般而言,取用者會在事件後重新開啟,或 seek 至 offset 零並重新讀取。Procfs 項目同樣具有檔案特定的輪詢語意。

虛擬檔案不是持久儲存 #

數個一般檔案的假設不適用於 procfs 與 sysfs:

  • 回報大小可能為零,即使 read 會回傳資料;
  • mmap、任意 seek、附加模式或部分寫入可能不受支援;
  • 程序與裝置變更時,目錄項目可能出現或消失;
  • 成功寫入可能觸發硬體活動,而不是儲存可取回的位元組;
  • 關機時資料會消失,並從下一個核心的狀態重建。

必須在重新開機後保留的設定,應放在持久設定系統中,其啟動邏輯會刻意寫入所需的核心介面。複製 /proc 或 /sys 無法備份核心狀態,而還原複製的檔案也無法重新建立程序或裝置。

參考資料 #

評論

在 GitHub 上閱讀或評論(發表評論需要登入)