知識倉庫@日々徒然

VFSメモ

最終更新:

匿名ユーザー

- view
だれでも歓迎! 編集
VFSの構造・動作。

UNIXのVFS実装(最前線UNIXのカーネルより)

代表的なオブジェクト

vノード

struct vnode {
    u_short v_flag;              /* V_ROOTなど */
    u_short v_count;             /* 参照カウントなど */
    struct vfs *vfsmountedhere;  /* マウントポイント用 */
    struct vnodeops *v_op;       /* vノード操作のベクタ */
    struct vfs *vfsp;            /* vノードが属するファイルシステム */
    struct stdata *v_stream;     /* 関連ストリームへのポインタ */
    struct page *v_page;         /* 常駐ページリスト */
    enum vtype v_type;           /* ファイルの種類 */
    dev_t v_rdev;                /* デバイスファイル用のデバイスID */
    caddr_t v_data;              /* プライベートデータ構造へのポインタ */
    …
};

vノード操作のベクタ

struct vnodeops {
    int (*vop_open)();
    int (*vop_close)();
    int (*vop_read)();
    …
};

vfsオブジェクト

struct vfs {
    struct vfs *vfs_next;              /* リスト中の次のVFS */
    struct vfsops *vfs_op;             /* 操作のベクタ */
    struct vnode *vfs_vnodecovered;    /* マウントされるvノード */
    caddr_t vfs_data;                  /* プライベートデータ */
    dev_t vfs_dev;                     /* デバイスID */
    …
};

vfs操作のベクタ

struct vfsops {
    int (*vfs_mount)();
    int (*vfs_unmount)();
    int (*vop_root)();
    int (*vfs_statvfs)();
    int (*vfs_sync)();
    …
};

仮想ファイルシステムスイッチテーブル

struct vfssw {
    char *vsw_name;                  /* ファイルシステムの名前 */
    int (*vsw_init)();               /* 初期化ルーチンのアドレス */
    struct vfsops vfsw_vfsops;       /* このファイルシステム用のvfs操作ベクタ */
    …
} vfssw[];

オブジェクト間の静的構造

  • 大域変数rootvfsから、nextによりvfsオブジェクトを辿ることができる。vfssw配列とvfsオブジェクトリストにより、カーネルはいつでも特定ファイルシステムを表すvfsオブジェクトを取得できる。
rootvfs -> vfsオブジェクト -> vfsオブジェクト -> …

  • vfsオブジェクトからは、マウントポイントのvノードを辿ることができる。これにより、あるファイルシステムのvノードから親階層に向けて論理ツリーを辿る際にファイルシステムをまたがって遡ることができる。
vfsオブジェクト -> マウントポイントのvノード -> 所属するvfsオブジェクト -> …

  • あるファイルシステムのルートにあたるvノードには、VROOTフラグあり
論理ツリーを遡る際に、現在のvノードがファイルシステムのルートかどうか識別する際に用いる。

  • vfsオブジェクトは、ファイルシステム依存データへのポインタを持つ。
vfsオブジェクト -> vfs_data

  • vfsオブジェクトは、ファイルシステム依存操作へのポインタを持つ。
vfsオブジェクト -> vfs_op

  • vノードは、ファイルシステム依存データへのポインタを持つ。
vノード -> v_data

  • vノードは、ファイルシステム依存操作へのポインタを持つ。
vノード -> v_op

オブジェクト間の相互作用

システムコール呼び出し時の動作

  • open操作
    • ユーザプロセスにより、openシステムコールが呼び出される。
    • カーネルは、ファイル記述子を割り当てる。
    • カーネルは、オープンファイルオブジェクトを割り当て、ファイル記述子テーブルにこの構造体へのポインタを保存する。
    • カーネルは、lookuppn()によりパス名を解決し、オープンするファイルのvノードを得る。この際lookuppn()は、親ディレクトリのvノードも返す。*1
    • カーネルは、呼び出し元が必要な権限を持っているかどうかをVOP_ACCESSにより確認する。
    • カーネルは、ディレクトリのオープンや実行中ファイルへの書き込みが行われていないかを確認する。
    • ファイルが存在していない場合、カーネルはO_CREATオプションを確認する。指定されていた場合、カーネルはVOP_CREATにより親ディレクトリ上にファイルを作成する。
