理想未来ってなんやねん

娘可愛い。お父さん頑張る。

続々:FreeBSD のファイルシステムのソースコードを読む

昨日の続き
vop_vector構造体と関連するソースコードを見ていきたいと思います。

vop_vector構造体変数

まずvop_vector構造体変数が定義されているソースを調べてみました。
他にもありますが全て載せても仕方が無いので絞っています。

ソースファイル 構造体変数名
kern/vfs_default.c default_vnodeops
fs/fifofs/fifo_vnops.c fifo_specops
fs/tmpfs/tmpfs_fifoops.c tmpfs_fifoop_entries
fs/tmpfs/tmpfs_vnops.c tmpfs_vnodeop_entries
fs/nfsclient/nfs_clvnops.c newnfs_vnodeops
fs/nfsclient/nfs_clvnops.c newnfs_fifoops
fs/cd9660/cd9660_vnops.c cd9660_vnodeops
fs/cd9660/cd9660_vnops.c cd9660_fifoops
ufs/ufs/ufs_vnops.c ufs_vnodeops
ufs/ufs/ufs_vnops.c ufs_fifoops
ufs/ffs/ffs_vnops.c ffs_vnodeops1
ufs/ffs/ffs_vnops.c ffs_fifoops1
ufs/ffs/ffs_vnops.c ffs_vnodeops2
ufs/ffs/ffs_vnops.c ffs_fifoops2

ファイルシステム毎にvnodeopおよびfinfoopの2つ定義されているようですね。


vop_vector構造体変数でセットされている値について表に纏めてみました。
http://d.hatena.ne.jp/pcmaster/files/vop_vector_list.html?d=y


vop_defaultは必ず定義されていますが、それ以外は意外と歯抜けです。
vop_defaultを見ると他の構造体変数のアドレスがセットされているのが分かります。


この表を見るとvop_defaultの多くはdefault_vnodeopsまたはfifo_specopsが指定されており、また、fifo_specopsのvop_defaultにはdefault_vnodeopsがセットされていることが分かります。


恐らくvop_defaultに指定された構造体変数が、親クラス的な働きをし、値を指定したメンバについてはオーバーライドされ、指定されていないメンバに関してはvop_defaultから継承された関数を使用しているのだと思います。

さて、構造体変数が定義されているだけでは使われる事がありませんので、どこかで参照している箇所があると思います。
grepで調べてみると下記の通りでした。

