目次


Linux 仮想ファイルシステム・スイッチの徹底調査

抽象化とその大局的概念

Comments

Linux ファイルシステムのサポートを柔軟かつ拡張可能にしているのは、抽象化された一連のインターフェースそのものです。そしてこれらのインターフェースのコアとなっているのが、仮想ファイルシステム・スイッチ (VFS) です。

VFS は、上位層のアプリケーションが各種のファイルシステムでファイル入出力を行うための標準インターフェース一式を提供します。その提供の形は、ファイル入出力の対象となる 1 つ以上のデバイスに対して複数の並行するファイルシステムをサポートできるような形をとります。さらに、これらのファイルシステムは静的である必要はなく、ストレージ・デバイスの一時的な特徴に併せて動的に追加したり、削除したりすることも可能です。

例えば、標準的な Linux デスクトップは使用可能なハード・ディスク上で ext3 ファイルシステムをサポートするだけでなく、CD-ROM が使用できるとしたら、CD-ROM 上で ISO 9660 ファイルシステムもサポートします (これは、CDFS (CD-ROM File System) とも呼ばれます)。CD-ROM は挿入された後に取り出されるため、Linux カーネルは構造と内容が異なる新しいファイルシステムに適応しなければなりません。リモート・ファイルシステムには、NFS (Network File System) を介してアクセスできるだけでなく、Linux はローカル・ハード・ディスクにある Windows®/Linux デュアルブート・システムの NTFS (NT File System) パーティションをマウントし、このパーティションに対して読み取り/書き込み操作を行うこともできます。

その上、リムーバル UFD (USB Flash Drive) のホットプラグも可能なことから、さらに別のファイルシステムまで提供される場合があります。これらのデバイスに対して常に、同じファイル入出力インターフェースのセットを使用できることから、そのベースとなるファイルシステムと物理デバイスをユーザーから抽象化できるというわけです (図 1 を参照)。

図 1. さまざまなファイルシステムとストレージ・デバイスに対して抽象化層が提供する統一されたインターフェース
さまざまなファイルシステムとストレージ・デバイスに対して抽象化層が提供する統一されたインターフェース
さまざまなファイルシステムとストレージ・デバイスに対して抽象化層が提供する統一されたインターフェース

階層型抽象化

ここで、Linux VFS が提供する抽象化機能を具体的なアーキテクチャーで表してみます。図 2 は、VFS の観点から見た Linux スタックの概要図です。VFS の上にあるのは、標準カーネルのシステム・コール・インターフェース (SCI) で、このインターフェースによってユーザー空間から (別のアドレス空間にある) カーネルへと呼び出しを移行することができます。このドメインでは、ユーザー空間のアプリケーションが POSIX の open を呼び出すと、その呼び出しは GNU C ライブラリー (glibc) を介してカーネルへ渡されて、システム・コールの逆多重化が行われ、最終的には sys_open によって、VFS が呼び出されます。

図 2. VFS の階層型アーキテクチャー
VFS の階層型アーキテクチャー
VFS の階層型アーキテクチャー

VFS が提供する抽象化層は、特定のファイルシステムがその振る舞いをどのように実装しているかに関する詳細から POSIX API を切り離します。ここで鍵となるのは、そのベースにあるファイルシステムが ext3 であろうと Btrfs であろうと、API の open、read、write、または close といったシステム・コールは同じように機能することです。これは、ベースにあるファイルシステムが継承する共通ファイル・モデルを VFS が提供するからです (これらのファイルシステムは各種の POSIX API 関数に対する振る舞いを実装しなければなりません)。また、VFS外部でも抽象化が行われることで、さらにベースにある物理デバイスも隠されます (これらの物理デバイスはディスクであったり、ディスクのパーティション、ネットワーク接続されたストレージ・エンティティー、メモリー、あるいは情報を一時的であっても保存可能なその他の媒体であったりする場合があります)。

VFS は、ベースにあるファイルシステムに対するファイル操作の詳細を抽象化するだけでなく、同じくベースにあるブロック・デバイスと使用可能なファイルシステムとを結び付けます。ここからは、VFS の内部構造について、さらにはそれぞれがどのように機能するのかを見て行きます。

VFS の内部構造

VFS サブシステムの全体的なアーキテクチャーについて説明する前に、このサブシステムで使用される主要なオブジェクトについて説明しておきます。このセクションで取り上げるのは、スーパーブロック、索引ノード (inode)、ディレクトリー・エントリー (dentry)、そしてファイル・オブジェクトです。その他、キャッシュなどの重要な要素については、後ほど全体的なアーキテクチャーを説明するときに説明します。

