Linuxの仮想ファイルシステムの詳細な説明

Linuxの仮想ファイルシステムの詳細な説明

ファイルシステムとは何ですか? Linux の初期の貢献者であり著者でもある Robert Love 氏によると、「ファイル システムとは、特定の構造に従ったデータの階層的ストレージです。」ただし、この説明は VFAT (仮想ファイル アロケーション テーブル)、Git、Cassandra (NoSQL データベース) にも適用されます。では、ファイルシステムをどのように区別するのでしょうか?

[[266711]]

ファイルシステムの基本概念

Linux カーネルでは、ファイル システムがエンティティであること、永続オブジェクトに対して open()、read()、および write() メソッドを実装していること、およびこれらのエンティティに関連付けられた名前を持っていることが求められます。オブジェクト指向プログラミングの観点から見ると、カーネルは一般的なファイルシステムを抽象的なインターフェースと見なします。これら 3 つの関数は「仮想」であり、デフォルトの定義はありません。したがって、カーネルのデフォルトのファイル システム実装は、仮想ファイル システム (VFS) と呼ばれます。


このコンソール セッションに示されているように、open()、read()、write() が実行できる場合は、それはファイルです。

VFS は、Unix 系システムにおける有名な「すべてがファイルである」という概念の基礎です。どれほど奇妙かを確認するために、上記の小さなデモでは、キャラクタ デバイス /dev/console が実際にどのように動作するかを示しています。この図は、仮想テレタイプ コンソール (tty) 上の対話型 Bash セッションを示しています。仮想コンソール デバイスに文字列を送信すると、その文字列が仮想画面に表示されます。そして、VFS にはさらに奇妙な特性があります。たとえば、その中で対処することができます。

ext4、NFS、/proc など、私たちがよく知っているファイル システムはすべて、file_operations と呼ばれる C 言語データ構造で 3 つの主要な関数の定義を提供します。さらに、個々のファイル システムは、使い慣れたオブジェクト指向の方法で VFS 機能を拡張およびオーバーライドします。 Robert Love 氏が指摘しているように、VFS 抽象化により、Linux ユーザーは、内部データ形式を気にすることなく、外部オペレーティング システムや抽象エンティティ (パイプなど) に (またはそこから) ファイルを簡単にコピーできるようになります。ユーザー空間側では、システム コールを通じて、プロセスはファイル システム メソッドの 1 つである read() を使用してファイルからカーネルのデータ構造にデータをコピーし、別のファイル システム メソッドである write() を使用してデータを出力できます。