指定されていなかった場合、カーネルはENOENTエラーを返す。
    • カーネルは、VOP_OPENを実行し、ファイルシステム依存の処理を行う。*2
    • カーネルはO_TRUNCオプションを確認し、指定されていた場合はファイルサイズを0にするためにVOP_SETATTRを呼ぶ。*3
    • カーネルは、オープンファイルオブジェクトを初期化する。vノードのポインタとopenモードのフラグを保存し、参照カウントを1にし、オフセットを0にする。
    • カーネルは、ファイル記述子の番号をユーザプロセスに返す。

  • read/write操作
    • ユーザプロセスにより、read/writeシステムコールが呼び出される。
    • カーネルは引数からuio構造体を作成する。
    • カーネルは引数のファイル記述子からオープンファイルオブジェクトを探し、要求された操作が可能な型でopenされているかを確認する。
    • カーネルは、オープンファイルオブジェクトから、vノードを取得する。
    • カーネルはVOP_RWLOCKでvノードをロックする。
    • カーネルは、VOP_READ/VOP_WRITEを呼び出す。
    • I/Oが完了したら、カーネルはVOP_UNLOCKでロックを解除する。
    • カーネルは、ユーザプロセスに読み書きしたバイト数を返す。

  • mount操作
    • ユーザプロセスにより、mountシステムコールが呼び出される。
    • カーネルは、ファイルシステム非依存のlookuppn()を呼び出し、マウントポイントのvノードを取得する。
    • カーネルは、取得したvノードが(ファイルではなく)ディレクトリであり、既に他のファイルシステムがマウントされていないかを確認する。
    • カーネルはvfsswリストを検索し、マウント対象のvfsオブジェクトを取得する。
    • カーネルは、vfs_op->vfs_initを実行する。これにより、以下の処理が行われる。
    • rootvfs変数を始点とするvfsオブジェクトリストに新たなvfsオブジェクトが追加される。
    • 追加されたオブジェクトのvfs_opにvfsswで指定されたvfsopsがセットされる。
    • 追加されたオブジェクトのvfs_vnodeoveredにマウントポイントのvノードがセットされる。
    • vfs_init操作が終了する。続いて、カーネルはVFS_MOUNTを実行する。これにより、ファイルシステムに依存した以下の処理が行われる。
    • 操作の権限がチェックされる。
    • ファイルシステム依存のデータオブジェクトが割り当てられ、ディスクからのデータを元に初期化される。
    • 割り当てられたデータオブジェクトが、vfsオブジェクトのvfs_dataに保存される。
    • ファイルシステムのルートディレクトリにアクセスし、そのvノードがメモリ中に初期化される。*4

LinuxのVFS実装

タグ:

+ タグ編集
  • タグ:

このサイトはreCAPTCHAによって保護されており、Googleの プライバシーポリシー利用規約 が適用されます。

記事メニュー
人気記事ランキング
目安箱バナー
注釈

*1 open対象ファイルが存在せず、ファイルを作成する場合に親ディレクトリのvノードが必要となるため。

*2 通常、何の処理も行われない

*3 ファイルシステム依存のコードは、ブロックの解放などを行う。

*4 これは、VFS_ROOT操作を実装するためである。カーネルが該ファイルシステムのルートディレクトリのvノードを取得するためには、vfsオブジェクトのVFS_ROOTを用いる以外に方法が用意されていない。VFS_ROOT操作の実体はファイルシステム依存の操作であるため、ファイルシステム側でルートディレクトリのvノードを管理する必要がある。