スーパーブロック

スーパーブロックとはファイルシステムに関する上位レベルのメタデータを収容するコンテナーのことです。スーパーブロックは、ディスク上 (実際には、冗長性をもたらすためにディスク上の複数の部分) とメモリー内にその構造があり、ファイルシステムの管理パラメーター (ブロックの合計数、空きブロック、ルート inode など) を定義して、ディスク上のファイルシステムを処理するための基礎を提供します。

ディスク上のスーパーブロックは、ディスク上のファイルシステムの構造に関する情報をカーネルに提供します。メモリー内のスーパーブロックが提供するのは、アクティブな (マウントされた) ファイルシステムを管理するために必要な情報と状態です。Linux は同時にマウントされた複数の並行するファイルシステムをサポートするため、各 super_block 構造体は super_blocks リスト内に保持されます (super_blocks リストは ./linux/fs/super.c 内に定義され、/linux/include/fs/fs.h に定義された構造体を持ちます)。

図 3 は、スーパーブロックとその要素の概略図です。super_block 構造体は、他の情報をカプセル化する他の数多くの構造体を参照します。file_system_type 構造体は、例えばファイルシステムの名前 (ext3 など) や、super_block を取得および削除するための各種のロックおよび関数を保持します。file_system_type オブジェクトは、お馴染みの register_file システム関数と unregister_file システム関数 (./linux/fs/file systems.c を参照) を使用して管理されます。super_operations 構造体は、inode の読み取り/書き込み操作用の関数に加え、それより上位レベルの操作 (再マウントなど) を対象とした多数の関数を定義します。ルート dentry オブジェクトも、このファイルシステムが常駐するブロック・デバイスであることから同じくここにキャッシュされます。さらに、inode を管理するための多数のリストも提供されています。具体的には、s_inodes (すべての inode のリスト)、s_dirty (すべてのダーティー inode のリスト)、s_ios_more_io (ライトバック用に配置)、および s_files (特定のファイルシステム用に開かれているすべてのファイルのリスト) などのリストです。

図 3. super_block 構造体とその関連要素の概略図
super_block 構造体とその関連要素の概略図
super_block 構造体とその関連要素の概略図

カーネル内部では、vfsmount という別の管理オブジェクトが、マウントされたファイルシステムに関する情報を提供することに注意してください。これらのオブジェクトのリストはスーパーブロックを参照し、マウント・ポイント、このファイルシステムが常駐する /dev デバイスの名前、そしてその他の上位レベルの接続情報を定義します。

索引ノード (inode)

Linux はファイルシステム内のすべてのオブジェクトを、inode (index node の省略形) というオブジェクトを使用して管理します。inode はファイル、ディレクトリー、または別のオブジェクトへのシンボリック・リンクを参照することができます。デバイスやメモリーなどの他のタイプのオブジェクトはファイルによって表されるため、inode はこれらのオブジェクトを表すためにも使用されることに注意してください。

ここで述べている inode は、VFS 層の inode (メモリー内 inode) のことですが、それぞれのファイルシステムにも inode が含まれます。各ファイルシステムに含まれる inode はディスク上に存在し、その特定のファイルシステムに固有のオブジェクトに関する詳細情報を提供します。

VFS の inode は、スラブ・アロケーターを使って (inode_cache から) 割り振られます (スラブ・アロケーターについての詳細は、「参考文献」のリンクを参照してください)。inode を構成するのは、inode を記述するデータと操作、inode の内容、そして inode で可能な各種の操作です。図 4 に示す単純な VFS inode は多数のリストで構成されていて、そのなかの 1 つが、この inode を参照する dentry を参照します。ここに含まれるオブジェクト・レベルのメタデータは、操作に伴い記録されるお馴染みの時刻 (作成時刻、アクセス時刻、変更時刻) ならびに所有者およびアクセスの権データ (group-id、user-id、アクセス権) で構成されています。inode が参照するこの inode で可能なファイル操作のほとんどは、システム・コール・インターフェースに直接マッピングされます (openreadwriteflush など)。さらに inode 特有の操作への参照もあります (createlookuplinkmkdir など)。そして最後に、アドレス空間オブジェクトによって表されるオブジェクトを対象とした実際のデータを管理するための構造体があります。アドレス空間オブジェクトとは、ページ・キャッシュに含まれる inode の各種ページを管理するオブジェクトのことです。アドレス空間オブジェクトは、ファイルのページを管理するためだけでなく、ファイルのセクションを個々のプロセス・アドレス空間にマッピングするためにも使用されます。アドレス空間オブジェクトには独自の操作セットがあります (writepagereadpagereleasepage など)。

