気になったことのあれこれ。この広告は、90日以上更新していないブログに表示しています。2.6.11のコードリーディングをしていく。CPUのアーキテクチャは書籍に沿ってIntelのx86とする。今回はプロセスの仮想ファイルシステム(VFS)のデータ構造について見ていく。System)はUNIXファイルシステムの全てのシステムコールを処理し、複数種類のファイルシステムへの共通インターフェースを提供する。VFSが扱うファイルシステムは以下の3種類に大別される。ディスクベースのファイルシステムローカルディスクやディスクをエミュレートするデバイスなど。社製マシン)などのメーカー独自のファイルシステムJFS(IBM社)やXFS(SGI社)などのLinuxに追加されたジャーナリングファイルシステムネットワークファイルシステムネットワーク接続した他のホストの上に存在するファイルにアクセスするためのファイルシステム。Protocol))特殊ファイルシステムローカルやネットワークどちらのディスク領域も管理しないファイルシステム(procfsなど)。Unixのディレクトリはルート(/)を起点とするツリー構造となっており、ルートディレクトリはルートファイルシステム(Ext2やExt3など)にマウントされ、他のファイルシステムはこのルートファイルシステムのサブディレクトリにマウントされる。ディスクベースのファイルシステムは通常、ハードディスクやフロッピー、CD-ROMといった物理的なブロック型デバイスに保存されるが、LinuxではVFSの機能で仮想ブロック型デバイスとして扱うことも可能。共通ファイルモデルVFSを支える概念として共通ファイルモデルが存在する。この共通モデルではディレクトリはファイルや他のディレクトリの情報をもったファイルとして扱われる。共通ファイルモデルは以下のようなオブジェクトから構成される。スーパーブロックマウントされたファイルシステムに関する情報を保存するオブジェクト。iノードオブジェクト個々のファイルの情報を持つオブジェクト。iノードにはiノード番号が振られファイルシステム内で一意にファイルを特定することができる。ファイルオープンされているファイルとプロセス間の処理に関する情報を保存するオブジェクト。プロセスがファルをオープンしている間のみカーネル内のメモリに存在する。dエントリディレクトリエントリ(ファイル名)と対応するファイルのリンク情報を保存するオブジェクト。ディスクベースのファイルシステムではファイルシステム独自の方法でディスクに保持される。詳解Linuxカーネル上記の図では3つのプロセスが同じファイルをオープンしており、そのうち2つが同じハードリンクを使用している。dエントリはハードリンクに対応しており、そのdエントリは同じiノードを参照している。VFSは共通インターフェースを提供するだけでなく性能面にも貢献しており、dエントリオブジェクトをdエントリキャッシュと呼ばれるディスクキャッシュ内に配置し、ファイルパスを高速にiノードへ変換を高速化している。(ディスクキャッシュは一般的にディスクに保存されている情報をRAMに置くための仕組み)VFSが扱うシステムコールVFSが扱うシステムコールには主に以下のようなモノが存在する。ファイルの拡張属性の操作VFSデータ構造スーパーブロックオブジェクトスーパーブロックオブジェクトはsuper_block構造体から為る。上記のリストのためのロック変数s_fs_infoの参照先にあるデータはファイルシステム固有の情報であり、iノードやディスクブロックの使用未使用を表すビットマップなどを保持し、ディスクにアクセスすることなくメモリ上の情報を更新する。一方で上記の方法だとメモリとディスクの情報に差異が生じるため、同期が取れていない状態を示すフラグとしてs_dirtyメンバが存在する。Linuxでは当該フラグを見て定期的にデータを動悸している。スーパーブロックの操作用メソッドはs_opメンバ変数が管理しており、super_operations構造体として定義されている。iノードがdirtyである時に呼び出される。loff_t);};iノードオブジェクトファイルシステムが扱う各ファイルは全てiノードと呼ばれるデータ構造で管理される。ファイル名は変更可能だがiノードはファイルに対して一意に存在している。メモリ内のiノードオブジェクトはinode構造体から為る。*/#endif};iノードオブジェクトのi_stateメンバはそのiノードの状態を表しており以下のような値がビットフラグとして設定される。各iノードは以下のいずれかの双方向リストに所属している。隣り合う要素同士は上記のi_listメンバで参照し合う。未使用のiノードオブジェクトのリスト。リスト上の要素はディスク上のiノードを正確に反映しておりプロセスからは利用されておらず、i_countメンバは0となっている。inode_unused;使用中のiノードオブジェクトのリスト。リスト上の要素はディスク上のiノードを正確に反映しており、プロセスが利用中のiノードオブジェクトが所属し、i_countメンバは0より大きい値が設定される。inode_in_use;dirtyな状態のiノードオブジェクトのリスト。対応するスーパーブロックオブジェクトのs_dirtyメンバによあって参照できる。上記のリストの他にもスーパーブロックオブジェクトのs_inodeメンバのリスト変数でも管理され、加えてinode_hashtableというハッシュテーブルでも管理されている。ハッシュテーブルの参照先は衝突を回避するためにinode構造体のi_hashメンバで双方向リストを為している。iノードの操作にはinode構造体のi_opメンバが保持しているメソッドを使用する。i_opはinode_operations構造体変数で以下のように定義されている。ファイルを参照する新しいハードリンクをディレクトリ内に作成する。*);};上記のうちiノードとファイルシステムに利用して意味があるのは一部のみで、ファイルシステムで実装されていないメソッドにはNULLが設定される。ファイルオブジェクトプロセスとそのプロセスによってオープンされたファイルの情報を保持するもので、ディスク上には存在しない。当該オブジェクトはfile構造体として定義されている。ファイルのアドレス空間オブジェクトへのポインタ};ファイルオブジェクトの中で重要なのはファイルポインタ(オフセット)で、現在利用中のファイルのどの位置を読んでいるのかを表すデータである。これはプロレス毎に独立した値として管理する必要があるため、iノードではなくファイルオブジェクトとして管理する。ファイルオブジェクトはファイルキャッシュから割り当てられる。*filp_cachep;システム上で作成できるファイルオブジェクト数はfile_statで管理される。NR_FILE};使用中のファイルオブジェクトはそのファイルを管理するファイルシステムのiノードを基点としたリストに繋がれ、前後の要素はファイルオブジェクトのf_listメンバで接続される。ファイルオブジェクトのf_countメンバはファイルオブジェクトの参照カウンタで、そのファイルオブジェクトを参照しているプロセスを表す(cloneシステムコールでCLONE_FILESフラグを指定されたプロセスは親とファイルオブジェクトを共有する)。この参照数はカーネルがオブジェクトを参照する際にも同様にインクリメントされる。ファイル操作用の関数はファイルオブジェクトのf_opメンバが保持しており、プロセスがファイルをオープンする際にiノードオフジェクトが保持している操作メソッドのアドレス群で初期化する。*);};実装されていないメソッドにはNULLが設定される。dエントリオブジェクトディスク上でディレクトリはファイルとサブディレクトリの一覧が入った通常のファイルとみなされており、そのディレクトリ内のエントリがメモリに読み込まれる際にdエントリとして扱われる。dエントリはプロセスが参照するパス名の要素1つ1つに対となるよう作成され/tmp/testであれば、/、tmp、testの3つに対して作成される。dエントリオブジェクトはディスク上に対応するデータは無く、スラブアロケータキャッシュに保存される。*dentry_cache;dエントリの構造体であるdentryは以下のように定義されている。*/};dエントリオブジェクトは以下のいずれかの状態になる。空きdエントリは有効な情報を保持しておらず、VFSによって使用されていない状態。メモリ領域はスラブアロケータによって管理される。未使用dエントリはカーネルよって使用されておらずd_countメンバは0だが、d_inodeメンバは対応するiノードを指している状態。dエントリは有効な情報を保持しているが再利用の対象と為る。使用中dエントリがカーネルによって使用されている。d_countは1以上の値が入っており、d_inodeは対応するiノードオブジェクトを指す。オブジェクトには有効な情報が格納されており破棄されない。負dエントリに対応するiノードが存在せず、ディスク上のiノードも削除された状態。d_inodeにはNULLが設定されている。dエントリオブジェクトの操作メソッドはd_opメンバが保持しており、当該メンバはdentry_operations構造体として定義されている。dエントリハッシュテーブルで使用されるファイルシステム独自のハッシュ関数。*);};dエントリキャッシュディレクトリエントリをディスクから読み込みdエントリオブジェクトを構築するのはコストがかかるため、dエントリキャッシュを使用する。状態のいずれかにあるdエントリキャッシュの集合ファイル名とディレクトリが与えられた際に対応するdエントリオブジェクトを高速に取得するためハッシュテーブル。未使用のdエントリに対応するiノードオブジェクトは、dエントリキャッシュに参照されているため破棄されない、よってそのiノードオブジェクトはRAMに置かれたままとなり、対応するdエントリによって高速に参照が可能となる。Used)リストで管理されている。LIST_HEAD(dentry_unused);dentry_unused変数のnextとprevメンバがリストの先頭と末尾を、dエントリオブジェクトのd_lruメンバがその前後の要素を参照している。使用中のdエントリオブジェクトは対応するiノードオブジェクトのi_dentryメンバが参照している双方向リストで管理される(iノードは複数のハードリンクから参照される可能性があるため)。dエントリオブジェクトのd_aliasメンバにはリストの隣接する要素のアドレスが保存される。ハッシュテーブルはdentry_hashtable配列によって実装されている。各要素は同じハッシュを持つdエントリリストへのポインタで配列のサイズはシステムが搭載しているRAMサイズに比例する。dエントリオブジェクトのd_hashメンバは同一ハッシュ値を持つリストの隣接する要素を参照する。プロセスとファイルプロセスにはワーキングディレクトリとルートディレクトリが存在し、その情報はプロセスディスクリプタ(tasK_struct)のfsメンバ(fs_struct)が保持している。altrootmnt;};プロセスには上記の他に現在オープンしているファイル情報も保持する必要があり、その情報はプロセスディスクリプタのfilesメンバであるfiles_struct構造体で管理されている。*/};fdはファイルオブジェクト配列へのポインタで、通常はfd_array配列を参照する。1番目の要素は標準入力、2番目は標準出力、3番目は標準エラー出力となる。dupやfcntlシステムコールで複数のファイルディスクリプタが同じオープン状態のファイルを参照可能なのは、複数の配列要素が同じファイルオブジェクトを参照することができるからである。プロセスはNR_OPENの値よりも多くファイルディスクリプタを使用することができない。上限の初期値は1024に設定されておりルート権限を保持している場合のみ上限を変更することが可能。*/ファイルディスクリプタ番号をfdが保持している場合、カレントプロセスからファイルオブジェクトを取得する際には以下のようなコードになる。特殊ファイルシステムネットワークやディスクベースのファイルシステム以外に特殊な用途で用いられるファイルシステムがいくつか存在する。代表的なものに以下のようなものが挙げられる。USBデバイス特殊ファイルシステムには対応するブロックデバイスが存在せず、マウント時に擬似デバイスを割り当てる。疑似デバイスのメジャー番号は0でマイナー番号は任意の値となる。ファイルシステム種別の登録ファイルシステムの登録にはカーネルのコンパイル時に静的に組み込む方法とモジュールとして動的に組み込む方法がある。登録したファイルシステムはfile_system_type構造体のオブジェクトとして管理される。*/};全てのファイルシステム種別オブジェクトは単方向リストのfile_systems変数で管理され、file_system_lock変数がスピンロック用の変数、これら2つの変数は以下のように定義されている。DEFINE_RWLOCK(file_systems_lock);get_sbは新しいスーパーブロックの割り当てと初期化、kill_sbはスーパーブロックを破棄するために使用される。fs_flagsメンバには以下のような値が設定される。*/実際のファイルシステムの登録処理はカーネルのコンパイル時に指定されたファイルシステムを、システムの初期化時にregister_filesystem関数を呼び出し適切なfile_system_typeオブジェクトをファイルシステム種別リストに挿入することで行われる。register_filesystem関数はモジュールを組み込む際にも呼び出される。»Profile低レイヤ好きのソフトウェアエンジニア。(1)はてなブログをはじめよう!k--onishiさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。