続々: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はBSD系Unixで扱われるファイルシステムのデータ構造です。
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構造体については次回に調べてみたいと思います。
次回に続く。
関連記事
[FreeBSD]続:FreeBSD のファイルシステムのソースコードを読む
[Mac OS X]MacFUSE+sshfsが便利
[Linux][レンタルサーバー]お名前.com レンタルサーバーVPSを借りてみた
[Linux][libvirt][Ruby]CentOSにruby-libvirtをインストールする
[PHP]PHPのガーベジコレクタについて
*1:error = getnewvnode("isofs", mp, &cd9660_vnodeops, &vp