図 4. VFS inode の簡易表現
VFS inode の簡易表現
VFS inode の簡易表現

以上の情報はすべて、./linux/include/linux/fs.h に記載されています。

ディレクトリー・エントリー (dentry)

ファイルシステムの階層的な性質は、dentry オブジェクトと呼ばれる VFS 内の別のオブジェクトによって管理されます。ファイルシステムには 1 つのルート dentry が設定されます (スーパーブロック内で参照される dentry)。これが唯一、親のない dentry です。その他の dentry には親があり、なかには子を持つものもあります。例えば、/home/user/name という階層を持つファイルが開かれたとすると、合計 4 つの dentry オブジェクトが作成されることになります。つまり、ルートの /、ルート・ディレクトリーの home エントリー、home ディレクトリーの user エントリー、そして user ディレクトリーの name エントリーのそれぞれに対して 1 つのオブジェクトです。このように、dentry は今日使われている階層型ファイルシステムにすんなりとマッピングされます。

dentry オブジェクトは dentry 構造体によって (./linux/include/fs/dcache.h 内に) 定義されます。このオブジェクトは、ファイルシステム内でのエントリーと他のエントリーとの関係を追跡したり、物理データ (ファイル名など) を追跡したりする多数の要素からなります。図 5 は、dentry オブジェクトの概略図です。このオブジェクトが含まれる特定のファイルシステム・インスタンスは、dentry が参照する super_block によって定義されます。図 5super_block の次にあるのはオブジェクトの親の dentry (親ディレクトリー) で、その後にリスト内に含まれる子 dentry が続きます (オブジェクトがディレクトリーである場合)。続いて定義されているのは dentry の操作です (hashcomparedeleterelease などの操作があります)。操作の次に定義されているオブジェクトの名前は inode の中に保持されるのではなく、この dentry に保持されます。そして最後に、VFS inode への参照が定義されます。

図 5. dentry オブジェクトの簡易表現
dentry オブジェクトの簡易表現

dentry オブジェクトが存在するのはファイルシステムのメモリー内だけで、ディスク上には保存されないことに注意してください。永続的に保存されるのはファイルシステムの inode のみで、dentry オブジェクトはパフォーマンス向上のために使用されます。dentry 構造体の詳細は、./linux/include/dcache.h を参照してください。

ファイル (file) オブジェクト

Linux システムで開かれているファイルごとに、file オブジェクトが存在します。このオブジェクトに含まれるのは、特定ユーザーのオープン・インスタンスに固有の情報です。図 6 は、極めて簡略化した file オブジェクトの図です。この図に示されているように、path 構造体は dentryvfsmount 両方への参照が定義されます。file オブジェクトのそれぞれに定義される一連のファイル操作は、お馴染みのものです (openclosereadwriteflush など)。フラグとアクセス権も定義されます (グループおよび所有者を含む)。そして最後に、特定のファイル・インスタンスに対してステートフルなデータ (ファイルへの現行オフセットなど) が定義されます。

図 6. file オブジェクトの簡易表現
file オブジェクトの簡易表現

オブジェクト間の関係

VFS 層の重要な各種オブジェクトについて概説したところで、これらのオブジェクトをまとめて 1 つの図に示し、それぞれがどのように関連しているのかを見てみましょう。この記事ではこれまでボトムアップ方式でオブジェクトを調べてきたので、今度はユーザーの観点で逆の方向から見ることにします (図 7 を参照)。

最上位にあるのは、プロセスのファイル記述子リストが参照するオープン file オブジェクトです。file オブジェクトが参照する dentry オブジェクトは、inode オブジェクトを参照します。inode オブジェクトと dentry オブジェクトの両方が参照するのは、そのベースとなる super_block オブジェクトです。複数の file オブジェクトが同じ dentry オブジェクトを参照する場合もあります (2 人のユーザーが同じファイルを共有している場合など)。図 7 では、dentry オブジェクトが別の dentry オブジェクトを参照している点にも注意してください。この場合、ディレクトリーがファイルを参照し、そのファイルが特定ファイルの inode オブジェクトを参照します。

図 7. VFS の主要なオブジェクト間の関係
VFS の主要なオブジェクト間の関係
VFS の主要なオブジェクト間の関係

