Linux は、保存されたデータとライブなカーネル状態の両方にファイルシステムインターフェイスを使用します。Virtual Filesystem Switch (VFS) は、共通のシステムコールを通じてそれらのオブジェクトにアクセスできるようにします。一方、procfs や sysfs などの擬似ファイルシステムは、カーネルオブジェクトから内容を生成します。似たパス構文であることは、擬似ファイルにディスクファイルの永続性や I/O セマンティクスを与えません。
カーネル抽象化としての VFS #
VFS は open、read、write、stat、mount などの操作の背後にあるカーネル層です。共通のオブジェクト型を通じて、マウントされたファイルシステムを表現します。
- スーパーブロックはファイルシステムのインスタンスを表し、マウントはそのインスタンスをマウント名前空間内の場所に取り付ける。
- inode はオブジェクトとそのメタデータを表す。
- dentry は名前を inode に関連付け、パス名検索に参加する。
- file はオープンされたインスタンスとその現在位置を表す。
- address space はキャッシュ可能なファイル内容をページキャッシュに接続する。
ファイルシステム実装は、関連するオブジェクトに操作テーブルを提供します。ext4 は読み取りを永続ブロックにマップし、NFS はネットワーク要求を発行し、procfs はカーネル構造体を整形できます。呼び出し元が受け取るのはファイルディスクリプターであり、同じシステムコール境界を使用します。
したがって「仮想ファイルシステム」は曖昧です。VFS は抽象化層を指し、擬似ファイルシステムは、オブジェクトがストレージボリューム上の永続ファイルに対応しないファイルシステム実装を指します。tmpfs もメモリを基盤としますが、通常の可変ファイルセマンティクスと、マウントごとに異なるデータを提供します。procfs と sysfs は、目的に合わせたカーネルインターフェイスを公開します。
Procfs のプロセスビューとシステムビュー #
Procfs は通常 /proc にマウントされます。数値ディレクトリはプロセスを公開し、数値以外のエントリはシステム全体の状態と制御インターフェイスを公開します。
/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 を、パス名でキャッシュされた 1 つのグローバルディレクトリツリーとしてモデル化しないでください。同じパスでも、呼び出し元、名前空間、資格情報、時点が異なれば異なる情報に解決される可能性があります。終了したプロセスへのオープンディスクリプターが、同じ 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 に値を出力させるか、1 つの書き込みバッファーを store に渡します。属性には 1 つの ASCII 値、または同じ型の値の配列を含めるべきです。単純なテキスト形式は検査可能で、場当たり的な構造化プロトコルの埋め込みを避けられるためです。この規約に従えないデータにはバイナリ属性が存在し、別のコールバックを持ちます。
テキストファイルを ABI エンドポイントとして扱う #
テキストだから非公式という意味ではありません。文書化された procfs または sysfs ファイルは、ファイル固有の構文を持つユーザー空間 ABI です。
- 完全な値を読み取り、ABI 文書で保証されている形式だけを解析する。
- 通常のテキスト属性を書き込むときは、想定される改行を含める。
- 文書化されていない空白、列位置、ディレクトリ順序、テスト専用インターフェイスの存在に依存しない。
- 書き込みエラーと短い書き込みを確認する。
openが成功しても、提案した値が受け入れられるとは限らない。
モードビットとファイル権限はアクセス制御層の 1 つにすぎません。ケーパビリティチェック、所有権、名前空間、ロックダウンポリシー、Linux Security Module が操作を拒否する場合があります。書き込みはライブなデバイスまたはドライバー状態を変更することが多いため、world-writable の sysfs 属性は意図的に推奨されません。
カーネルの Documentation/ABI ツリーは、インターフェイスを stable、testing、obsolete、removed に分類します。testing 属性に依存するソフトウェアは、stable なものを使用するソフトウェアとは異なる互換性の約束を受け入れます。機能検出では文書化されたパスを確認して ENOENT を処理します。カーネルバージョンの比較では、ベンダーのバックポートと設定の選択を考慮できません。
読み取りはトランザクションではなくスナップショット #
多くの擬似ファイルは読み取り時に生成されます。カーネル状態は、ファイルを開いてから読み取り解析するまでの間や、関連する 2 つのファイルの読み取り間で変化する可能性があります。1 つの大きな procfs レポートであっても、わずかに異なる時点で観測されたフィールドを要約する場合があります。sysfs 属性をオフセット 0 に巻き戻すと、show コールバックが再度呼び出され、新しい値が返る可能性があります。
したがって、特定の ABI が保証しない限り、複数の読み取りはアトミックなシステムスナップショットを提供しません。堅牢な利用側は次を行うべきです。
- 小さな属性には 1 回の読み取り操作または読み取りループを使用する。
ENOENT、ENODEV、または関連するエラーでプロセスやデバイスが消えることを許容する。- 以前に読み取った状態に対して操作するときは、識別子を再度検証する。
- オブジェクト間の一貫性が必要な場合は、専用のトランザクション API を使用する。
一部の sysfs 属性は、サブシステムが sysfs 通知機構を呼び出すときに poll/select 通知をサポートします。その通知は属性ごとのオプトインであり、/sys 以下のすべてのファイルの性質ではありません。利用側は通常、イベント後に再オープンするかオフセット 0 にシークして再読み取りします。Procfs エントリにも同様にファイル固有のポーリングセマンティクスがあります。
擬似ファイルは永続ストレージではない #
Procfs と sysfs では、通常のファイルに関するいくつかの仮定が失敗します。
- 報告されるサイズが 0 でも、
readがデータを返す場合がある。 mmap、任意のシーク、追加モード、部分的な書き込みがサポートされない場合がある。- プロセスやデバイスの変化に応じて、ディレクトリエントリが現れたり消えたりする。
- 成功した書き込みが取得可能なバイトを保存するのではなく、ハードウェア動作を起動する場合がある。
- シャットダウン時にデータは消え、次のカーネルの状態から再構成される。
再起動後も存続する必要がある設定は、起動ロジックが必要なカーネルインターフェイスへ意図的に書き込む永続設定システムに置きます。/proc または /sys をコピーしてもカーネル状態をバックアップできず、コピーしたファイルを復元してもプロセスやデバイスを再作成できません。
コメント
GitHub で閲覧・コメントする(投稿にはログインが必要です)