VFS 基本タイプに属する関数定義自体はカーネル ソース コードの fs/*.c ファイルにありますが、fs/ のサブディレクトリには特定のファイル システムが含まれています。カーネルには、cgroups、/dev、tmpfs などのファイルシステムのようなエンティティも含まれています。これらはブート プロセスの初期段階で必要となるため、カーネルの init/ サブディレクトリで定義されます。 cgroup、/dev、tmpfs は、file_operations の 3 つの主要関数を呼び出さず、メモリを直接読み書きすることに注意してください。

次の図は、ユーザー空間が Linux システムに一般的にマウントされるさまざまな種類のファイル システムにアクセスする方法を大まかに示しています。この図には示されていないパイプ、dmesg、POSIX クロックなどの構造も struct file_operations を実装しており、それらのアクセスも VFS レイヤーを経由します。


ユーザー空間がさまざまな種類のファイルシステムにアクセスする方法

VFS は、システム コールと特定のファイル操作 (ext4 や procfs など) の実装の間に位置する「シム レイヤー」です。その後、file_operations 関数はデバイス固有のドライバーまたはメモリ アクセサーと通信できるようになります。 tmpfs、devtmpfs、cgroup は file_operations を使用せず、メモリに直接アクセスします。

VFS が存在すると、基本的なファイル システム関連のメソッドを各ファイル システム タイプごとに再実装する必要がないため、コードの再利用が促進されます。コードの再利用は、広く受け入れられているソフトウェア エンジニアリングのベスト プラクティスです。残念なことに、再利用されたコードによって重大なバグが発生した場合、共通メソッドを継承するすべての実装が影響を受けます。

/tmp: ちょっとしたヒント

システムにどのような VFS が存在するかを確認する簡単な方法は、mount | と入力することです。 grep -v sd | grep -v :/ を実行すると、ほとんどのマシンで、ディスク上に存在せず、NFS でもないマウントされたファイル システムがすべて一覧表示されます。リストされている VFS マウントの 1 つは /tmp である必要がありますか?

/tmp を物理ストレージ デバイスに置くのは無謀だということは誰もが知っています。画像: https://tinyurl.com/ybomxyfo

ストレージデバイスに /tmp を残しておくのはなぜ望ましくないのでしょうか? /tmp 内のファイルは一時的なもの (!) であり、ストレージ デバイスはメモリよりも遅いため、tmpfs ファイル システムが作成されました。さらに、物理デバイスは、頻繁な書き込みにより、メモリよりも摩耗の影響を受けやすくなります。 ***、/tmp 内のファイルには機密情報が含まれている可能性があるため、再起動のたびにそれらが消えるようにする機能があります。

残念ながら、一部の Linux ディストリビューションのインストール スクリプトでは、依然としてデフォルトでストレージ デバイスに /tmp が作成されます。システムにこのようなことが起きても、絶望しないでください。問題を解決するには、常に優れた Arch Wiki の簡単な指示に従ってください。ただし、tmpfs に割り当てられたメモリは他の目的には使用できなくなることに注意してください。つまり、大きなファイルを含む大きな tmpfs により、システムのメモリが不足し、クラッシュする可能性があります。

もう 1 つのヒント: /etc/fstab ファイルを編集するときは、必ず改行文字で終了してください。そうしないと、システムが起動しません。 (どうして私が知っているか推測してください。)

/proc と /sys

/tmp の他に、ほとんどの Linux ユーザーが最もよく知っている VFS は /proc と /sys です。 (/dev は共有メモリに依存しており、file_operations 構造がありません)。なぜ2つなのですか?詳しく見てみましょう。

procfs は、カーネルとそれが制御するプロセスの瞬間的な状態のスナップショットをユーザー空間に提供します。 /proc では、カーネルは割り込み、仮想メモリ、スケジューラなど、カーネルが提供する機能に関する情報を公開します。さらに、/proc/sys は、sysctl コマンドで構成できる設定が保存され、ユーザー空間からアクセスできる場所です。個々のプロセスのステータスと統計は/proc/に保存されます。カタログにレポートします。


/proc/meminfo は空のファイルですが、それでも貴重な情報が含まれています。

/proc ファイルの動作は、VFS がディスク上のファイル システムと異なる可能性があることを示しています。一方、/proc/meminfo には、free コマンドで表示できる情報が含まれています。一方、まだ空いています!どうしてこんなことが起こるのでしょうか?この状況は、コーネル大学の物理学者 N. デビッド・マーミンが 1985 年に書いた「もし誰も月を見なかったら何が起こるのか? 現実と量子論」と題する論文を彷彿とさせる。実際のところ、プロセスが /proc からデータを要求したときにカーネルはメモリに関する統計情報を収集しますが、誰もそれを見ていない場合、/proc 内のファイルには実際には何も含まれていません。マーミンはこう述べています。「一般に、測定によって測定対象の特性の既存の値が明らかになるわけではないというのが、量子力学の基本的な理論です。」 (月に関する質問の答えは練習問題として残しておきます。)

/proc 内のファイルは、プロセスがアクセスしていない場合、空になります。 (ソース)

procfs の空のファイルは、そこに存在する情報が動的であるため、意味があります。 sysfs の場合は状況が異なります。 /proc と /sys 内の空ではないファイルの数を比較してみましょう。


procfs には、エクスポートされたカーネル構成という空でないファイルが 1 つだけあります。これは、起動ごとに 1 回だけ生成する必要があるため、例外です。一方、/sys には大きなファイルが多数あり、そのほとんどは 1 ページのメモリで構成されています。通常、sysfs ファイルには、/proc/meminfo などのファイルを読み取ることによって生成される情報テーブルとは対照的に、数字または文字列のみが含まれます。

sysfs の目的は、「kobjects」と呼ばれるカーネル オブジェクトの読み取り可能および書き込み可能な属性をユーザー空間に公開することです。 kobject の唯一の目的は参照カウントです。kobject への最後の参照が削除されると、システムはそれに関連付けられたリソースを再利用します。ただし、/sys はカーネルの有名な「ユーザー空間への安定した ABI」を構成しており、その内容のほとんどは、いかなる状況でも誰も「破壊」することはできません。しかし、これは、揮発性オブジェクトの参照カウントとは異なり、sysfs 内のファイルが静的であることを意味するものではありません。

カーネルの安定した ABI は、/sys に実際にある内容ではなく、ある時点で /sys に何が存在する可能性があるかを制限します。 sysfs 内のファイルの権限を一覧表示すると、デバイス、モジュール、ファイル システムなどの構成可能および調整可能なパラメータを設定または読み取る方法を理解するのに役立ちます。論理的には、カーネルのドキュメントに明示的に記載されていなくても、procfs もカーネルの安定した ABI の一部になります。


sysfs 内のファイルは、エンティティのすべての属性を正確に記述し、読み取り可能、書き込み可能、​​またはその両方にすることができます。ファイル内の「0」は、SSD 非リムーバブル ストレージ デバイスを示します。

eBPF と bcc ツールを使用して VFS の内部を覗く

カーネルが sysfs ファイルを管理する方法を理解する最も簡単な方法は、実際に動作している様子を見ることです。また、ARM64 または x86_64 でこれを確認する最も簡単な方法は、eBPF を使用することです。 eBPF (拡張 Berkeley Packet Filter) は、カーネル内で実行され、特権ユーザーがコマンド ラインからクエリを実行できる仮想マシンで構成されています。カーネルのソースコードは、カーネルが何ができるかを読者に伝えます。起動したシステムで eBPF ツールを実行すると、カーネルが実際に何を実行するかがわかります。

幸いなことに、主要な Linux ディストリビューションのパッケージで利用可能で、Brendan Gregg によって十分に文書化されている bcc ツールを使用して eBPF を開始するのは簡単です。 bcc ツールは、小さな C スニペットが埋め込まれた Python スクリプトであるため、どちらかの言語に精通している人なら誰でも簡単に変更できます。現在、bcc/tools には 80 個の Python スクリプトが存在するため、システム管理者や開発者が自分のニーズに合った既存のスクリプトを見つけることができる可能性が非常に高くなります。

実行中のシステムで VFS がどの程度うまく機能しているかを把握するには、単純な vfscount または vfsstat スクリプトを使用してみてください。これらのスクリプトでは、毎秒何十回もの vfs_open() とその関連コンポーネントの呼び出しが表示されます。


vfsstat.py は、VFS 関数の呼び出しを単純にカウントする C スニペットが埋め込まれた Python スクリプトです。

もう少し単純な例として、実行中のシステムに USB スティックを挿入したときに sysfs で何が起こるかを見てみましょう。


eBPF を使用して、USB スティックを挿入したときに /sys で何が起こるかを確認します。簡単な例と複雑な例があります。

上記の最初の簡単な例では、trace.py bcc ツール スクリプトは、sysfs_create_files() コマンドが実行されるたびにメッセージを出力します。 USB スティック挿入イベントに応答して、 sysfs_create_files() が kworker スレッドによって開始されたことがわかりましたが、どのようなファイルが作成されたのでしょうか?この 2 番目の例は、eBPF の威力を示しています。ここで、trace.py はカーネル バックトレース (-K オプション) と sysfs_create_files() によって作成されたファイルの名前を出力しています。一重引用符で囲まれたコード スニペットは、簡単に認識できる書式文字列を含む C ソース コードであり、提供されている Python スクリプトは、LLVM Just-in-Time コンパイラ (JIT) を導入して、カーネル仮想マシン内でコンパイルおよび実行します。フォーマット文字列が引数の 1 つを参照できるように、完全な sysfs_create_files() 関数シグネチャを 2 番目のコマンドで再現する必要があります。この C スニペットにエラーがあると、認識可能な C コンパイラ エラーが発生します。たとえば、-I パラメータを省略すると、結果は「BPF テキストをコンパイルできません」になります。 C または Python に精通している開発者は、bcc ツールを簡単に拡張および変更できます。

USB スティックを挿入した後、カーネル バックトレースにより、PID 7711 が sysfs に events というファイルを作成した kworker スレッドであることが示されました。 sysfs_remove_files() を使用した対応する呼び出しは、USB スティックを取り外すとイベント ファイルが削除されることを示しており、これは参照カウントの考え方と一致しています。 USB スティック挿入中に eBPF で sysfs_create_link() を観察すると (図示せず)、少なくとも 48 個のシンボリック リンクが作成されていることがわかります。

そもそもイベント ファイルの目的は何でしょうか? cscope を使用して関数 __device_add_disk() を検索すると、disk_add_events() が呼び出され、このファイルに「mediachange」または「ejectrequest」のいずれかが書き込まれることがわかります。ここで、カーネルのブロック層は、「ディスク」の出現と消失をユーザー空間に通知します。 USB スティックの挿入がどのように機能するかをチェックするこの方法が、ソースのみからプロセスを理解しようとする方法と比べて、どれだけ高速であるかを考えてみましょう。

読み取り専用ルートファイルシステムにより組み込みデバイスが可能に

実際、電源プラグを抜いてサーバーやデスクトップ システムをシャットダウンする人はいません。なぜ?物理ストレージ デバイスにマウントされたファイル システムに保留中の (未完了の) 書き込みがある場合があり、そのステータスを記録するデータ構造がストレージに書き込まれた内容と同期していない可能性があります。このような状況が発生すると、システム所有者は次回の起動時に fsck ファイル システム回復ツールが完了するまで待機する必要があり、最悪の場合、実際にデータが失われます。

しかし、愛好家なら、ルーター、サーモスタット、自動車など、多くの IoT デバイスや組み込みデバイスが Linux を実行していることを聞いたことがあるでしょう。これらのデバイスの多くにはユーザー インターフェイスがほとんどなく、きれいに「アンブート」する方法はありません。バッテリーが切れた状態で車を始動すると、Linux を実行しているホスト デバイスの電源が絶えずオンとオフを繰り返す状態を想像してください。エンジンが最終的に実行を開始すると、システムは長時間の fsck なしでどのように起動するのでしょうか?答えは、組み込みデバイスが読み取り専用のルートファイルシステム (略して ro-rootfs) に依存しているということです。

ro-rootfs は、組み込みシステムで fsck があまり必要ない理由です。

ro-rootfs には多くの利点がありますが、耐久性ほど明白なものではありません。 1 つは、Linux プロセスが書き込みできない場合、マルウェアは /usr または /lib に書き込むことができないということです。もう 1 つは、サポート スタッフは理論上は現場のシステムと同一のローカル システムを持っているため、リモート デバイスのオンサイト サポートには、ほぼ不変のファイル システムが不可欠であるということです。おそらく最も重要な(しかし最も微妙な)利点は、ro-rootfs により、開発者がプロ​​ジェクトの設計段階でどのシステム オブジェクトを不変にするか決定しなければならないことです。 ro-rootfs の扱いは、プログラミング言語の定数変数の場合と同様に、不便であったり、面倒であったりすることがよくありますが、そのメリットは余分なオーバーヘッドを簡単に補って余りあります。

組み込み開発者にとって、読み取り専用のルート ファイル システムを作成するには追加の作業が必要であり、ここで VFS が役立ちます。Linux では、/var 内のファイルが書き込み可能である必要があり、組み込みシステムで実行される多くの一般的なアプリケーションは、$HOME に構成ドットファイルを作成しようとします。ホーム ディレクトリに配置された構成ファイルに対する 1 つの解決策は、通常、それらを事前に生成し、rootfs に組み込むことです。 /var の場合、1 つの方法は、/ 自体は読み取り専用でマウントし、別の書き込み可能なパーティションにマウントすることです。バインドマウントまたはオーバーレイマウントの使用も、一般的な代替手段です。

バインド マウントとオーバーレイ マウント、およびコンテナーでのそれらの使用法 バインド マウントとオーバーレイ マウントについて学習するには、man mount を実行するのが最適です。これにより、組み込み開発者とシステム管理者は、あるパスの場所にファイル システムを作成し、別のパスのアプリケーションでそれを使用できるようになります。組み込みシステムの場合、これは /var 内の書き込み不可のフラッシュ デバイスにファイルを保存するが、起動時に tmpfs 内のパスを /var パスにオーバーレイまたはバインド マウントして、アプリケーションがそこに必要なものを自由に書き込めるようにすることを意味します。次に電源を入れると、/var の変更は消えてしまいます。オーバーレイ マウントは、tmpfs と基礎となるファイルシステム間の結合を提供し、ro-rootfs 内の既存のファイルを直接変更できるようにします。一方、バインド マウントは、新しい空の tmpfs ディレクトリを ro-rootfs パスで書き込み可能に表示します。オーバーレイ ファイル システムは適切なファイル システム タイプですが、バインド マウントは VFS 名前空間機能によって実装されます。

オーバーレイ マウントとバインド マウントの説明を見ると、これらが Linux コンテナーで広く使用されていることに驚く人はいないはずです。 bcc の mountsnoop ツールを実行して、systemd-nspawn を使用してコンテナを起動したときに何が起こるかを監視してみましょう。


mountsnoop.py の実行中に、コンテナを起動するために system-nspawn が呼び出されます。

何が起こったか見てみましょう:


コンテナの「起動」中に mountsnoop を実行すると、コンテナのランタイムがバインドマウントに大きく依存していることがわかります。 (詳細出力の冒頭部分のみ表示)

ここで、systemd-nspawn は、ホストの procfs および sysfs から選択されたファイルを、コンテナの rootfs 内のパスとして利用できるようにします。バインドマウント時に MS_BIND フラグを設定することに加えて、マウント システム コールの他のいくつかのフラグを使用して、ホストの名前空間とコンテナー内の変更との関係を判断します。たとえば、バインド マウントは、呼び出しに応じて、/proc および /sys の変更をコンテナーに伝播したり、非表示にしたりすることができます。

要約する

Linux の内部を理解することは、不可能な作業のように思えるかもしれません。なぜなら、カーネル自体は、Linux ユーザー空間アプリケーションや glibc などの C ライブラリのシステム コール インターフェイスに加えて、膨大な量のコードから構成されているからです。進歩を遂げる方法の 1 つは、カーネル サブシステムのソース コードを読み、ユーザー空間に面したシステム コールとヘッダー ファイル、および主要なカーネル内部インターフェイスを理解することに重点を置くことです。ここでは、file_operations テーブルを例として使用します。 file_operations は「すべてがファイルである」という状態を実際に機能させるものなので、これを習得すると特にやりがいを感じます。 *** fs/ ディレクトリ内のカーネル C ソース ファイルは、仮想ファイル システムの実装を構成します。仮想ファイル システムは、一般的なファイル システムとストレージ デバイスの広範かつ比較的簡単な相互運用性を実現するシム レイヤーです。 Linux 名前空間を介したバインド マウントおよびオーバーレイ マウントは、コンテナーと読み取り専用ルート ファイル システムを可能にする VFS マジックです。ソースコード研究と組み合わせることで、eBPF カーネル ツールとその bcc インターフェイスにより、カーネルの調査がこれまで以上に簡単になります。

<<:  技術力を活かして異なるJD Cloudセキュリティを構築

>>:  クラウドコンピューティングで働いてみませんか? IT担当者が理解すべき5つのスキル

推薦する

ChionCloud: 香港 + 米国のクラウド サーバー、CN2 GIA ネットワーク、60 元/月、1G メモリ/1 コア/30G ハードディスク/3M 帯域幅無制限

ChionCloudは2009年に設立され、香港に登録されています。香港とロサンゼルスのデータセンタ...

【WeChatパブリックプラットフォーム】オンラインストアを開設し、既存の顧客を維持するための新しいヒント

私は以前、「WeChatの発展動向についての簡単な議論」というタイトルの記事を書き、WeChatパブ...

ビジュアルクラウドアーキテクチャの5つの柱

組織のクラウド インフラストラクチャから最大限の価値を引き出すことは困難な作業です。しかし、重要な考...

APP無料・有料チャンネルプロモーションのハイライト!

実際にやってみるまで、APPを宣伝するさまざまな方法について聞いていました。お金をかけずにチャンネル...

マルチアクセス エッジ コンピューティング (MEC) = 未来?

最新のデバイス、アプリケーション、サービスのほとんどは、クラウド コンピューティング リソース (デ...

ウェブサイトのデザイン分析: 製品におけるガイド付きデザインについての簡単な説明

初めて見知らぬ街に旅行する人を想像してみてください。トラブルを避けたい、見知らぬ土地に不慣れなため、...

草の根ウェブマスターがあなたの質問に答えます: SEOはそれほど神秘的ではありません

ウェブサイトの運営とプロモーションの過程で、SEO最適化は欠かせない手段であるため、近年、多くのウェ...

コメント: 草の根ナビゲーション サイトはまだ復活できるでしょうか? どうすれば復活できるでしょうか?

ウェブマスター業界に参入したばかりの友人は、ナビゲーションサイトについてあまりよく知らないかもしれま...

Baidu のウェブサイトの掲載とランキングの要因の分析例

インターネットで何年も活動した後、私はそれなりの成功を収めましたが、それはほんの一瞬の成功に過ぎませ...

virmach-34 USD/E3-1240V2/32G メモリ/2X1T ハードディスク/12IP/10T トラフィック/IPMI

私のブログを長い間フォローしている若い人たちは、8月にvirmachが初めてサーバー上で起動されたと...

2022年 日本モバイルアプリケーショントレンドレポート

このレポートでは、日本におけるモバイルゲーム、eコマース、フィンテック、出会い系アプリ、CTV プラ...

インベントリ: 2022 年の信頼性の高いエッジ コンピューティング プラットフォーム

現代のテクノロジーが進歩し、即時の満足を求める人間の欲求を満たすにつれて、消費者は製品プロバイダーを...

クラウド コンピューティング + モバイル デバイス、クラウド コンピューティングは次のトレンドになるでしょうか?

過去 10 年間にテクノロジー業界で起こった主要な出来事を順位付けすると、2 つのことが非常に重要に...

Baidu 入札でお金を稼ぐのは簡単すぎます。悪意のあるクリックによる減額は明らかです。

以下の内容には写真と証拠があります。注釈付きの説明文を除いて、写真に他の改変はありません。私は自分の...

Baiduの重みにおけるTaoxie.comとPaixie.comのカタログの違いに関する構造的議論

今日は8月10日です。実は今朝からTaoxie.comとPaixie.comを見てきました。なぜなら...