Node: lower layer code, Next: vfs interface integration, Previous: lower layer structures, Up: Implementation
This section will guide you through your filesystem code general structure based on the existing filesystem. The easiest way to create good global filesystem environment is to copy existing arrangements. Your new filesystem should probably go into the ufs/myfs/ directory if it's an Hard Drive filesystem.
The first important file is myfs_extern.h. It's the file that will be included in the vfs interface so it must contains all the definitions of vfsops, vnops, and others global declarations. These declarations must be inner __BEGIN_DECLS and __END_DECLS macros. It must also contain the declaration as extern of the vnops pointer types. example :
__BEGIN_DECLS /* myfs_vfsops.c */ int myfs_mountroot(void); int myfs_mount(struct mount *, const char *, void *, struct nameidata *, struct proc *); int myfs_reload(struct mount *, struct ucred *, struct proc *); ... /* myfs_vnops.c */ int myfs_create(void *); int myfs_mknod(void *); int myfs_open(void *); ... __END_DECLS extern int (**myfs_vnodeop_p)(void *);
// vfs interface operations struct vfsops myfs_vfsops = { myfs_mount, myfs_start, myfs_unmount, myfs_root, myfs_quotactl, myfs_statfs, myfs_sync, myfs_vget, myfs_fhtovp, myfs_vptofh, myfs_init, myfs_sysctl, myfs_check_export, vfs_stdextattrctl };
int myfs_foo(arg, bar) struct vfs_arg* arg; int bar; { ...
If you don't want to implement a particular vfs operation that is not
necessary, don't
hesitate to return an EOPNOTSUPP error so the error will be reported to
the user. If on the other hand, the system want you to make a silly
thing that will corrupt your filesystem simply do a kernel panic. Even
if it's not smart, this way you will not have a corrupted filesystem and
you will be able to easily see the debugging of the kernel and what
happened. This way, if you think it's a kernel bug, you will be able to
contact OpenBSD core team that will help you finding and debugging the
problem.
The last part is the vnops. The work is usually done in myfs_vnops.c. Unlike
the vfsops part, we will begin by the implementation of the
operations. All the functions have the same
signature (int func (void *)) so be careful to cast the void * to the
corresponding struct before using it. If you don't do that
the kernel will remind you to do it. The above example is the
standard coding style in the OpenBSD kernel. Take care to use ap-> and
not v-> in future treatments.
int myfs_foo(v) void *v; { struct vop_foo_args /* { struct vnode *a_dvp; int a; } */ *ap = v; printf (``arg->a=%i'', ap->a); ...
/* Global vfs vnode operations for myfs. */ int (**myfs_vnodeop_p)(void *); struct vnodeopv_entry_desc myfs_vnodeop_entries[] = { { &vop_default_desc, vn_default_error }, { &vop_lookup_desc, myfs_lookup }, /* lookup */ { &vop_create_desc, myfs_create }, /* create */ { &vop_mknod_desc, myfs_mknod }, /* mknod */ { &vop_open_desc, myfs_open }, /* open */ { &vop_close_desc, myfs_close }, /* close */ { &vop_access_desc, myfs_access }, /* access */ { &vop_getattr_desc, myfs_getattr }, /* getattr */ { &vop_setattr_desc, myfs_setattr }, /* setattr */ { &vop_read_desc, myfs_read }, /* read */ { &vop_write_desc, myfs_write }, /* write */ ... { NULL, NULL } }; struct vnodeopv_desc myfs_vnodeop_opv_desc = { &myfs_vnodeop_p, myfs_vnodeop_entries };This is the myfs_vnodeop_opv_desc that will be used by the vfs interface. For vnops if you do not want to support an operation you simply do not need to include it in the available entries. The vfs will only call entries put in the descs vector. Otherwise it will return a EINVALL error.