An instance of the vnode operations structure (struct vnodeops, listed in Figure fig-vnodeops-h) exists for each different type of file system. For each vnode, the vnode field v_op is set to the pointer of the operations vector of the underlying file system.
4.5in
typedef struct vnodeops { int (*vop_open)(); int (*vop_close)(); int (*vop_read)(); int (*vop_write)(); int (*vop_ioctl)(); int (*vop_setfl)(); int (*vop_getattr)(); int (*vop_setattr)(); int (*vop_access)(); int (*vop_lookup)(); int (*vop_create)(); int (*vop_remove)(); int (*vop_link)(); int (*vop_rename)(); int (*vop_mkdir)(); int (*vop_rmdir)(); int (*vop_readdir)(); int (*vop_symlink)(); int (*vop_readlink)(); int (*vop_fsync)(); void (*vop_inactive)(); int (*vop_fid)(); void (*vop_rwlock)(); void (*vop_rwunlock)(); int (*vop_seek)(); int (*vop_cmp)(); int (*vop_frlock)(); int (*vop_space)(); int (*vop_realvp)(); int (*vop_getpage)(); int (*vop_putpage)(); int (*vop_map)(); int (*vop_addmap)(); int (*vop_delmap)(); int (*vop_poll)(); int (*vop_dump)(); int (*vop_pathconf)(); int (*vop_pageio)(); int (*vop_dumpctl)(); void (*vop_dispose)(); int (*vop_setsecattr)(); int (*vop_getsecattr)(); } vnodeops_t; |
Each field of the structure is assigned a pointer to a function that implements a particular operation on the file system in question:
Vnode operations get invoked transparently via macros that dereference the operations vector's field for that operation, and pass along the vnode and the arguments it needs. Each vnode operation has a macro associated with it, located in <sys/vnode.h>. Figure fig-vnode-mac shows as an example, the definitions for some of these calls.
6.3in
#define VOP_OPEN(vpp, mode, cr) (*(*(vpp))->v_op->vop_open)(vpp, mode, cr) #define VOP_CLOSE(vp, f, c, o, cr) (*(vp)->v_op->vop_close)(vp, f, c, o, cr) #define VOP_READ(vp, uiop, iof, cr) (*(vp)->v_op->vop_read)(vp, uiop, iof, cr) #define VOP_MKDIR(dp, p, vap, vpp, cr) (*(dp)->v_op->vop_mkdir)(dp, p, vap, vpp, cr) #define VOP_GETATTR(vp, vap, f, cr) (*(vp)->v_op->vop_getattr)(vp, vap, f, cr) #define VOP_LOOKUP(vp, cp, vpp, pnp, f, rdir, cr) \ (*(vp)->v_op->vop_lookup)(vp, cp, vpp, pnp, f, rdir, cr) #define VOP_CREATE(dvp, p, vap, ex, mode, vpp, cr) \ (*(dvp)->v_op->vop_create)(dvp, p, vap, ex, mode, vpp, cr) |
When any piece of file system code, that has a handle on a vnode, wants to call a vnode operation on it, it simply dereferences the macro, as depicted in Figure fig-vnode-mac-ex.
3.5in
int foo(vnode_t *dp, char *name, vattr_t *vap, vnode_t **vpp, cred_t *cr) { int error; error = VOP_MKDIR(dp, name, vap, vpp, cr); if (error) return (error); } |