VFS のアーキテクチャー

VFS の内部アーキテクチャーは、ファイルシステムを抽象化するディスパッチ層と、ファイルシステム操作のパフォーマンスを向上させるためのいくつものキャッシュからなります。このセクションでは内部アーキテクチャーについて調べるとともに、主要なオブジェクトがどのようにやりとりするのかも調べます (図 8 を参照)。

図 8. VFS 層の概要
VFS 層の概要
VFS 層の概要

VFS 内で動的に管理される 2 つの主要なオブジェクトは、dentryinode です。これらのオブジェクトは、そのベースとなるファイルシステムにアクセスする際のパフォーマンスを向上させるためにキャッシュに入れられます。ファイルを開くと、パスを表すディレクトリー・レベルを示すエントリーが dentry キャッシュに取り込まれます。オブジェクトには、ファイルを表す inode も作成されます。dentry キャッシュはハッシュ・テーブルを使って作成され、オブジェクトの名前を基にハッシュ値が計算されます。dentry_cache スラブ・アロケーターから割り当てられる dentry キャッシュのエントリーは、メモリーに負担がかかると、LRU (Least Recently Used) アルゴリズムによってエントリーを削除します。dentry キャッシュに関連する関数は、./linux/fs/dcache.c (および ./linux/include/linux/dcache.h) にあります。

inode キャッシュは、検索を高速化するために 2 つのリストと 1 つのハッシュ・テーブルとして実装されます。最初のリストが現在使用中の inode を定義し、2 つ目のリストが未使用の inode を定義します。使用中の inode はハッシュ・テーブルにも保存されます。個々の inode キャッシュ・オブジェクトは、inode_cache スラブ・アロケーターから割り当てられます。inode キャッシュに関連する関数は、./linux/fs/inode.c (および ./linux/include/fs.h) にあります。現在の実装では、dentry キャッシュが inode キャッシュのマスターとなるため、dentry オブジェクトが存在するときには、inode オブジェクトも inode キャッシュに存在することになります。検索は dentry キャッシュで行われ、その結果 inode キャッシュ内のオブジェクトが検出されます。

さらに詳しく調べてください

この記事では、VFS とその手法、そしてさまざまなファイルシステムへのアクセスを統一するために使用されているオブジェクトについて表面的に説明したにすぎません。このように、サブシステムからして Linux はスケーラブルで柔軟性と拡張性に優れています。「参考文献」セクションで紹介している資料を参考に、さらに詳しく学んでください。


ダウンロード可能なリソース


関連トピック

  • ファイルシステムを管理する Linux サブシステムは大規模で複雑です。さらに大掛かりなファイルシステム・サブシステムについて詳しく学ぶには、Tim の「Linux ファイルシステム」(developerWorks、2007年10月) を読んでください。
  • ext4 について紹介している Tim の「ext4 の徹底調査」(developerWorks、2009年2月) で、この次世代ジャーナリング・ファイルシステムの概要を学んでください。
  • スラブ・アロケーターを使用して Linux がメモリーを管理する方法については、Tim の「Linux スラブ・アロケーターの徹底調査」(developerWorks、2007年5月) で説明しています。
  • ユーザー空間から VFS を操作するには、コマンドをユーザー空間とカーネルとの間でのコマンドの遷移を管理するシステム・コール・インターフェースが必要です。このプロセスについて詳しく学ぶには、Tim の「Linux システム・コールを使用したカーネル・コマンド」(developerWorks、2007年3月) を読んでください。
  • IBM AIX® オペレーティング・システムにも VFS 実装が提供されています。この AIX VFS 実装を紹介している「仮想ファイルシステムの概要」では、仮想ファイルシステムのなかで表現されるさまざまなオブジェクトについて説明しています。
  • Institut für Informatik によるオペレーティング・システム・コースの Linux VFS 概要では、VFS をわかりやすく紹介するとともに、ext2 ファイルシステムでの使用方法を検討しています。インド・ボンベイの Indian Institute of Technology によるプレゼンテーションでも、VFS について分かりやすく簡潔に紹介しています。
  • developerWorks Linux ゾーンに豊富に揃った Linux 開発者向けの資料を調べてください。記事とチュートリアルの人気ランキングも要チェックです。
  • developerWorks に掲載されているすべての「Linux のヒント」シリーズの記事Linux チュートリアルを参照してください。

コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Linux
ArticleID=432972
ArticleTitle=Linux 仮想ファイルシステム・スイッチの徹底調査
publish-date=08312009