Home | History | Annotate | Download | only in fs
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     26 
     27 #include <sys/types.h>
     28 #include <sys/atomic.h>
     29 #include <sys/kmem.h>
     30 #include <sys/mutex.h>
     31 #include <sys/errno.h>
     32 #include <sys/param.h>
     33 #include <sys/sysmacros.h>
     34 #include <sys/systm.h>
     35 #include <sys/cmn_err.h>
     36 #include <sys/debug.h>
     37 
     38 #include <sys/fem.h>
     39 #include <sys/vfs.h>
     40 #include <sys/vnode.h>
     41 #include <sys/vfs_opreg.h>
     42 
     43 #define	NNODES_DEFAULT	8	/* Default number of nodes in a fem_list */
     44 /*
     45  * fl_ntob(n) - Fem_list: number of nodes to bytes
     46  * Given the number of nodes in a fem_list return the size, in bytes,
     47  * of the fem_list structure.
     48  */
     49 #define	fl_ntob(n)	(sizeof (struct fem_list) + \
     50 			((n) - 1) * sizeof (struct fem_node))
     51 
     52 typedef enum {
     53 	FEMTYPE_NULL,	/* Uninitialized */
     54 	FEMTYPE_VNODE,
     55 	FEMTYPE_VFS,
     56 	FEMTYPE_NTYPES
     57 } femtype_t;
     58 
     59 #define	FEM_HEAD(_t) femtype[(_t)].head.fn_op.anon
     60 #define	FEM_GUARD(_t) femtype[(_t)].guard
     61 
     62 static struct fem_type_info {
     63 	struct fem_node		head;
     64 	struct fem_node		guard;
     65 	femop_t			*errf;
     66 }	femtype[FEMTYPE_NTYPES];
     67 
     68 
     69 /*
     70  * For each type, two tables - the translation offset definition, which
     71  * is used by fs_build_vector to layout the operation(s) vector; and the
     72  * guard_operation_vector which protects from stack under-run.
     73  */
     74 
     75 int fem_err();
     76 int fsem_err();
     77 
     78 
     79 #define	_FEMOPDEF(name, member)  \
     80 	{ VOPNAME_##name, offsetof(fem_t, femop_##member), NULL, fem_err }
     81 
     82 static fs_operation_trans_def_t	fem_opdef[] = {
     83 	_FEMOPDEF(OPEN,		open),
     84 	_FEMOPDEF(CLOSE,	close),
     85 	_FEMOPDEF(READ,		read),
     86 	_FEMOPDEF(WRITE,	write),
     87 	_FEMOPDEF(IOCTL,	ioctl),
     88 	_FEMOPDEF(SETFL,	setfl),
     89 	_FEMOPDEF(GETATTR,	getattr),
     90 	_FEMOPDEF(SETATTR,	setattr),
     91 	_FEMOPDEF(ACCESS,	access),
     92 	_FEMOPDEF(LOOKUP,	lookup),
     93 	_FEMOPDEF(CREATE,	create),
     94 	_FEMOPDEF(REMOVE,	remove),
     95 	_FEMOPDEF(LINK,		link),
     96 	_FEMOPDEF(RENAME,	rename),
     97 	_FEMOPDEF(MKDIR,	mkdir),
     98 	_FEMOPDEF(RMDIR,	rmdir),
     99 	_FEMOPDEF(READDIR,	readdir),
    100 	_FEMOPDEF(SYMLINK,	symlink),
    101 	_FEMOPDEF(READLINK,	readlink),
    102 	_FEMOPDEF(FSYNC,	fsync),
    103 	_FEMOPDEF(INACTIVE,	inactive),
    104 	_FEMOPDEF(FID,		fid),
    105 	_FEMOPDEF(RWLOCK,	rwlock),
    106 	_FEMOPDEF(RWUNLOCK,	rwunlock),
    107 	_FEMOPDEF(SEEK,		seek),
    108 	_FEMOPDEF(CMP,		cmp),
    109 	_FEMOPDEF(FRLOCK,	frlock),
    110 	_FEMOPDEF(SPACE,	space),
    111 	_FEMOPDEF(REALVP,	realvp),
    112 	_FEMOPDEF(GETPAGE,	getpage),
    113 	_FEMOPDEF(PUTPAGE,	putpage),
    114 	_FEMOPDEF(MAP,		map),
    115 	_FEMOPDEF(ADDMAP,	addmap),
    116 	_FEMOPDEF(DELMAP,	delmap),
    117 	_FEMOPDEF(POLL,		poll),
    118 	_FEMOPDEF(DUMP,		dump),
    119 	_FEMOPDEF(PATHCONF,	pathconf),
    120 	_FEMOPDEF(PAGEIO,	pageio),
    121 	_FEMOPDEF(DUMPCTL,	dumpctl),
    122 	_FEMOPDEF(DISPOSE,	dispose),
    123 	_FEMOPDEF(SETSECATTR,	setsecattr),
    124 	_FEMOPDEF(GETSECATTR,	getsecattr),
    125 	_FEMOPDEF(SHRLOCK,	shrlock),
    126 	_FEMOPDEF(VNEVENT,	vnevent),
    127 	{ NULL, 0, NULL, NULL }
    128 };
    129 
    130 
    131 #define	_FEMGUARD(name, ignore)  \
    132 	{ VOPNAME_##name, (femop_t *)fem_err }
    133 
    134 static struct fs_operation_def fem_guard_ops[] = {
    135 	_FEMGUARD(OPEN,		open),
    136 	_FEMGUARD(CLOSE,	close),
    137 	_FEMGUARD(READ,		read),
    138 	_FEMGUARD(WRITE,	write),
    139 	_FEMGUARD(IOCTL,	ioctl),
    140 	_FEMGUARD(SETFL,	setfl),
    141 	_FEMGUARD(GETATTR,	getattr),
    142 	_FEMGUARD(SETATTR,	setattr),
    143 	_FEMGUARD(ACCESS,	access),
    144 	_FEMGUARD(LOOKUP,	lookup),
    145 	_FEMGUARD(CREATE,	create),
    146 	_FEMGUARD(REMOVE,	remove),
    147 	_FEMGUARD(LINK,		link),
    148 	_FEMGUARD(RENAME,	rename),
    149 	_FEMGUARD(MKDIR,	mkdir),
    150 	_FEMGUARD(RMDIR,	rmdir),
    151 	_FEMGUARD(READDIR,	readdir),
    152 	_FEMGUARD(SYMLINK,	symlink),
    153 	_FEMGUARD(READLINK,	readlink),
    154 	_FEMGUARD(FSYNC,	fsync),
    155 	_FEMGUARD(INACTIVE,	inactive),
    156 	_FEMGUARD(FID,		fid),
    157 	_FEMGUARD(RWLOCK,	rwlock),
    158 	_FEMGUARD(RWUNLOCK,	rwunlock),
    159 	_FEMGUARD(SEEK,		seek),
    160 	_FEMGUARD(CMP,		cmp),
    161 	_FEMGUARD(FRLOCK,	frlock),
    162 	_FEMGUARD(SPACE,	space),
    163 	_FEMGUARD(REALVP,	realvp),
    164 	_FEMGUARD(GETPAGE,	getpage),
    165 	_FEMGUARD(PUTPAGE,	putpage),
    166 	_FEMGUARD(MAP,		map),
    167 	_FEMGUARD(ADDMAP,	addmap),
    168 	_FEMGUARD(DELMAP,	delmap),
    169 	_FEMGUARD(POLL,		poll),
    170 	_FEMGUARD(DUMP,		dump),
    171 	_FEMGUARD(PATHCONF,	pathconf),
    172 	_FEMGUARD(PAGEIO,	pageio),
    173 	_FEMGUARD(DUMPCTL,	dumpctl),
    174 	_FEMGUARD(DISPOSE,	dispose),
    175 	_FEMGUARD(SETSECATTR,	setsecattr),
    176 	_FEMGUARD(GETSECATTR,	getsecattr),
    177 	_FEMGUARD(SHRLOCK,	shrlock),
    178 	_FEMGUARD(VNEVENT,	vnevent),
    179 	{ NULL, NULL }
    180 };
    181 
    182 
    183 #define	_FSEMOPDEF(name, member)  \
    184 	{ VFSNAME_##name, offsetof(fsem_t, fsemop_##member), NULL, fsem_err }
    185 
    186 static fs_operation_trans_def_t fsem_opdef[] = {
    187 	_FSEMOPDEF(MOUNT, 	mount),
    188 	_FSEMOPDEF(UNMOUNT,	unmount),
    189 	_FSEMOPDEF(ROOT,	root),
    190 	_FSEMOPDEF(STATVFS,	statvfs),
    191 	_FSEMOPDEF(SYNC,	sync),
    192 	_FSEMOPDEF(VGET,	vget),
    193 	_FSEMOPDEF(MOUNTROOT,	mountroot),
    194 	_FSEMOPDEF(FREEVFS,	freevfs),
    195 	_FSEMOPDEF(VNSTATE,	vnstate),
    196 	{ NULL, 0, NULL, NULL }
    197 };
    198 
    199 #define	_FSEMGUARD(name, ignore)  \
    200 	{ VFSNAME_##name, (femop_t *)fsem_err }
    201 
    202 static struct fs_operation_def fsem_guard_ops[] = {
    203 	_FSEMGUARD(MOUNT, 	mount),
    204 	_FSEMGUARD(UNMOUNT,	unmount),
    205 	_FSEMGUARD(ROOT,	root),
    206 	_FSEMGUARD(STATVFS,	statvfs),
    207 	_FSEMGUARD(SYNC,	sync),
    208 	_FSEMGUARD(VGET,	vget),
    209 	_FSEMGUARD(MOUNTROOT,	mountroot),
    210 	_FSEMGUARD(FREEVFS,	freevfs),
    211 	_FSEMGUARD(VNSTATE,	vnstate),
    212 	{ NULL, NULL}
    213 };
    214 
    215 
    216 /*
    217  * vsop_find, vfsop_find -
    218  *
    219  * These macros descend the stack until they find either a basic
    220  * vnode/vfs operation [ indicated by a null fn_available ] or a
    221  * stacked item where this method is non-null [_vsop].
    222  *
    223  * The DEBUG one is written with a single function which manually applies
    224  * the structure offsets.  It can have additional debugging support.
    225  */
    226 
    227 #ifndef DEBUG
    228 
    229 #define	vsop_find(ap, func, funct, arg0, _vop, _vsop) \
    230 for (;;) { \
    231 	if ((ap)->fa_fnode->fn_available == NULL) { \
    232 		*(func) = (funct (*)())((ap)->fa_fnode->fn_op.vnode->_vop); \
    233 		*(arg0) = (void *)(ap)->fa_vnode.vp; \
    234 		break;	\
    235 	} else if ((*(func) = (funct (*)())((ap)->fa_fnode->fn_op.fem->_vsop))\
    236 		    != NULL) { \
    237 		*(arg0) = (void *) (ap); \
    238 		break;	\
    239 	} else { \
    240 		(ap)->fa_fnode--; \
    241 	} \
    242 } \
    243 
    244 #define	vfsop_find(ap, func, funct, arg0, _vop, _vsop) \
    245 for (;;) { \
    246 	if ((ap)->fa_fnode->fn_available == NULL) { \
    247 		*(func) = (funct (*)())((ap)->fa_fnode->fn_op.vfs->_vop); \
    248 		*(arg0) = (void *)(ap)->fa_vnode.vp; \
    249 		break; \
    250 	} else if ((*(func) = (funct (*)())((ap)->fa_fnode->fn_op.fsem->_vsop))\
    251 		    != NULL) { \
    252 		*(arg0) = (void *) (ap); \
    253 		break; \
    254 	} else { \
    255 		(ap)->fa_fnode--; \
    256 	} \
    257 } \
    258 
    259 #else
    260 
    261 #define	vsop_find(ap, func, funct, arg0, _vop, _vsop) \
    262 	*(arg0) = _op_find((ap), (void **)(func), \
    263 			offsetof(vnodeops_t, _vop), offsetof(fem_t, _vsop))
    264 
    265 #define	vfsop_find(ap, func, funct, arg0, _fop, _fsop) \
    266 	*(arg0) = _op_find((ap), (void **)(func), \
    267 			offsetof(vfsops_t, _fop), offsetof(fsem_t, _fsop))
    268 
    269 static void *
    270 _op_find(femarg_t *ap, void **fp, int offs0, int offs1)
    271 {
    272 	void *ptr;
    273 	for (;;) {
    274 		struct fem_node	*fnod = ap->fa_fnode;
    275 		if (fnod->fn_available == NULL) {
    276 			*fp = *(void **)((char *)fnod->fn_op.anon + offs0);
    277 			ptr = (void *)(ap->fa_vnode.anon);
    278 			break;
    279 		} else if ((*fp = *(void **)((char *)fnod->fn_op.anon+offs1))
    280 		    != NULL) {
    281 			ptr = (void *)(ap);
    282 			break;
    283 		} else {
    284 			ap->fa_fnode--;
    285 		}
    286 	}
    287 	return (ptr);
    288 }
    289 #endif
    290 
    291 static fem_t *
    292 fem_alloc()
    293 {
    294 	fem_t	*p;
    295 
    296 	p = (fem_t *)kmem_alloc(sizeof (*p), KM_SLEEP);
    297 	return (p);
    298 }
    299 
    300 void
    301 fem_free(fem_t *p)
    302 {
    303 	kmem_free(p, sizeof (*p));
    304 }
    305 
    306 static fsem_t *
    307 fsem_alloc()
    308 {
    309 	fsem_t	*p;
    310 
    311 	p = (fsem_t *)kmem_alloc(sizeof (*p), KM_SLEEP);
    312 	return (p);
    313 }
    314 
    315 void
    316 fsem_free(fsem_t *p)
    317 {
    318 	kmem_free(p, sizeof (*p));
    319 }
    320 
    321 
    322 /*
    323  * fem_get, fem_release - manage reference counts on the stack.
    324  *
    325  * The list of monitors can be updated while operations are in
    326  * progress on the object.
    327  *
    328  * The reference count facilitates this by counting the number of
    329  * current accessors, and deconstructing the list when it is exhausted.
    330  *
    331  * fem_lock() is required to:
    332  *	look at femh_list
    333  *	update what femh_list points to
    334  *	update femh_list
    335  *	increase femh_list->feml_refc.
    336  *
    337  * the feml_refc can decrement without holding the lock;
    338  * when feml_refc becomes zero, the list is destroyed.
    339  *
    340  */
    341 
    342 static struct fem_list *
    343 fem_lock(struct fem_head *fp)
    344 {
    345 	struct fem_list	*sp = NULL;
    346 
    347 	ASSERT(fp != NULL);
    348 	mutex_enter(&fp->femh_lock);
    349 	sp = fp->femh_list;
    350 	return (sp);
    351 }
    352 
    353 static void
    354 fem_unlock(struct fem_head *fp)
    355 {
    356 	ASSERT(fp != NULL);
    357 	mutex_exit(&fp->femh_lock);
    358 }
    359 
    360 /*
    361  * Addref can only be called while its head->lock is held.
    362  */
    363 
    364 static void
    365 fem_addref(struct fem_list *sp)
    366 {
    367 	atomic_add_32(&sp->feml_refc, 1);
    368 }
    369 
    370 static uint32_t
    371 fem_delref(struct fem_list *sp)
    372 {
    373 	return (atomic_add_32_nv(&sp->feml_refc, -1));
    374 }
    375 
    376 static struct fem_list *
    377 fem_get(struct fem_head *fp)
    378 {
    379 	struct fem_list *sp = NULL;
    380 
    381 	if (fp != NULL) {
    382 		if ((sp = fem_lock(fp)) != NULL) {
    383 			fem_addref(sp);
    384 		}
    385 		fem_unlock(fp);
    386 	}
    387 	return (sp);
    388 }
    389 
    390 static void
    391 fem_release(struct fem_list *sp)
    392 {
    393 	int	i;
    394 
    395 	ASSERT(sp->feml_refc != 0);
    396 	if (fem_delref(sp) == 0) {
    397 		/*
    398 		 * Before freeing the list, we need to release the
    399 		 * caller-provided data.
    400 		 */
    401 		for (i = sp->feml_tos; i > 0; i--) {
    402 			struct fem_node *fnp = &sp->feml_nodes[i];
    403 
    404 			if (fnp->fn_av_rele)
    405 				(*(fnp->fn_av_rele))(fnp->fn_available);
    406 		}
    407 		kmem_free(sp, fl_ntob(sp->feml_ssize));
    408 	}
    409 }
    410 
    411 
    412 /*
    413  * These are the 'head' operations which perform the interposition.
    414  *
    415  * This set must be 1:1, onto with the (vnodeops, vfsos).
    416  *
    417  * If there is a desire to globally disable interposition for a particular
    418  * method, the corresponding 'head' routine should unearth the base method
    419  * and invoke it directly rather than bypassing the function.
    420  *
    421  * All the functions are virtually the same, save for names, types & args.
    422  *  1. get a reference to the monitor stack for this object.
    423  *  2. store the top of stack into the femarg structure.
    424  *  3. store the basic object (vnode *, vnode **, vfs *) in the femarg struc.
    425  *  4. invoke the "top" method for this object.
    426  *  5. release the reference to the monitor stack.
    427  *
    428  */
    429 
    430 static int
    431 vhead_open(vnode_t **vpp, int mode, cred_t *cr, caller_context_t *ct)
    432 {
    433 	femarg_t	farg;
    434 	struct fem_list	*femsp;
    435 	int		(*func)();
    436 	void		*arg0;
    437 	int		errc;
    438 
    439 	if ((femsp = fem_lock((*vpp)->v_femhead)) == NULL) {
    440 		func = (int (*)()) ((*vpp)->v_op->vop_open);
    441 		arg0 = (void *)vpp;
    442 		fem_unlock((*vpp)->v_femhead);
    443 		errc = (*func)(arg0, mode, cr, ct);
    444 	} else {
    445 		fem_addref(femsp);
    446 		fem_unlock((*vpp)->v_femhead);
    447 		farg.fa_vnode.vpp = vpp;
    448 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
    449 		vsop_find(&farg, &func, int, &arg0, vop_open, femop_open);
    450 		errc = (*func)(arg0, mode, cr, ct);
    451 		fem_release(femsp);
    452 	}
    453 	return (errc);
    454 }
    455 
    456 static int
    457 vhead_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
    458 	caller_context_t *ct)
    459 {
    460 	femarg_t	farg;
    461 	struct fem_list	*femsp;
    462 	int		(*func)();
    463 	void		*arg0;
    464 	int		errc;
    465 
    466 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
    467 		func = (int (*)()) (vp->v_op->vop_close);
    468 		arg0 = vp;
    469 		fem_unlock(vp->v_femhead);
    470 		errc = (*func)(arg0, flag, count, offset, cr, ct);
    471 	} else {
    472 		fem_addref(femsp);
    473 		fem_unlock(vp->v_femhead);
    474 		farg.fa_vnode.vp = vp;
    475 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
    476 		vsop_find(&farg, &func, int, &arg0, vop_close, femop_close);
    477 		errc = (*func)(arg0, flag, count, offset, cr, ct);
    478 		fem_release(femsp);
    479 	}
    480 	return (errc);
    481 }
    482 
    483 static int
    484 vhead_read(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr,
    485 	caller_context_t *ct)
    486 {
    487 	femarg_t	farg;
    488 	struct fem_list	*femsp;
    489 	int		(*func)();
    490 	void		*arg0;
    491 	int		errc;
    492 
    493 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
    494 		func = (int (*)()) (vp->v_op->vop_read);
    495 		arg0 = vp;
    496 		fem_unlock(vp->v_femhead);
    497 		errc = (*func)(arg0, uiop, ioflag, cr, ct);
    498 	} else {
    499 		fem_addref(femsp);
    500 		fem_unlock(vp->v_femhead);
    501 		farg.fa_vnode.vp = vp;
    502 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
    503 		vsop_find(&farg, &func, int, &arg0, vop_read, femop_read);
    504 		errc = (*func)(arg0, uiop, ioflag, cr, ct);
    505 		fem_release(femsp);
    506 	}
    507 	return (errc);
    508 }
    509 
    510 static int
    511 vhead_write(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr,
    512 	caller_context_t *ct)
    513 {
    514 	femarg_t	farg;
    515 	struct fem_list	*femsp;
    516 	int		(*func)();
    517 	void		*arg0;
    518 	int		errc;
    519 
    520 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
    521 		func = (int (*)()) (vp->v_op->vop_write);
    522 		arg0 = vp;
    523 		fem_unlock(vp->v_femhead);
    524 		errc = (*func)(arg0, uiop, ioflag, cr, ct);
    525 	} else {
    526 		fem_addref(femsp);
    527 		fem_unlock(vp->v_femhead);
    528 		farg.fa_vnode.vp = vp;
    529 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
    530 		vsop_find(&farg, &func, int, &arg0, vop_write, femop_write);
    531 		errc = (*func)(arg0, uiop, ioflag, cr, ct);
    532 		fem_release(femsp);
    533 	}
    534 	return (errc);
    535 }
    536 
    537 static int
    538 vhead_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr,
    539 	int *rvalp, caller_context_t *ct)
    540 {
    541 	femarg_t	farg;
    542 	struct fem_list	*femsp;
    543 	int		(*func)();
    544 	void		*arg0;
    545 	int		errc;
    546 
    547 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
    548 		func = (int (*)()) (vp->v_op->vop_ioctl);
    549 		arg0 = vp;
    550 		fem_unlock(vp->v_femhead);
    551 		errc = (*func)(arg0, cmd, arg, flag, cr, rvalp, ct);
    552 	} else {
    553 		fem_addref(femsp);
    554 		fem_unlock(vp->v_femhead);
    555 		farg.fa_vnode.vp = vp;
    556 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
    557 		vsop_find(&farg, &func, int, &arg0, vop_ioctl, femop_ioctl);
    558 		errc = (*func)(arg0, cmd, arg, flag, cr, rvalp, ct);
    559 		fem_release(femsp);
    560 	}
    561 	return (errc);
    562 }
    563 
    564 static int
    565 vhead_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr,
    566 	caller_context_t *ct)
    567 {
    568 	femarg_t	farg;
    569 	struct fem_list	*femsp;
    570 	int		(*func)();
    571 	void		*arg0;
    572 	int		errc;
    573 
    574 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
    575 		func = (int (*)()) (vp->v_op->vop_setfl);
    576 		arg0 = vp;
    577 		fem_unlock(vp->v_femhead);
    578 		errc = (*func)(arg0, oflags, nflags, cr, ct);
    579 	} else {
    580 		fem_addref(femsp);
    581 		fem_unlock(vp->v_femhead);
    582 		farg.fa_vnode.vp = vp;
    583 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
    584 		vsop_find(&farg, &func, int, &arg0, vop_setfl, femop_setfl);
    585 		errc = (*func)(arg0, oflags, nflags, cr, ct);
    586 		fem_release(femsp);
    587 	}
    588 	return (errc);
    589 }
    590 
    591 static int
    592 vhead_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
    593 	caller_context_t *ct)
    594 {
    595 	femarg_t	farg;
    596 	struct fem_list	*femsp;
    597 	int		(*func)();
    598 	void		*arg0;
    599 	int		errc;
    600 
    601 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
    602 		func = (int (*)()) (vp->v_op->vop_getattr);
    603 		arg0 = vp;
    604 		fem_unlock(vp->v_femhead);
    605 		errc = (*func)(arg0, vap, flags, cr, ct);
    606 	} else {
    607 		fem_addref(femsp);
    608 		fem_unlock(vp->v_femhead);
    609 		farg.fa_vnode.vp = vp;
    610 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
    611 		vsop_find(&farg, &func, int, &arg0, vop_getattr,
    612 		    femop_getattr);
    613 		errc = (*func)(arg0, vap, flags, cr, ct);
    614 		fem_release(femsp);
    615 	}
    616 	return (errc);
    617 }
    618 
    619 static int
    620 vhead_setattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
    621 	caller_context_t *ct)
    622 {
    623 	femarg_t	farg;
    624 	struct fem_list	*femsp;
    625 	int		(*func)();
    626 	void		*arg0;
    627 	int		errc;
    628 
    629 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
    630 		func = (int (*)()) (vp->v_op->vop_setattr);
    631 		arg0 = vp;
    632 		fem_unlock(vp->v_femhead);
    633 		errc = (*func)(arg0, vap, flags, cr, ct);
    634 	} else {
    635 		fem_addref(femsp);
    636 		fem_unlock(vp->v_femhead);
    637 		farg.fa_vnode.vp = vp;
    638 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
    639 		vsop_find(&farg, &func, int, &arg0, vop_setattr,
    640 		    femop_setattr);
    641 		errc = (*func)(arg0, vap, flags, cr, ct);
    642 		fem_release(femsp);
    643 	}
    644 	return (errc);
    645 }
    646 
    647 static int
    648 vhead_access(vnode_t *vp, int mode, int flags, cred_t *cr,
    649 	caller_context_t *ct)
    650 {
    651 	femarg_t	farg;
    652 	struct fem_list	*femsp;
    653 	int		(*func)();
    654 	void		*arg0;
    655 	int		errc;
    656 
    657 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
    658 		func = (int (*)()) (vp->v_op->vop_access);
    659 		arg0 = vp;
    660 		fem_unlock(vp->v_femhead);
    661 		errc = (*func)(arg0, mode, flags, cr, ct);
    662 	} else {
    663 		fem_addref(femsp);
    664 		fem_unlock(vp->v_femhead);
    665 		farg.fa_vnode.vp = vp;
    666 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
    667 		vsop_find(&farg, &func, int, &arg0, vop_access,
    668 		    femop_access);
    669 		errc = (*func)(arg0, mode, flags, cr, ct);
    670 		fem_release(femsp);
    671 	}
    672 	return (errc);
    673 }
    674 
    675 static int
    676 vhead_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp,
    677 	int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
    678 	int *direntflags, pathname_t *realpnp)
    679 {
    680 	femarg_t	farg;
    681 	struct fem_list	*femsp;
    682 	int		(*func)();
    683 	void		*arg0;
    684 	int		errc;
    685 
    686 	if ((femsp = fem_lock(dvp->v_femhead)) == NULL) {
    687 		func = (int (*)()) (dvp->v_op->vop_lookup);
    688 		arg0 = dvp;
    689 		fem_unlock(dvp->v_femhead);
    690 		errc = (*func)(arg0, nm, vpp, pnp, flags, rdir, cr, ct,
    691 		    direntflags, realpnp);
    692 	} else {
    693 		fem_addref(femsp);
    694 		fem_unlock(dvp->v_femhead);
    695 		farg.fa_vnode.vp = dvp;
    696 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
    697 		vsop_find(&farg, &func, int, &arg0, vop_lookup,
    698 		    femop_lookup);
    699 		errc = (*func)(arg0, nm, vpp, pnp, flags, rdir, cr, ct,
    700 		    direntflags, realpnp);
    701 		fem_release(femsp);
    702 	}
    703 	return (errc);
    704 }
    705 
    706 static int
    707 vhead_create(vnode_t *dvp, char *name, vattr_t *vap, vcexcl_t excl,
    708 	int mode, vnode_t **vpp, cred_t *cr, int flag, caller_context_t *ct,
    709 	vsecattr_t *vsecp)
    710 {
    711 	femarg_t	farg;
    712 	struct fem_list	*femsp;
    713 	int		(*func)();
    714 	void		*arg0;
    715 	int		errc;
    716 
    717 	if ((femsp = fem_lock(dvp->v_femhead)) == NULL) {
    718 		func = (int (*)()) (dvp->v_op->vop_create);
    719 		arg0 = dvp;
    720 		fem_unlock(dvp->v_femhead);
    721 		errc = (*func)(arg0, name, vap, excl, mode, vpp, cr, flag,
    722 		    ct, vsecp);
    723 	} else {
    724 		fem_addref(femsp);
    725 		fem_unlock(dvp->v_femhead);
    726 		farg.fa_vnode.vp = dvp;
    727 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
    728 		vsop_find(&farg, &func, int, &arg0, vop_create,
    729 		    femop_create);
    730 		errc = (*func)(arg0, name, vap, excl, mode, vpp, cr, flag,
    731 		    ct, vsecp);
    732 		fem_release(femsp);
    733 	}
    734 	return (errc);
    735 }
    736 
    737 static int
    738 vhead_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct,
    739 	int flags)
    740 {
    741 	femarg_t	farg;
    742 	struct fem_list	*femsp;
    743 	int		(*func)();
    744 	void		*arg0;
    745 	int		errc;
    746 
    747 	if ((femsp = fem_lock(dvp->v_femhead)) == NULL) {
    748 		func = (int (*)()) (dvp->v_op->vop_remove);
    749 		arg0 = dvp;
    750 		fem_unlock(dvp->v_femhead);
    751 		errc = (*func)(arg0, nm, cr, ct, flags);
    752 	} else {
    753 		fem_addref(femsp);
    754 		fem_unlock(dvp->v_femhead);
    755 		farg.fa_vnode.vp = dvp;
    756 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
    757 		vsop_find(&farg, &func, int, &arg0, vop_remove,
    758 		    femop_remove);
    759 		errc = (*func)(arg0, nm, cr, ct, flags);
    760 		fem_release(femsp);
    761 	}
    762 	return (errc);
    763 }
    764 
    765 static int
    766 vhead_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr,
    767 	caller_context_t *ct, int flags)
    768 {
    769 	femarg_t	farg;
    770 	struct fem_list	*femsp;
    771 	int		(*func)();
    772 	void		*arg0;
    773 	int		errc;
    774 
    775 	if ((femsp = fem_lock(tdvp->v_femhead)) == NULL) {
    776 		func = (int (*)()) (tdvp->v_op->vop_link);
    777 		arg0 = tdvp;
    778 		fem_unlock(tdvp->v_femhead);
    779 		errc = (*func)(arg0, svp, tnm, cr, ct, flags);
    780 	} else {
    781 		fem_addref(femsp);
    782 		fem_unlock(tdvp->v_femhead);
    783 		farg.fa_vnode.vp = tdvp;
    784 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
    785 		vsop_find(&farg, &func, int, &arg0, vop_link, femop_link);
    786 		errc = (*func)(arg0, svp, tnm, cr, ct, flags);
    787 		fem_release(femsp);
    788 	}
    789 	return (errc);
    790 }
    791 
    792 static int
    793 vhead_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
    794 	cred_t *cr, caller_context_t *ct, int flags)
    795 {
    796 	femarg_t	farg;
    797 	struct fem_list	*femsp;
    798 	int		(*func)();
    799 	void		*arg0;
    800 	int		errc;
    801 
    802 	if ((femsp = fem_lock(sdvp->v_femhead)) == NULL) {
    803 		func = (int (*)()) (sdvp->v_op->vop_rename);
    804 		arg0 = sdvp;
    805 		fem_unlock(sdvp->v_femhead);
    806 		errc = (*func)(arg0, snm, tdvp, tnm, cr, ct, flags);
    807 	} else {
    808 		fem_addref(femsp);
    809 		fem_unlock(sdvp->v_femhead);
    810 		farg.fa_vnode.vp = sdvp;
    811 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
    812 		vsop_find(&farg, &func, int, &arg0, vop_rename,
    813 		    femop_rename);
    814 		errc = (*func)(arg0, snm, tdvp, tnm, cr, ct, flags);
    815 		fem_release(femsp);
    816 	}
    817 	return (errc);
    818 }
    819 
    820 static int
    821 vhead_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t **vpp,
    822 	cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp)
    823 {
    824 	femarg_t	farg;
    825 	struct fem_list	*femsp;
    826 	int		(*func)();
    827 	void		*arg0;
    828 	int		errc;
    829 
    830 	if ((femsp = fem_lock(dvp->v_femhead)) == NULL) {
    831 		func = (int (*)()) (dvp->v_op->vop_mkdir);
    832 		arg0 = dvp;
    833 		fem_unlock(dvp->v_femhead);
    834 		errc = (*func)(arg0, dirname, vap, vpp, cr, ct, flags, vsecp);
    835 	} else {
    836 		fem_addref(femsp);
    837 		fem_unlock(dvp->v_femhead);
    838 		farg.fa_vnode.vp = dvp;
    839 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
    840 		vsop_find(&farg, &func, int, &arg0, vop_mkdir, femop_mkdir);
    841 		errc = (*func)(arg0, dirname, vap, vpp, cr, ct, flags, vsecp);
    842 		fem_release(femsp);
    843 	}
    844 	return (errc);
    845 }
    846 
    847 static int
    848 vhead_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
    849 	caller_context_t *ct, int flags)
    850 {
    851 	femarg_t	farg;
    852 	struct fem_list	*femsp;
    853 	int		(*func)();
    854 	void		*arg0;
    855 	int		errc;
    856 
    857 	if ((femsp = fem_lock(dvp->v_femhead)) == NULL) {
    858 		func = (int (*)()) (dvp->v_op->vop_rmdir);
    859 		arg0 = dvp;
    860 		fem_unlock(dvp->v_femhead);
    861 		errc = (*func)(arg0, nm, cdir, cr, ct, flags);
    862 	} else {
    863 		fem_addref(femsp);
    864 		fem_unlock(dvp->v_femhead);
    865 		farg.fa_vnode.vp = dvp;
    866 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
    867 		vsop_find(&farg, &func, int, &arg0, vop_rmdir, femop_rmdir);
    868 		errc = (*func)(arg0, nm, cdir, cr, ct, flags);
    869 		fem_release(femsp);
    870 	}
    871 	return (errc);
    872 }
    873 
    874 static int
    875 vhead_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp,
    876 	caller_context_t *ct, int flags)
    877 {
    878 	femarg_t	farg;
    879 	struct fem_list	*femsp;
    880 	int		(*func)();
    881 	void		*arg0;
    882 	int		errc;
    883 
    884 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
    885 		func = (int (*)()) (vp->v_op->vop_readdir);
    886 		arg0 = vp;
    887 		fem_unlock(vp->v_femhead);
    888 		errc = (*func)(arg0, uiop, cr, eofp, ct, flags);
    889 	} else {
    890 		fem_addref(femsp);
    891 		fem_unlock(vp->v_femhead);
    892 		farg.fa_vnode.vp = vp;
    893 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
    894 		vsop_find(&farg, &func, int, &arg0, vop_readdir,
    895 		    femop_readdir);
    896 		errc = (*func)(arg0, uiop, cr, eofp, ct, flags);
    897 		fem_release(femsp