変数名 ファイル 行数 コード
tmpfs_fifoop_entries fs/tmpfs/tmpfs_subr.c 375 vp->v_op = &tmpfs_fifoop_entries;
tmpfs_vnodeop_entries fs/tmpfs/tmpfs_subr.c 352 error = getnewvnode("tmpfs", mp, &tmpfs_vnodeop_entries, &vp);
cd9660_fifoops fs/cd9660/cd9660_vfsops.c 812 vp->v_op = &cd9660_fifoops;
cd9660_vnodeops fs/cd9660/cd9660_vfsops.c 682 if *1 != 0) {
newnfs_fifoops fs/nfsclient/nfs_clport.c 357 vp->v_op = &newnfs_fifoops;
newnfs_vnodeops fs/nfsclient/nfs_clnode.c 124 error = getnewvnode("newnfs", mntp, &newnfs_vnodeops, &nvp);
ffs_fifoops1 ufs/ffs/ffs_vfsops.c 1510 error = ufs_vinit(mp, &ffs_fifoops1, &vp);
ffs_fifoops2 ufs/ffs/ffs_vfsops.c 1512 error = ufs_vinit(mp, &ffs_fifoops2, &vp);
ffs_vnodeops1 ufs/ffs/ffs_alloc.c 1011 (*vpp)->v_op = &ffs_vnodeops1;
ffs_vnodeops1 ufs/ffs/ffs_vfsops.c 1437 error = getnewvnode("ufs", mp, &ffs_vnodeops1, &vp);
ffs_vnodeops2 ufs/ffs/ffs_alloc.c 1009 (*vpp)->v_op = &ffs_vnodeops2;
ffs_vnodeops2 ufs/ffs/ffs_vfsops.c 1439 error = getnewvnode("ufs", mp, &ffs_vnodeops2, &vp);
ufs_fifoops ufs/ffs/ffs_vnops.c 1380 return (VOP_STRATEGY_APV(&ufs_fifoops, ap));

vnodeopは、getnewvnode関数の引数として渡されているようです。


fifoopに関しては、vp->v_opにセットされているようです。
調べたところvpはvnode構造体のポインタでした。
vp->v_opにセットする際にvp->v_type がVFIFOであるかチェックしています。

v_typeはvnodeの型のようです。
man vnodeで確認すると、次のように書いてあります。

VNODE TYPES
     VNON   No type.

     VREG   A regular file; may be with or without VM object backing.  If you
            want to make sure this get a backing object, call
            vfs_object_create(9).

     VDIR   A directory.

     VBLK   A block device; may be with or without VM object backing.  If you
            want to make sure this get a backing object, call
            vfs_object_create(9).

     VCHR   A character device.

     VLNK   A symbolic link.

     VSOCK  A socket.  Advisory locking will not work on this.

     VFIFO  A FIFO (named pipe).  Advisory locking will not work on this.

     VBAD   An old style bad sector map

日本語訳は下記にあります。
http://www.jp.freebsd.org/cgi/mroff.cgi?subdir=man&lc=1&cmd=&man=vnode&dir=jpman-8.1.2%2Fman§=0

VFIFOは名前付きパイプのようですので、名前付きパイプをサポートする場合に使われるのだと思います。


vnodeはBSDUnixで扱われるファイルシステムのデータ構造です。
Linuxや他のUnixではinodeといいますが、こちらの方はご存知の方も多いと思います。

vnodeについては後日調べてみます。

エントリポイントはどこだ?

ここまで調べてエントリポイントらしきコードが見つかりませんでした。
エントリポイントとはC言語で作成した実行プログラムであればmain、WindowsのDLLであればDllMainのようにプログラムを開始する箇所です。


vop_vector構造体をたどることでエントリポイントを探せるかと思いましたが、探し当てることが出来ませんでしたので他の方法で探してみたいと思います。


色々探してみたところ、fs/tmpfs/tmpfs_vfsops.cの最下行に次のようなコードを見つけました。

/*
 * tmpfs vfs operations.
 */

struct vfsops tmpfs_vfsops = {
        .vfs_mount =                    tmpfs_mount,
        .vfs_unmount =                  tmpfs_unmount,
        .vfs_root =                     tmpfs_root,
        .vfs_statfs =                   tmpfs_statfs,
        .vfs_fhtovp =                   tmpfs_fhtovp,
};
VFS_SET(tmpfs_vfsops, tmpfs, 0);


fs/cd9660/cd9660_vfsops.cにも同様のコードがあります。

static struct vfsops cd9660_vfsops = {
        .vfs_fhtovp =           cd9660_fhtovp,
        .vfs_mount =            cd9660_mount,
        .vfs_cmount =           cd9660_cmount,
        .vfs_root =             cd9660_root,
        .vfs_statfs =           cd9660_statfs,
        .vfs_unmount =          cd9660_unmount,
        .vfs_vget =             cd9660_vget,
};
VFS_SET(cd9660_vfsops, cd9660, VFCF_READONLY);
MODULE_VERSION(cd9660, 1);


ufs/ffs/ffs_vfsops.cにも存在しました。

static struct vfsops ufs_vfsops = {
        .vfs_extattrctl =       ffs_extattrctl,
        .vfs_fhtovp =           ffs_fhtovp,
        .vfs_init =             ffs_init,
        .vfs_mount =            ffs_mount,
        .vfs_cmount =           ffs_cmount,
        .vfs_quotactl =         ufs_quotactl,
        .vfs_root =             ufs_root,
        .vfs_statfs =           ffs_statfs,
        .vfs_sync =             ffs_sync,
        .vfs_uninit =           ffs_uninit,
        .vfs_unmount =          ffs_unmount,
        .vfs_vget =             ffs_vget,
        .vfs_susp_clean =       process_deferred_inactive,
};

VFS_SET(ufs_vfsops, ufs, 0);
MODULE_VERSION(ufs, 1);

vfsops構造体とVFS_SETマクロが怪しそうです。
VFS_SETはマニュアルに下記の通り記載されています。

http://www.jp.freebsd.org/cgi/mroff.cgi?subdir=man&lc=1&cmd=&man=VFS_SET&dir=jpman-8.0.2%2Fman§=0

〜〜〜省略〜〜〜
名称
     VFS_SET -- ローダブルファイルシステム vfsconf のセットアップ

書式
     #include <sys/param.h>
     #include <sys/kernel.h>
     #include <sys/module.h>
     #include <sys/mount.h>

     void
     VFS_SET(struct vfsops *vfsops, fsname, int flags);

解説
     VFS_SET() はローダブルモジュールのために与えられた vfsops, fsname および
     flags で vfsconf 構造体を作成し、イベントハンドラとして vfs_modevent() を
     使用して DECLARE_MODULE(9) の呼び出しによって宣言します。
〜〜〜省略〜〜〜


どうやらVFS_SETマクロでvfsops構造体変数のポインタをセットしているようですね。
vfsops構造体から追っていけば、ファイルシステムの動作について理解出来そうです。


そんな感じで、vfsops構造体については次回に調べてみたいと思います。

次回に続く。

*1:error = getnewvnode("isofs", mp, &cd9660_vnodeops, &vp