続:FreeBSD のファイルシステムのソースコードを読む
昨日の続き。
modulesディレクトリの下にはMakefileしかなく、ソースコード本体はfsやufsディレクトリにあることがわかりましたので、fsディレクトリを見ていきたいと思います。
ソースコードが短いものを探す
できれば短いコードの方がわかりやすいので、サイズの小さいものを探します。
$ cd /usr/src/sys/fs $ du | sort -n 8 ./deadfs 22 ./fifofs 26 ./fdescfs 28 ./portalfs 50 ./nullfs 70 ./pseudofs 76 ./procfs 92 ./devfs 94 ./udf 108 ./hpfs 110 ./nwfs 110 ./unionfs 120 ./tmpfs 130 ./ntfs 140 ./cd9660 140 ./smbfs 184 ./coda 246 ./msdosfs 318 ./nfs 432 ./nfsserver 552 ./nfsclient 3058 .
deadfsが一番小さいようですね。
deadfs
どんなファイルシステムか知りませんが、とりあえず見てみます。
$ cd deadfs $ ls -l -rw-r--r-- 1 root wheel 5563 Oct 25 2009 dead_vnops.c
dead_vnops.cというファイルが一つだけありました。
中身を確認します。
長くなりますが始めなので敢えて全て載せます。
/*- * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)dead_vnops.c 8.1 (Berkeley) 6/10/93 * $FreeBSD: src/sys/fs/deadfs/dead_vnops.c,v 1.51.2.1.2.1 2009/10/25 01:10:29 kensmith Exp $ */ #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> #include <sys/lock.h> #include <sys/mutex.h> #include <sys/poll.h> #include <sys/vnode.h> /* * Prototypes for dead operations on vnodes. */ static vop_bmap_t dead_bmap; static vop_ioctl_t dead_ioctl; static vop_lookup_t dead_lookup; static vop_open_t dead_open; static vop_poll_t dead_poll; static vop_read_t dead_read; static vop_write_t dead_write; static vop_getwritemount_t dead_getwritemount; static vop_rename_t dead_rename; struct vop_vector dead_vnodeops = { .vop_default = &default_vnodeops, .vop_access = VOP_EBADF, .vop_advlock = VOP_EBADF, .vop_bmap = dead_bmap, .vop_create = VOP_PANIC, .vop_getattr = VOP_EBADF, .vop_getwritemount = dead_getwritemount, .vop_inactive = VOP_NULL, .vop_ioctl = dead_ioctl, .vop_link = VOP_PANIC, .vop_lookup = dead_lookup, .vop_mkdir = VOP_PANIC, .vop_mknod = VOP_PANIC, .vop_open = dead_open, .vop_pathconf = VOP_EBADF, /* per pathconf(2) */ .vop_poll = dead_poll, .vop_read = dead_read, .vop_readdir = VOP_EBADF, .vop_readlink = VOP_EBADF, .vop_reclaim = VOP_NULL, .vop_remove = VOP_PANIC, .vop_rename = dead_rename, .vop_rmdir = VOP_PANIC, .vop_setattr = VOP_EBADF, .vop_symlink = VOP_PANIC, .vop_vptocnp = VOP_EBADF, .vop_write = dead_write, }; /* ARGSUSED */ static int dead_getwritemount(ap) struct vop_getwritemount_args /* { struct vnode *a_vp; struct mount **a_mpp; } */ *ap; { *(ap->a_mpp) = NULL; return (0); } /* * Trivial lookup routine that always fails. */ /* ARGSUSED */ static int dead_lookup(ap) struct vop_lookup_args /* { struct vnode * a_dvp; struct vnode ** a_vpp; struct componentname * a_cnp; } */ *ap; { *ap->a_vpp = NULL; return (ENOTDIR); } /* * Open always fails as if device did not exist. */ /* ARGSUSED */ static int dead_open(ap) struct vop_open_args /* { struct vnode *a_vp; int a_mode; struct ucred *a_cred; struct proc *a_p; } */ *ap; { return (ENXIO); } /* * Vnode op for read */ /* ARGSUSED */ static int dead_read(ap) struct vop_read_args /* { struct vnode *a_vp; struct uio *a_uio; int a_ioflag; struct ucred *a_cred; } */ *ap; { /* * Return EOF for tty devices, EIO for others */ if ((ap->a_vp->v_vflag & VV_ISTTY) == 0) return (EIO); return (0); } /* * Vnode op for write */ /* ARGSUSED */ static int dead_write(ap) struct vop_write_args /* { struct vnode *a_vp; struct uio *a_uio; int a_ioflag; struct ucred *a_cred; } */ *ap; { return (EIO); } /* * Device ioctl operation. */ /* ARGSUSED */ static int dead_ioctl(ap) struct vop_ioctl_args /* { struct vnode *a_vp; u_long a_command; caddr_t a_data; int a_fflag; struct ucred *a_cred; struct proc *a_p; } */ *ap; { /* XXX: Doesn't this just recurse back here ? */ return (VOP_IOCTL_AP(ap)); } /* * Wait until the vnode has finished changing state. */ static int dead_bmap(ap) struct vop_bmap_args /* { struct vnode *a_vp; daddr_t a_bn; struct bufobj **a_bop; daddr_t *a_bnp; int *a_runp; int *a_runb; } */ *ap; { return (VOP_BMAP(ap->a_vp, ap->a_bn, ap->a_bop, ap->a_bnp, ap->a_runp, ap->a_runb)); } /* * Trivial poll routine that always returns POLLHUP. * This is necessary so that a process which is polling a file * gets notified when that file is revoke()d. */ static int dead_poll(ap) struct vop_poll_args *ap; { return (POLLHUP); } static int dead_rename(ap) struct vop_rename_args /* { struct vnode *a_fdvp; struct vnode *a_fvp; struct componentname *a_fcnp; struct vnode *a_tdvp; struct vnode *a_tvp; struct componentname *a_tcnp; } */ *ap; { if (ap->a_tvp) vput(ap->a_tvp); if (ap->a_tdvp == ap->a_tvp) vrele(ap->a_tdvp); else vput(ap->a_tdvp); vrele(ap->a_fdvp); vrele(ap->a_fvp); return (EXDEV); }
deadfsという名前の通り、中身はないようです。
このファイルから次のことが分かります。
- includeされているヘッダファイル
- 関数のプロトタイプ宣言
- 関数テーブル(vop_vector)
- 関数定義(実体)
- 使われている定数、マクロ
ヘッダファイル
deadfsは最も小さいファイルシステムであると思いますので、ここで読み込んでいるヘッダファイルが、ファイルシステムを作る際に最低限必要になるヘッダファイルということになると思います。
#include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> #include <sys/lock.h> #include <sys/mutex.h> #include <sys/poll.h> #include <sys/vnode.h>
vop_vector構造体
興味を引くvop_vector構造体です。
おそらくファイルシステム共通の関数テーブルになっていると想像します。
ファイルシステムのモジュールを作成する場合は、この構造体変数を定義する必要があるのだと思います。
struct vop_vector dead_vnodeops = { .vop_default = &default_vnodeops, .vop_access = VOP_EBADF, .vop_advlock = VOP_EBADF, .vop_bmap = dead_bmap, .vop_create = VOP_PANIC, .vop_getattr = VOP_EBADF, .vop_getwritemount = dead_getwritemount, .vop_inactive = VOP_NULL, .vop_ioctl = dead_ioctl, .vop_link = VOP_PANIC, .vop_lookup = dead_lookup, .vop_mkdir = VOP_PANIC, .vop_mknod = VOP_PANIC, .vop_open = dead_open, .vop_pathconf = VOP_EBADF, /* per pathconf(2) */ .vop_poll = dead_poll, .vop_read = dead_read, .vop_readdir = VOP_EBADF, .vop_readlink = VOP_EBADF, .vop_reclaim = VOP_NULL, .vop_remove = VOP_PANIC, .vop_rename = dead_rename, .vop_rmdir = VOP_PANIC, .vop_setattr = VOP_EBADF, .vop_symlink = VOP_PANIC, .vop_vptocnp = VOP_EBADF, .vop_write = dead_write, };
vop_vector構造体の定義がありませんでした。
sys/vnode.hで定義されているのかと思いましたが見当たりませんでした。
どうやらsys/kern/vnode_if.srcを元に、sys/tools/vnode_if.awkで生成されているようです。
sys/tools/vnode_if.awkは、sys/conf/kmod.mkおよびsys/conf/kern.post.mkで呼ばれています。
sys/conf/kmod.mkは、/usr/share/mk/bsd.kmod.mkでincludeされています。
bsd.kmod.mkは、sys/modules以下のモジュールのMakefile内でインクルードされていますので、makeする際に生成されるのではないかと推察します。
deadfsはsys/modulesディレクトリの下に無いため、代わりにtmpfsで確かめてみたところ、
# make Warning: Object directory not changed from original /usr/src/sys/modules/tmpfs @ -> /usr/src/sys machine -> /usr/src/sys/amd64/include awk -f @/tools/vnode_if.awk @/kern/vnode_if.src -p awk -f @/tools/vnode_if.awk @/kern/vnode_if.src -q awk -f @/tools/vnode_if.awk @/kern/vnode_if.src -h cc -O2 -pipe -fno-strict-aliasing -Werror -D_KERNEL -DKLD_MODULE -nostdinc -I. -I@ -I@/contrib/altq -finline-limit=8000 --param inline-unit-growth=100 --param large-function-growth=1000 -fno-common -fno-omit-frame-pointer -mcmodel=kernel -mno-red-zone -mfpmath=387 -mno-sse -mno-sse2 -mno-sse3 -mno-mmx -mno-3dnow -msoft-float -fno-asynchronous-unwind-tables -ffreestanding -fstack-protector -std=iso9899:1999 -fstack-protector -Wall -Wredundant-decls -Wnested-externs -Wstrict-prototypes -Wmissing-prototypes -Wpointer-arith -Winline -Wcast-qual -Wundef -Wno-pointer-sign -fformat-extensions -c /usr/src/sys/modules/tmpfs/../../fs/tmpfs/tmpfs_vnops.c cc -O2 -pipe -fno-strict-aliasing -Werror -D_KERNEL -DKLD_MODULE -nostdinc -I. -I@ -I@/contrib/altq -finline-limit=8000 --param inline-unit-growth=100 --param large-function-growth=1000 -fno-common -fno-omit-frame-pointer -mcmodel=kernel -mno-red-zone -mfpmath=387 -mno-sse -mno-sse2 -mno-sse3 -mno-mmx -mno-3dnow -msoft-float -fno-asynchronous-unwind-tables -ffreestanding -fstack-protector -std=iso9899:1999 -fstack-protector -Wall -Wredundant-decls -Wnested-externs -Wstrict-prototypes -Wmissing-prototypes -Wpointer-arith -Winline -Wcast-qual -Wundef -Wno-pointer-sign -fformat-extensions -c /usr/src/sys/modules/tmpfs/../../fs/tmpfs/tmpfs_fifoops.c cc -O2 -pipe -fno-strict-aliasing -Werror -D_KERNEL -DKLD_MODULE -nostdinc -I. -I@ -I@/contrib/altq -finline-limit=8000 --param inline-unit-growth=100 --param large-function-growth=1000 -fno-common -fno-omit-frame-pointer -mcmodel=kernel -mno-red-zone -mfpmath=387 -mno-sse -mno-sse2 -mno-sse3 -mno-mmx -mno-3dnow -msoft-float -fno-asynchronous-unwind-tables -ffreestanding -fstack-protector -std=iso9899:1999 -fstack-protector -Wall -Wredundant-decls -Wnested-externs -Wstrict-prototypes -Wmissing-prototypes -Wpointer-arith -Winline -Wcast-qual -Wundef -Wno-pointer-sign -fformat-extensions -c /usr/src/sys/modules/tmpfs/../../fs/tmpfs/tmpfs_vfsops.c cc -O2 -pipe -fno-strict-aliasing -Werror -D_KERNEL -DKLD_MODULE -nostdinc -I. -I@ -I@/contrib/altq -finline-limit=8000 --param inline-unit-growth=100 --param large-function-growth=1000 -fno-common -fno-omit-frame-pointer -mcmodel=kernel -mno-red-zone -mfpmath=387 -mno-sse -mno-sse2 -mno-sse3 -mno-mmx -mno-3dnow -msoft-float -fno-asynchronous-unwind-tables -ffreestanding -fstack-protector -std=iso9899:1999 -fstack-protector -Wall -Wredundant-decls -Wnested-externs -Wstrict-prototypes -Wmissing-prototypes -Wpointer-arith -Winline -Wcast-qual -Wundef -Wno-pointer-sign -fformat-extensions -c /usr/src/sys/modules/tmpfs/../../fs/tmpfs/tmpfs_subr.c ld -d -warn-common -r -d -o tmpfs.ko tmpfs_vnops.o tmpfs_fifoops.o tmpfs_vfsops.o tmpfs_subr.o :> export_syms awk -f /usr/src/sys/modules/tmpfs/../../conf/kmod_syms.awk tmpfs.ko export_syms | xargs -J% objcopy % tmpfs.ko objcopy --strip-debug tmpfs.ko
予想通りtools/vnode_if.awkが実行され、下記のヘッダファイルが生成されました。
$ ls -l *.h -rw-r--r-- 1 root wheel 32302 May 1 20:40 vnode_if.h -rw-r--r-- 1 root wheel 1877 May 1 20:40 vnode_if_newproto.h -rw-r--r-- 1 root wheel 4563 May 1 20:40 vnode_if_typedef.h
vop_vectorは、上記ヘッダファイル内のvnode_if_newproto.hで定義されています。
定義は下記の通りです。
struct vop_vector { struct vop_vector *vop_default; vop_bypass_t *vop_bypass; vop_islocked_t *vop_islocked; vop_lookup_t *vop_lookup; vop_cachedlookup_t *vop_cachedlookup; vop_create_t *vop_create; vop_whiteout_t *vop_whiteout; vop_mknod_t *vop_mknod; vop_open_t *vop_open; vop_close_t *vop_close; vop_access_t *vop_access; vop_accessx_t *vop_accessx; vop_getattr_t *vop_getattr; vop_setattr_t *vop_setattr; vop_markatime_t *vop_markatime; vop_read_t *vop_read; vop_write_t *vop_write; vop_ioctl_t *vop_ioctl; vop_poll_t *vop_poll; vop_kqfilter_t *vop_kqfilter; vop_revoke_t *vop_revoke; vop_fsync_t *vop_fsync; vop_remove_t *vop_remove; vop_link_t *vop_link; vop_rename_t *vop_rename; vop_mkdir_t *vop_mkdir; vop_rmdir_t *vop_rmdir; vop_symlink_t *vop_symlink; vop_readdir_t *vop_readdir; vop_readlink_t *vop_readlink; vop_inactive_t *vop_inactive; vop_reclaim_t *vop_reclaim; vop_lock1_t *vop_lock1; vop_unlock_t *vop_unlock; vop_bmap_t *vop_bmap; vop_strategy_t *vop_strategy; vop_getwritemount_t *vop_getwritemount; vop_print_t *vop_print; vop_pathconf_t *vop_pathconf; vop_advlock_t *vop_advlock; vop_advlockasync_t *vop_advlockasync; vop_reallocblks_t *vop_reallocblks; vop_getpages_t *vop_getpages; vop_putpages_t *vop_putpages; vop_getacl_t *vop_getacl; vop_setacl_t *vop_setacl; vop_aclcheck_t *vop_aclcheck; vop_closeextattr_t *vop_closeextattr; vop_getextattr_t *vop_getextattr; vop_listextattr_t *vop_listextattr; vop_openextattr_t *vop_openextattr; vop_deleteextattr_t *vop_deleteextattr; vop_setextattr_t *vop_setextattr; vop_setlabel_t *vop_setlabel; vop_vptofh_t *vop_vptofh; vop_vptocnp_t *vop_vptocnp; };
ファイルシステムモジュールを作成する場合は、上記の構造体で定義されている関数を書いていけば良いのだと思います。
vop_vector構造体のメンバ変数の名前ですが、プレフィックスを取り除くと半数ぐらいはシステムコールに存在する関数の名前になっています。
おそらく該当するシステムコールが呼ばれた際に、この構造体にセットした関数が呼び出されるのではないかと思います。