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 2007 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 #pragma ident	"@(#)fem.c	1.15	07/10/25 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);
    898 	}
    899 	return (errc);
    900 }
    901 
    902 static int
    903 vhead_symlink(vnode_t *dvp, char *linkname, vattr_t *vap, char *target,
    904 	cred_t *cr, caller_context_t *ct, int flags)
    905 {
    906 	femarg_t	farg;
    907 	struct fem_list	*femsp;
    908 	int		(*func)();
    909 	void		*arg0;
    910 	int		errc;
    911 
    912 	if ((femsp = fem_lock(dvp->v_femhead)) == NULL) {
    913 		func = (int (*)()) (dvp->v_op->vop_symlink);
    914 		arg0 = dvp;
    915 		fem_unlock(dvp->v_femhead);
    916 		errc = (*func)(arg0, linkname, vap, target, cr, ct, flags);
    917 	} else {
    918 		fem_addref(femsp);
    919 		fem_unlock(dvp->v_femhead);
    920 		farg.fa_vnode.vp = dvp;
    921 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
    922 		vsop_find(&farg, &func, int, &arg0, vop_symlink,
    923 			femop_symlink);
    924 		errc = (*func)(arg0, linkname, vap, target, cr, ct, flags);
    925 		fem_release(femsp);
    926 	}
    927 	return (errc);
    928 }
    929 
    930 static int
    931 vhead_readlink(vnode_t *vp, uio_t *uiop, cred_t *cr, caller_context_t *ct)
    932 {
    933 	femarg_t	farg;
    934 	struct fem_list	*femsp;
    935 	int		(*func)();
    936 	void		*arg0;
    937 	int		errc;
    938 
    939 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
    940 		func = (int (*)()) (vp->v_op->vop_readlink);
    941 		arg0 = vp;
    942 		fem_unlock(vp->v_femhead);
    943 		errc = (*func)(arg0, uiop, cr, ct);
    944 	} else {
    945 		fem_addref(femsp);
    946 		fem_unlock(vp->v_femhead);
    947 		farg.fa_vnode.vp = vp;
    948 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
    949 		vsop_find(&farg, &func, int, &arg0, vop_readlink,
    950 			femop_readlink);
    951 		errc = (*func)(arg0, uiop, cr, ct);
    952 		fem_release(femsp);
    953 	}
    954 	return (errc);
    955 }
    956 
    957 static int
    958 vhead_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
    959 {
    960 	femarg_t	farg;
    961 	struct fem_list	*femsp;
    962 	int		(*func)();
    963 	void		*arg0;
    964 	int		errc;
    965 
    966 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
    967 		func = (int (*)()) (vp->v_op->vop_fsync);
    968 		arg0 = vp;
    969 		fem_unlock(vp->v_femhead);
    970 		errc = (*func)(arg0, syncflag, cr, ct);
    971 	} else {
    972 		fem_addref(femsp);
    973 		fem_unlock(vp->v_femhead);
    974 		farg.fa_vnode.vp = vp;
    975 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
    976 		vsop_find(&farg, &func, int, &arg0, vop_fsync, femop_fsync);
    977 		errc = (*func)(arg0, syncflag, cr, ct);
    978 		fem_release(femsp);
    979 	}
    980 	return (errc);
    981 }
    982 
    983 static void
    984 vhead_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
    985 {
    986 	femarg_t	farg;
    987 	struct fem_list	*femsp;
    988 	void		(*func)();
    989 	void		*arg0;
    990 
    991 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
    992 		func = (void (*)()) (vp->v_op->vop_inactive);
    993 		arg0 = vp;
    994 		fem_unlock(vp->v_femhead);
    995 		(*func)(arg0, cr, ct);
    996 	} else {
    997 		fem_addref(femsp);
    998 		fem_unlock(vp->v_femhead);
    999 		farg.fa_vnode.vp = vp;
   1000 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
   1001 		vsop_find(&farg, &func, void, &arg0, vop_inactive,
   1002 			femop_inactive);
   1003 		(*func)(arg0, cr, ct);
   1004 		fem_release(femsp);
   1005 	}
   1006 }
   1007 
   1008 static int
   1009 vhead_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct)
   1010 {
   1011 	femarg_t	farg;
   1012 	struct fem_list	*femsp;
   1013 	int		(*func)();
   1014 	void		*arg0;
   1015 	int		errc;
   1016 
   1017 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
   1018 		func = (int (*)()) (vp->v_op->vop_fid);
   1019 		arg0 = vp;
   1020 		fem_unlock(vp->v_femhead);
   1021 		errc = (*func)(arg0, fidp, ct);
   1022 	} else {
   1023 		fem_addref(femsp);
   1024 		fem_unlock(vp->v_femhead);
   1025 		farg.fa_vnode.vp = vp;
   1026 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
   1027 		vsop_find(&farg, &func, int, &arg0, vop_fid, femop_fid);
   1028 		errc = (*func)(arg0, fidp, ct);
   1029 		fem_release(femsp);
   1030 	}
   1031 	return (errc);
   1032 }
   1033 
   1034 static int
   1035 vhead_rwlock(vnode_t *vp, int write_lock, caller_context_t *ct)
   1036 {
   1037 	femarg_t	farg;
   1038 	struct fem_list	*femsp;
   1039 	int		(*func)();
   1040 	void		*arg0;
   1041 	int		errc;
   1042 
   1043 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
   1044 		func = (int (*)()) (vp->v_op->vop_rwlock);
   1045 		arg0 = vp;
   1046 		fem_unlock(vp->v_femhead);
   1047 		errc = (*func)(arg0, write_lock, ct);
   1048 	} else {
   1049 		fem_addref(femsp);
   1050 		fem_unlock(vp->v_femhead);
   1051 		farg.fa_vnode.vp = vp;
   1052 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
   1053 		vsop_find(&farg, &func, int, &arg0, vop_rwlock,
   1054 			femop_rwlock);
   1055 		errc = (*func)(arg0, write_lock, ct);
   1056 		fem_release(femsp);
   1057 	}
   1058 	return (errc);
   1059 }
   1060 
   1061 static void
   1062 vhead_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ct)
   1063 {
   1064 	femarg_t	farg;
   1065 	struct fem_list	*femsp;
   1066 	void		(*func)();
   1067 	void		*arg0;
   1068 
   1069 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
   1070 		func = (void (*)()) (vp->v_op->vop_rwunlock);
   1071 		arg0 = vp;
   1072 		fem_unlock(vp->v_femhead);
   1073 		(*func)(arg0, write_lock, ct);
   1074 	} else {
   1075 		fem_addref(femsp);
   1076 		fem_unlock(vp->v_femhead);
   1077 		farg.fa_vnode.vp = vp;
   1078 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
   1079 		vsop_find(&farg, &func, void, &arg0, vop_rwunlock,
   1080 			femop_rwunlock);
   1081 		(*func)(arg0, write_lock, ct);
   1082 		fem_release(femsp);
   1083 	}
   1084 }
   1085 
   1086 static int
   1087 vhead_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
   1088 {
   1089 	femarg_t	farg;
   1090 	struct fem_list	*femsp;
   1091 	int		(*func)();
   1092 	void		*arg0;
   1093 	int		errc;
   1094 
   1095 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
   1096 		func = (int (*)()) (vp->v_op->vop_seek);
   1097 		arg0 = vp;
   1098 		fem_unlock(vp->v_femhead);
   1099 		errc = (*func)(arg0, ooff, noffp, ct);
   1100 	} else {
   1101 		fem_addref(femsp);
   1102 		fem_unlock(vp->v_femhead);
   1103 		farg.fa_vnode.vp = vp;
   1104 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
   1105 		vsop_find(&farg, &func, int, &arg0, vop_seek, femop_seek);
   1106 		errc = (*func)(arg0, ooff, noffp, ct);
   1107 		fem_release(femsp);
   1108 	}
   1109 	return (errc);
   1110 }
   1111 
   1112 static int
   1113 vhead_cmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct)
   1114 {
   1115 	femarg_t	farg;
   1116 	struct fem_list	*femsp;
   1117 	int		(*func)();
   1118 	void		*arg0;
   1119 	int		errc;
   1120 
   1121 	if ((femsp = fem_lock(vp1->v_femhead)) == NULL) {
   1122 		func = (int (*)()) (vp1->v_op->vop_cmp);
   1123 		arg0 = vp1;
   1124 		fem_unlock(vp1->v_femhead);
   1125 		errc = (*func)(arg0, vp2, ct);
   1126 	} else {
   1127 		fem_addref(femsp);
   1128 		fem_unlock(vp1->v_femhead);
   1129 		farg.fa_vnode.vp = vp1;
   1130 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
   1131 		vsop_find(&farg, &func, int, &arg0, vop_cmp, femop_cmp);
   1132 		errc = (*func)(arg0, vp2, ct);
   1133 		fem_release(femsp);
   1134 	}
   1135 	return (errc);
   1136 }
   1137 
   1138 static int
   1139 vhead_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
   1140 	offset_t offset, struct flk_callback *flk_cbp, cred_t *cr,
   1141 	caller_context_t *ct)
   1142 {
   1143 	femarg_t	farg;
   1144 	struct fem_list	*femsp;
   1145 	int		(*func)();
   1146 	void		*arg0;
   1147 	int		errc;
   1148 
   1149 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
   1150 		func = (int (*)()) (vp->v_op->vop_frlock);
   1151 		arg0 = vp;
   1152 		fem_unlock(vp->v_femhead);
   1153 		errc = (*func)(arg0, cmd, bfp, flag, offset, flk_cbp, cr, ct);
   1154 	} else {
   1155 		fem_addref(femsp);
   1156 		fem_unlock(vp->v_femhead);
   1157 		farg.fa_vnode.vp = vp;
   1158 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
   1159 		vsop_find(&farg, &func, int, &arg0, vop_frlock,
   1160 			femop_frlock);
   1161 		errc = (*func)(arg0, cmd, bfp, flag, offset, flk_cbp, cr, ct);
   1162 		fem_release(femsp);
   1163 	}
   1164 	return (errc);
   1165 }
   1166 
   1167 static int
   1168 vhead_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
   1169 	offset_t offset, cred_t *cr, caller_context_t *ct)
   1170 {
   1171 	femarg_t	farg;
   1172 	struct fem_list	*femsp;
   1173 	int		(*func)();
   1174 	void		*arg0;
   1175 	int		errc;
   1176 
   1177 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
   1178 		func = (int (*)()) (vp->v_op->vop_space);
   1179 		arg0 = vp;
   1180 		fem_unlock(vp->v_femhead);
   1181 		errc = (*func)(arg0, cmd, bfp, flag, offset, cr, ct);
   1182 	} else {
   1183 		fem_addref(femsp);
   1184 		fem_unlock(vp->v_femhead);
   1185 		farg.fa_vnode.vp = vp;
   1186 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
   1187 		vsop_find(&farg, &func, int, &arg0, vop_space, femop_space);
   1188 		errc = (*func)(arg0, cmd, bfp, flag, offset, cr, ct);
   1189 		fem_release(femsp);
   1190 	}
   1191 	return (errc);
   1192 }
   1193 
   1194 static int
   1195 vhead_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
   1196 {
   1197 	femarg_t	farg;
   1198 	struct fem_list	*femsp;
   1199 	int		(*func)();
   1200 	void		*arg0;
   1201 	int		errc;
   1202 
   1203 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
   1204 		func = (int (*)()) (vp->v_op->vop_realvp);
   1205 		arg0 = vp;
   1206 		fem_unlock(vp->v_femhead);
   1207 		errc = (*func)(arg0, vpp, ct);
   1208 	} else {
   1209 		fem_addref(femsp);
   1210 		fem_unlock(vp->v_femhead);
   1211 		farg.fa_vnode.vp = vp;
   1212 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
   1213 		vsop_find(&farg, &func, int, &arg0, vop_realvp,
   1214 			femop_realvp);
   1215 		errc = (*func)(arg0, vpp, ct);
   1216 		fem_release(femsp);
   1217 	}
   1218 	return (errc);
   1219 }
   1220 
   1221 static int
   1222 vhead_getpage(vnode_t *vp, offset_t off, size_t len, uint_t *protp,
   1223 	struct page **plarr, size_t plsz, struct seg *seg, caddr_t addr,
   1224 	enum seg_rw rw, cred_t *cr, caller_context_t *ct)
   1225 {
   1226 	femarg_t	farg;
   1227 	struct fem_list	*femsp;
   1228 	int		(*func)();
   1229 	void		*arg0;
   1230 	int		errc;
   1231 
   1232 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
   1233 		func = (int (*)()) (vp->v_op->vop_getpage);
   1234 		arg0 = vp;
   1235 		fem_unlock(vp->v_femhead);
   1236 		errc = (*func)(arg0, off, len, protp, plarr, plsz, seg,
   1237 			addr, rw, cr, ct);
   1238 	} else {
   1239 		fem_addref(femsp);
   1240 		fem_unlock(vp->v_femhead);
   1241 		farg.fa_vnode.vp = vp;
   1242 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
   1243 		vsop_find(&farg, &func, int, &arg0, vop_getpage,
   1244 			femop_getpage);
   1245 		errc = (*func)(arg0, off, len, protp, plarr, plsz, seg,
   1246 			addr, rw, cr, ct);
   1247 		fem_release(femsp);
   1248 	}
   1249 	return (errc);
   1250 }
   1251 
   1252 static int
   1253 vhead_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr,
   1254 	caller_context_t *ct)
   1255 {
   1256 	femarg_t	farg;
   1257 	struct fem_list	*femsp;
   1258 	int		(*func)();
   1259 	void		*arg0;
   1260 	int		errc;
   1261 
   1262 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
   1263 		func = (int (*)()) (vp->v_op->vop_putpage);
   1264 		arg0 = vp;
   1265 		fem_unlock(vp->v_femhead);
   1266 		errc = (*func)(arg0, off, len, flags, cr, ct);
   1267 	} else {
   1268 		fem_addref(femsp);
   1269 		fem_unlock(vp->v_femhead);
   1270 		farg.fa_vnode.vp = vp;
   1271 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
   1272 		vsop_find(&farg, &func, int, &arg0, vop_putpage,
   1273 			femop_putpage);
   1274 		errc = (*func)(arg0, off, len, flags, cr, ct);
   1275 		fem_release(femsp);
   1276 	}
   1277 	return (errc);
   1278 }
   1279 
   1280 static int
   1281 vhead_map(vnode_t *vp, offset_t off, struct as *as, caddr_t *addrp,
   1282 	size_t len, uchar_t prot, uchar_t maxprot, uint_t flags,
   1283 	cred_t *cr, caller_context_t *ct)
   1284 {
   1285 	femarg_t	farg;
   1286 	struct fem_list	*femsp;
   1287 	int		(*func)();
   1288 	void		*arg0;
   1289 	int		errc;
   1290 
   1291 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
   1292 		func = (int (*)()) (vp->v_op->vop_map);
   1293 		arg0 = vp;
   1294 		fem_unlock(vp->v_femhead);
   1295 		errc = (*func)(arg0, off, as, addrp, len, prot, maxprot,
   1296 			flags, cr, ct);
   1297 	} else {
   1298 		fem_addref(femsp);
   1299 		fem_unlock(vp->v_femhead);
   1300 		farg.fa_vnode.vp = vp;
   1301 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
   1302 		vsop_find(&farg, &func, int, &arg0, vop_map, femop_map);
   1303 		errc = (*func)(arg0, off, as, addrp, len, prot, maxprot,
   1304 			flags, cr, ct);
   1305 		fem_release(femsp);
   1306 	}
   1307 	return (errc);
   1308 }
   1309 
   1310 static int
   1311 vhead_addmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
   1312 	size_t len, uchar_t prot, uchar_t maxprot, uint_t flags,
   1313 	cred_t *cr, caller_context_t *ct)
   1314 {
   1315 	femarg_t	farg;
   1316 	struct fem_list	*femsp;
   1317 	int		(*func)();
   1318 	void		*arg0;
   1319 	int		errc;
   1320 
   1321 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
   1322 		func = (int (*)()) (vp->v_op->vop_addmap);
   1323 		arg0 = vp;
   1324 		fem_unlock(vp->v_femhead);
   1325 		errc = (*func)(arg0, off, as, addr, len, prot, maxprot,
   1326 			flags, cr, ct);
   1327 	} else {
   1328 		fem_addref(femsp);
   1329 		fem_unlock(vp->v_femhead);
   1330 		farg.fa_vnode.vp = vp;
   1331 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
   1332 		vsop_find(&farg, &func, int, &arg0, vop_addmap,
   1333 			femop_addmap);
   1334 		errc = (*func)(arg0, off, as, addr, len, prot, maxprot,
   1335 			flags, cr, ct);
   1336 		fem_release(femsp);
   1337 	}
   1338 	return (errc);
   1339 }
   1340 
   1341 static int
   1342 vhead_delmap(vnode_t *vp, offset_t off, struct as *as, caddr_t addr,
   1343 	size_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *cr,
   1344 	caller_context_t *ct)
   1345 {
   1346 	femarg_t	farg;
   1347 	struct fem_list	*femsp;
   1348 	int		(*func)();
   1349 	void		*arg0;
   1350 	int		errc;
   1351 
   1352 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
   1353 		func = (int (*)()) (vp->v_op->vop_delmap);
   1354 		arg0 = vp;
   1355 		fem_unlock(vp->v_femhead);
   1356 		errc = (*func)(arg0, off, as, addr, len, prot, maxprot,
   1357 			flags, cr, ct);
   1358 	} else {
   1359 		fem_addref(femsp);
   1360 		fem_unlock(vp->v_femhead);
   1361 		farg.fa_vnode.vp = vp;
   1362 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
   1363 		vsop_find(&farg, &func, int, &arg0, vop_delmap,
   1364 			femop_delmap);
   1365 		errc = (*func)(arg0, off, as, addr, len, prot, maxprot,
   1366 			flags, cr, ct);
   1367 		fem_release(femsp);
   1368 	}
   1369 	return (errc);
   1370 }
   1371 
   1372 static int
   1373 vhead_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
   1374 	struct pollhead **phpp, caller_context_t *ct)
   1375 {
   1376 	femarg_t	farg;
   1377 	struct fem_list	*femsp;
   1378 	int		(*func)();
   1379 	void		*arg0;
   1380 	int		errc;
   1381 
   1382 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
   1383 		func = (int (*)()) (vp->v_op->vop_poll);
   1384 		arg0 = vp;
   1385 		fem_unlock(vp->v_femhead);
   1386 		errc = (*func)(arg0, events, anyyet, reventsp, phpp, ct);
   1387 	} else {
   1388 		fem_addref(femsp);
   1389 		fem_unlock(vp->v_femhead);
   1390 		farg.fa_vnode.vp = vp;
   1391 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
   1392 		vsop_find(&farg, &func, int, &arg0, vop_poll, femop_poll);
   1393 		errc = (*func)(arg0, events, anyyet, reventsp, phpp, ct);
   1394 		fem_release(femsp);
   1395 	}
   1396 	return (errc);
   1397 }
   1398 
   1399 static int
   1400 vhead_dump(vnode_t *vp, caddr_t addr, int lbdn, int dblks, caller_context_t *ct)
   1401 {
   1402 	femarg_t	farg;
   1403 	struct fem_list	*femsp;
   1404 	int		(*func)();
   1405 	void		*arg0;
   1406 	int		errc;
   1407 
   1408 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
   1409 		func = (int (*)()) (vp->v_op->vop_dump);
   1410 		arg0 = vp;
   1411 		fem_unlock(vp->v_femhead);
   1412 		errc = (*func)(arg0, addr, lbdn, dblks, ct);
   1413 	} else {
   1414 		fem_addref(femsp);
   1415 		fem_unlock(vp->v_femhead);
   1416 		farg.fa_vnode.vp = vp;
   1417 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
   1418 		vsop_find(&farg, &func, int, &arg0, vop_dump, femop_dump);
   1419 		errc = (*func)(arg0, addr, lbdn, dblks, ct);
   1420 		fem_release(femsp);
   1421 	}
   1422 	return (errc);
   1423 }
   1424 
   1425 static int
   1426 vhead_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
   1427 	caller_context_t *ct)
   1428 {
   1429 	femarg_t	farg;
   1430 	struct fem_list	*femsp;
   1431 	int		(*func)();
   1432 	void		*arg0;
   1433 	int		errc;
   1434 
   1435 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
   1436 		func = (int (*)()) (vp->v_op->vop_pathconf);
   1437 		arg0 = vp;
   1438 		fem_unlock(vp->v_femhead);
   1439 		errc = (*func)(arg0, cmd, valp, cr, ct);
   1440 	} else {
   1441 		fem_addref(femsp);
   1442 		fem_unlock(vp->v_femhead);
   1443 		farg.fa_vnode.vp = vp;
   1444 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
   1445 		vsop_find(&farg, &func, int, &arg0, vop_pathconf,
   1446 			femop_pathconf);
   1447 		errc = (*func)(arg0, cmd, valp, cr, ct);
   1448 		fem_release(femsp);
   1449 	}
   1450 	return (errc);
   1451 }
   1452 
   1453 static int
   1454 vhead_pageio(vnode_t *vp, struct page *pp, u_offset_t io_off,
   1455 	size_t io_len, int flags, cred_t *cr, caller_context_t *ct)
   1456 {
   1457 	femarg_t	farg;
   1458 	struct fem_list	*femsp;
   1459 	int		(*func)();
   1460 	void		*arg0;
   1461 	int		errc;
   1462 
   1463 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
   1464 		func = (int (*)()) (vp->v_op->vop_pageio);
   1465 		arg0 = vp;
   1466 		fem_unlock(vp->v_femhead);
   1467 		errc = (*func)(arg0, pp, io_off, io_len, flags, cr, ct);
   1468 	} else {
   1469 		fem_addref(femsp);
   1470 		fem_unlock(vp->v_femhead);
   1471 		farg.fa_vnode.vp = vp;
   1472 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
   1473 		vsop_find(&farg, &func, int, &arg0, vop_pageio,
   1474 			femop_pageio);
   1475 		errc = (*func)(arg0, pp, io_off, io_len, flags, cr, ct);
   1476 		fem_release(femsp);
   1477 	}
   1478 	return (errc);
   1479 }
   1480 
   1481 static int
   1482 vhead_dumpctl(vnode_t *vp, int action, int *blkp, caller_context_t *ct)
   1483 {
   1484 	femarg_t	farg;
   1485 	struct fem_list	*femsp;
   1486 	int		(*func)();
   1487 	void		*arg0;
   1488 	int		errc;
   1489 
   1490 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
   1491 		func = (int (*)()) (vp->v_op->vop_dumpctl);
   1492 		arg0 = vp;
   1493 		fem_unlock(vp->v_femhead);
   1494 		errc = (*func)(arg0, action, blkp, ct);
   1495 	} else {
   1496 		fem_addref(femsp);
   1497 		fem_unlock(vp->v_femhead);
   1498 		farg.fa_vnode.vp = vp;
   1499 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
   1500 		vsop_find(&farg, &func, int, &arg0, vop_dumpctl,
   1501 			femop_dumpctl);
   1502 		errc = (*func)(arg0, action, blkp, ct);
   1503 		fem_release(femsp);
   1504 	}
   1505 	return (errc);
   1506 }
   1507 
   1508 static void
   1509 vhead_dispose(vnode_t *vp, struct page *pp, int flag, int dn, cred_t *cr,
   1510 	caller_context_t *ct)
   1511 {
   1512 	femarg_t	farg;
   1513 	struct fem_list	*femsp;
   1514 	void		(*func)();
   1515 	void		*arg0;
   1516 
   1517 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
   1518 		func = (void (*)()) (vp->v_op->vop_dispose);
   1519 		arg0 = vp;
   1520 		fem_unlock(vp->v_femhead);
   1521 		(*func)(arg0, pp, flag, dn, cr, ct);
   1522 	} else {
   1523 		fem_addref(femsp);
   1524 		fem_unlock(vp->v_femhead);
   1525 		farg.fa_vnode.vp = vp;
   1526 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
   1527 		vsop_find(&farg, &func, void, &arg0, vop_dispose,
   1528 			femop_dispose);
   1529 		(*func)(arg0, pp, flag, dn, cr, ct);
   1530 		fem_release(femsp);
   1531 	}
   1532 }
   1533 
   1534 static int
   1535 vhead_setsecattr(vnode_t *vp, vsecattr_t *vsap, int flag, cred_t *cr,
   1536 	caller_context_t *ct)
   1537 {
   1538 	femarg_t	farg;
   1539 	struct fem_list	*femsp;
   1540 	int		(*func)();
   1541 	void		*arg0;
   1542 	int		errc;
   1543 
   1544 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
   1545 		func = (int (*)()) (vp->v_op->vop_setsecattr);
   1546 		arg0 = vp;
   1547 		fem_unlock(vp->v_femhead);
   1548 		errc = (*func)(arg0, vsap, flag, cr, ct);
   1549 	} else {
   1550 		fem_addref(femsp);
   1551 		fem_unlock(vp->v_femhead);
   1552 		farg.fa_vnode.vp = vp;
   1553 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
   1554 		vsop_find(&farg, &func, int, &arg0, vop_setsecattr,
   1555 			femop_setsecattr);
   1556 		errc = (*func)(arg0, vsap, flag, cr, ct);
   1557 		fem_release(femsp);
   1558 	}
   1559 	return (errc);
   1560 }
   1561 
   1562 static int
   1563 vhead_getsecattr(vnode_t *vp, vsecattr_t *vsap, int flag, cred_t *cr,
   1564 	caller_context_t *ct)
   1565 {
   1566 	femarg_t	farg;
   1567 	struct fem_list	*femsp;
   1568 	int		(*func)();
   1569 	void		*arg0;
   1570 	int		errc;
   1571 
   1572 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
   1573 		func = (int (*)()) (vp->v_op->vop_getsecattr);
   1574 		arg0 = vp;
   1575 		fem_unlock(vp->v_femhead);
   1576 		errc = (*func)(arg0, vsap, flag, cr, ct);
   1577 	} else {
   1578 		fem_addref(femsp);
   1579 		fem_unlock(vp->v_femhead);
   1580 		farg.fa_vnode.vp = vp;
   1581 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
   1582 		vsop_find(&farg, &func, int, &arg0, vop_getsecattr,
   1583 			femop_getsecattr);
   1584 		errc = (*func)(arg0, vsap, flag, cr, ct);
   1585 		fem_release(femsp);
   1586 	}
   1587 	return (errc);
   1588 }
   1589 
   1590 static int
   1591 vhead_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag,
   1592 	cred_t *cr, caller_context_t *ct)
   1593 {
   1594 	femarg_t	farg;
   1595 	struct fem_list	*femsp;
   1596 	int		(*func)();
   1597 	void		*arg0;
   1598 	int		errc;
   1599 
   1600 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
   1601 		func = (int (*)()) (vp->v_op->vop_shrlock);
   1602 		arg0 = vp;
   1603 		fem_unlock(vp->v_femhead);
   1604 		errc = (*func)(arg0, cmd, shr, flag, cr, ct);
   1605 	} else {
   1606 		fem_addref(femsp);
   1607 		fem_unlock(vp->v_femhead);
   1608 		farg.fa_vnode.vp = vp;
   1609 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
   1610 		vsop_find(&farg, &func, int, &arg0, vop_shrlock,
   1611 			femop_shrlock);
   1612 		errc = (*func)(arg0, cmd, shr, flag, cr, ct);
   1613 		fem_release(femsp);
   1614 	}
   1615 	return (errc);
   1616 }
   1617 
   1618 static int
   1619 vhead_vnevent(vnode_t *vp, vnevent_t vnevent, vnode_t *dvp, char *cname,
   1620     caller_context_t *ct)
   1621 {
   1622 	femarg_t	farg;
   1623 	struct fem_list	*femsp;
   1624 	int		(*func)();
   1625 	void		*arg0;
   1626 	int		errc;
   1627 
   1628 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
   1629 		func = (int (*)()) (vp->v_op->vop_vnevent);
   1630 		arg0 = vp;
   1631 		fem_unlock(vp->v_femhead);
   1632 		errc = (*func)(arg0, vnevent, dvp, cname, ct);
   1633 	} else {
   1634 		fem_addref(femsp);
   1635 		fem_unlock(vp->v_femhead);
   1636 		farg.fa_vnode.vp = vp;
   1637 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
   1638 		vsop_find(&farg, &func, int, &arg0, vop_vnevent,
   1639 			femop_vnevent);
   1640 		errc = (*func)(arg0, vnevent, dvp, cname, ct);
   1641 		fem_release(femsp);
   1642 	}
   1643 	return (errc);
   1644 }
   1645 
   1646 static int
   1647 fshead_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
   1648 {
   1649 	fsemarg_t	farg;
   1650 	struct fem_list	*femsp;
   1651 	int		(*func)();
   1652 	void		*arg0;
   1653 	int		errc;
   1654 
   1655 	ASSERT(vfsp->vfs_implp);
   1656 
   1657 	if ((femsp = fem_lock(vfsp->vfs_femhead)) == NULL) {
   1658 		func = (int (*)()) vfsp->vfs_op->vfs_mount;
   1659 		fem_unlock(vfsp->vfs_femhead);
   1660 		errc = (*func)(vfsp, mvp, uap, cr);
   1661 	} else {
   1662 		fem_addref(femsp);
   1663 		fem_unlock(vfsp->vfs_femhead);
   1664 		farg.fa_vnode.vfsp = vfsp;
   1665 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
   1666 		vfsop_find(&farg, &func, int, &arg0, vfs_mount,
   1667 			fsemop_mount);
   1668 		errc = (*func)(arg0, mvp, uap, cr);
   1669 		fem_release(femsp);
   1670 	}
   1671 	return (errc);
   1672 }
   1673 
   1674 static int
   1675 fshead_unmount(vfs_t *vfsp, int flag, cred_t *cr)
   1676 {
   1677 	fsemarg_t	farg;
   1678 	struct fem_list	*femsp;
   1679 	int		(*func)();
   1680 	void		*arg0;
   1681 	int		errc;
   1682 
   1683 	ASSERT(vfsp->vfs_implp);
   1684 
   1685 	if ((femsp = fem_lock(vfsp->vfs_femhead)) == NULL) {
   1686 		func = (int (*)()) vfsp->vfs_op->vfs_unmount;
   1687 		fem_unlock(vfsp->vfs_femhead);
   1688 		errc = (*func)(vfsp, flag, cr);
   1689 	} else {
   1690 		fem_addref(femsp);
   1691 		fem_unlock(vfsp->vfs_femhead);
   1692 		farg.fa_vnode.vfsp = vfsp;
   1693 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
   1694 		vfsop_find(&farg, &func, int, &arg0, vfs_unmount,
   1695 			fsemop_unmount);
   1696 		errc = (*func)(arg0, flag, cr);
   1697 		fem_release(femsp);
   1698 	}
   1699 	return (errc);
   1700 }
   1701 
   1702 static int
   1703 fshead_root(vfs_t *vfsp, vnode_t **vpp)
   1704 {
   1705 	fsemarg_t	farg;
   1706 	struct fem_list	*femsp;
   1707 	int		(*func)();
   1708 	void		*arg0;
   1709 	int		errc;
   1710 
   1711 	ASSERT(vfsp->vfs_implp);
   1712 
   1713 	if ((femsp = fem_lock(vfsp->vfs_femhead)) == NULL) {
   1714 		func = (int (*)()) vfsp->vfs_op->vfs_root;
   1715 		fem_unlock(vfsp->vfs_femhead);
   1716 		errc = (*func)(vfsp, vpp);
   1717 	} else {
   1718 		fem_addref(femsp);
   1719 		fem_unlock(vfsp->vfs_femhead);
   1720 		farg.fa_vnode.vfsp = vfsp;
   1721 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
   1722 		vfsop_find(&farg, &func, int, &arg0, vfs_root, fsemop_root);
   1723 		errc = (*func)(arg0, vpp);
   1724 		fem_release(femsp);
   1725 	}
   1726 	return (errc);
   1727 }
   1728 
   1729 static int
   1730 fshead_statvfs(vfs_t *vfsp, statvfs64_t *sp)
   1731 {
   1732 	fsemarg_t	farg;
   1733 	struct fem_list	*femsp;
   1734 	int		(*func)();
   1735 	void		*arg0;
   1736 	int		errc;
   1737 
   1738 	ASSERT(vfsp->vfs_implp);
   1739 
   1740 	if ((femsp = fem_lock(vfsp->vfs_femhead)) == NULL) {
   1741 		func = (int (*)()) vfsp->vfs_op->vfs_statvfs;
   1742 		fem_unlock(vfsp->vfs_femhead);
   1743 		errc = (*func)(vfsp, sp);
   1744 	} else {
   1745 		fem_addref(femsp);
   1746 		fem_unlock(vfsp->vfs_femhead);
   1747 		farg.fa_vnode.vfsp = vfsp;
   1748 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
   1749 		vfsop_find(&farg, &func, int, &arg0, vfs_statvfs,
   1750 			fsemop_statvfs);
   1751 		errc = (*func)(arg0, sp);
   1752 		fem_release(femsp);
   1753 	}
   1754 	return (errc);
   1755 }
   1756 
   1757 static int
   1758 fshead_sync(vfs_t *vfsp, short flag, cred_t *cr)
   1759 {
   1760 	fsemarg_t	farg;
   1761 	struct fem_list	*femsp;
   1762 	int		(*func)();
   1763 	void		*arg0;
   1764 	int		errc;
   1765 
   1766 	ASSERT(vfsp->vfs_implp);
   1767 
   1768 	if ((femsp = fem_lock(vfsp->vfs_femhead)) == NULL) {
   1769 		func = (int (*)()) vfsp->vfs_op->vfs_sync;
   1770 		fem_unlock(vfsp->vfs_femhead);
   1771 		errc = (*func)(vfsp, flag, cr);
   1772 	} else {
   1773 		fem_addref(femsp);
   1774 		fem_unlock(vfsp->vfs_femhead);
   1775 		farg.fa_vnode.vfsp = vfsp;
   1776 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
   1777 		vfsop_find(&farg, &func, int, &arg0, vfs_sync, fsemop_sync);
   1778 		errc = (*func)(arg0, flag, cr);
   1779 		fem_release(femsp);
   1780 	}
   1781 	return (errc);
   1782 }
   1783 
   1784 static int
   1785 fshead_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp)
   1786 {
   1787 	fsemarg_t	farg;
   1788 	struct fem_list	*femsp;
   1789 	int		(*func)();
   1790 	void		*arg0;
   1791 	int		errc;
   1792 
   1793 	ASSERT(vfsp->vfs_implp);
   1794 
   1795 	if ((femsp = fem_lock(vfsp->vfs_femhead)) == NULL) {
   1796 		func = (int (*)()) vfsp->vfs_op->vfs_vget;
   1797 		fem_unlock(vfsp->vfs_femhead);
   1798 		errc = (*func)(vfsp, vpp, fidp);
   1799 	} else {
   1800 		fem_addref(femsp);
   1801 		fem_unlock(vfsp->vfs_femhead);
   1802 		farg.fa_vnode.vfsp = vfsp;
   1803 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
   1804 		vfsop_find(&farg, &func, int, &arg0, vfs_vget, fsemop_vget);
   1805 		errc = (*func)(arg0, vpp, fidp);
   1806 		fem_release(femsp);
   1807 	}
   1808 	return (errc);
   1809 }
   1810 
   1811 static int
   1812 fshead_mountroot(vfs_t *vfsp, enum whymountroot reason)
   1813 {
   1814 	fsemarg_t	farg;
   1815 	struct fem_list	*femsp;
   1816 	int		(*func)();
   1817 	void		*arg0;
   1818 	int		errc;
   1819 
   1820 	ASSERT(vfsp->vfs_implp);
   1821 
   1822 	if ((femsp = fem_lock(vfsp->vfs_femhead)) == NULL) {
   1823 		func = (int (*)()) vfsp->vfs_op->vfs_mountroot;
   1824 		fem_unlock(vfsp->vfs_femhead);
   1825 		errc = (*func)(vfsp, reason);
   1826 	} else {
   1827 		fem_addref(femsp);
   1828 		fem_unlock(vfsp->vfs_femhead);
   1829 		farg.fa_vnode.vfsp = vfsp;
   1830 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
   1831 		vfsop_find(&farg, &func, int, &arg0, vfs_mountroot,
   1832 			fsemop_mountroot);
   1833 		errc = (*func)(arg0, reason);
   1834 		fem_release(femsp);
   1835 	}
   1836 	return (errc);
   1837 }
   1838 
   1839 static void
   1840 fshead_freevfs(vfs_t *vfsp)
   1841 {
   1842 	fsemarg_t	farg;
   1843 	struct fem_list	*femsp;
   1844 	void		(*func)();
   1845 	void		*arg0;
   1846 
   1847 	ASSERT(vfsp->vfs_implp);
   1848 
   1849 	if ((femsp = fem_lock(vfsp->vfs_femhead)) == NULL) {
   1850 		func = (void (*)()) vfsp->vfs_op->vfs_freevfs;
   1851 		fem_unlock(vfsp->vfs_femhead);
   1852 		(*func)(vfsp);
   1853 	} else {
   1854 		fem_addref(femsp);
   1855 		fem_unlock(vfsp->vfs_femhead);
   1856 		farg.fa_vnode.vfsp = vfsp;
   1857 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
   1858 		vfsop_find(&farg, &func, void, &arg0, vfs_freevfs,
   1859 			fsemop_freevfs);
   1860 		(*func)(arg0);
   1861 		fem_release(femsp);
   1862 	}
   1863 }
   1864 
   1865 static int
   1866 fshead_vnstate(vfs_t *vfsp, vnode_t *vp, vntrans_t nstate)
   1867 {
   1868 	fsemarg_t	farg;
   1869 	struct fem_list	*femsp;
   1870 	int		(*func)();
   1871 	void		*arg0;
   1872 	int		errc;
   1873 
   1874 	ASSERT(vfsp->vfs_implp);
   1875 
   1876 	if ((femsp = fem_lock(vfsp->vfs_femhead)) == NULL) {
   1877 		func = (int (*)()) vfsp->vfs_op->vfs_vnstate;
   1878 		fem_unlock(vfsp->vfs_femhead);
   1879 		errc = (*func)(vfsp, vp, nstate);
   1880 	} else {
   1881 		fem_addref(femsp);
   1882 		fem_unlock(vfsp->vfs_femhead);
   1883 		farg.fa_vnode.vfsp = vfsp;
   1884 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
   1885 		vfsop_find(&farg, &func, int, &arg0, vfs_vnstate,
   1886 			fsemop_vnstate);
   1887 		errc = (*func)(arg0, vp, nstate);
   1888 		fem_release(femsp);
   1889 	}
   1890 	return (errc);
   1891 }
   1892 
   1893 
   1894 /*
   1895  * specification table for the vhead vnode operations.
   1896  * It is an error for any operations to be missing.
   1897  */
   1898 
   1899 static struct fs_operation_def fhead_vn_spec[] = {
   1900 	{ VOPNAME_OPEN, (femop_t *)vhead_open },
   1901 	{ VOPNAME_CLOSE, (femop_t *)vhead_close },
   1902 	{ VOPNAME_READ, (femop_t *)vhead_read },
   1903 	{ VOPNAME_WRITE, (femop_t *)vhead_write },
   1904 	{ VOPNAME_IOCTL, (femop_t *)vhead_ioctl },
   1905 	{ VOPNAME_SETFL, (femop_t *)vhead_setfl },
   1906 	{ VOPNAME_GETATTR, (femop_t *)vhead_getattr },
   1907 	{ VOPNAME_SETATTR, (femop_t *)vhead_setattr },
   1908 	{ VOPNAME_ACCESS, (femop_t *)vhead_access },
   1909 	{ VOPNAME_LOOKUP, (femop_t *)vhead_lookup },
   1910 	{ VOPNAME_CREATE, (femop_t *)vhead_create },
   1911 	{ VOPNAME_REMOVE, (femop_t *)vhead_remove },
   1912 	{ VOPNAME_LINK, (femop_t *)vhead_link },
   1913 	{ VOPNAME_RENAME, (femop_t *)vhead_rename },
   1914 	{ VOPNAME_MKDIR, (femop_t *)vhead_mkdir },
   1915 	{ VOPNAME_RMDIR, (femop_t *)vhead_rmdir },
   1916 	{ VOPNAME_READDIR, (femop_t *)vhead_readdir },
   1917 	{ VOPNAME_SYMLINK, (femop_t *)vhead_symlink },
   1918 	{ VOPNAME_READLINK, (femop_t *)vhead_readlink },
   1919 	{ VOPNAME_FSYNC, (femop_t *)vhead_fsync },
   1920 	{ VOPNAME_INACTIVE, (femop_t *)vhead_inactive },
   1921 	{ VOPNAME_FID, (femop_t *)vhead_fid },
   1922 	{ VOPNAME_RWLOCK, (femop_t *)vhead_rwlock },
   1923 	{ VOPNAME_RWUNLOCK, (femop_t *)vhead_rwunlock },
   1924 	{ VOPNAME_SEEK, (femop_t *)vhead_seek },
   1925 	{ VOPNAME_CMP, (femop_t *)vhead_cmp },
   1926 	{ VOPNAME_FRLOCK, (femop_t *)vhead_frlock },
   1927 	{ VOPNAME_SPACE, (femop_t *)vhead_space },
   1928 	{ VOPNAME_REALVP, (femop_t *)vhead_realvp },
   1929 	{ VOPNAME_GETPAGE, (femop_t *)vhead_getpage },
   1930 	{ VOPNAME_PUTPAGE, (femop_t *)vhead_putpage },
   1931 	{ VOPNAME_MAP, (femop_t *)vhead_map },
   1932 	{ VOPNAME_ADDMAP, (femop_t *)vhead_addmap },
   1933 	{ VOPNAME_DELMAP, (femop_t *)vhead_delmap },
   1934 	{ VOPNAME_POLL, (femop_t *)vhead_poll },
   1935 	{ VOPNAME_DUMP, (femop_t *)vhead_dump },
   1936 	{ VOPNAME_PATHCONF, (femop_t *)vhead_pathconf },
   1937 	{ VOPNAME_PAGEIO, (femop_t *)vhead_pageio },
   1938 	{ VOPNAME_DUMPCTL, (femop_t *)vhead_dumpctl },
   1939 	{ VOPNAME_DISPOSE, (femop_t *)vhead_dispose },
   1940 	{ VOPNAME_SETSECATTR, (femop_t *)vhead_setsecattr },
   1941 	{ VOPNAME_GETSECATTR, (femop_t *)vhead_getsecattr },
   1942 	{ VOPNAME_SHRLOCK, (femop_t *)vhead_shrlock },
   1943 	{ VOPNAME_VNEVENT, (femop_t *)vhead_vnevent },
   1944 	{	NULL,	NULL	}
   1945 };
   1946 
   1947 /*
   1948  * specification table for the vfshead vnode operations.
   1949  * It is an error for any operations to be missing.
   1950  */
   1951 
   1952 static struct fs_operation_def fshead_vfs_spec[]  = {
   1953 	{ VFSNAME_MOUNT, (femop_t *)fshead_mount },
   1954 	{ VFSNAME_UNMOUNT, (femop_t *)fshead_unmount },
   1955 	{ VFSNAME_ROOT, (femop_t *)fshead_root },
   1956 	{ VFSNAME_STATVFS, (femop_t *)fshead_statvfs },
   1957 	{ VFSNAME_SYNC, (femop_t *)fshead_sync },
   1958 	{ VFSNAME_VGET, (femop_t *)fshead_vget },
   1959 	{ VFSNAME_MOUNTROOT, (femop_t *)fshead_mountroot },
   1960 	{ VFSNAME_FREEVFS, (femop_t *)fshead_freevfs },
   1961 	{ VFSNAME_VNSTATE, (femop_t *)fshead_vnstate },
   1962 	{	NULL,	NULL	}
   1963 };
   1964 
   1965 /*
   1966  * This set of routines transfer control to the next stacked monitor.
   1967  *
   1968  * Each routine is identical except for naming, types and arguments.
   1969  *
   1970  * The basic steps are:
   1971  * 1.  Decrease the stack pointer by one.
   1972  * 2.  If the current item is a base operation (vnode, vfs), goto 5.
   1973  * 3.  If the current item does not have a corresponding operation, goto 1
   1974  * 4.  Return by invoking the current item with the argument handle.
   1975  * 5.  Return by invoking the base operation with the base object.
   1976  *
   1977  * for each classification, there needs to be at least one "next" operation
   1978  * for each "head"operation.
   1979  *
   1980  */
   1981 
   1982 int
   1983 vnext_open(femarg_t *vf, int mode, cred_t *cr, caller_context_t *ct)
   1984 {
   1985 	int (*func)() = NULL;
   1986 	void *arg0 = NULL;
   1987 
   1988 	ASSERT(vf != NULL);
   1989 	vf->fa_fnode--;
   1990 	vsop_find(vf, &func, int, &arg0, vop_open, femop_open);
   1991 	ASSERT(func != NULL);
   1992 	ASSERT(arg0 != NULL);
   1993 	return ((*func)(arg0, mode, cr, ct));
   1994 }
   1995 
   1996 int
   1997 vnext_close(femarg_t *vf, int flag, int count, offset_t offset, cred_t *cr,
   1998 	caller_context_t *ct)
   1999 {
   2000 	int (*func)() = NULL;
   2001 	void *arg0 = NULL;
   2002 
   2003 	ASSERT(vf != NULL);
   2004 	vf->fa_fnode--;
   2005 	vsop_find(vf, &func, int, &arg0, vop_close, femop_close);
   2006 	ASSERT(func != NULL);
   2007 	ASSERT(arg0 != NULL);
   2008 	return ((*func)(arg0, flag, count, offset, cr, ct));
   2009 }
   2010 
   2011 int
   2012 vnext_read(femarg_t *vf, uio_t *uiop, int ioflag, cred_t *cr,
   2013 	caller_context_t *ct)
   2014 {
   2015 	int (*func)() = NULL;
   2016 	void *arg0 = NULL;
   2017 
   2018 	ASSERT(vf != NULL);
   2019 	vf->fa_fnode--;
   2020 	vsop_find(vf, &func, int, &arg0, vop_read, femop_read);
   2021 	ASSERT(func != NULL);
   2022 	ASSERT(arg0 != NULL);
   2023 	return ((*func)(arg0, uiop, ioflag, cr, ct));
   2024 }
   2025 
   2026 int
   2027 vnext_write(femarg_t *vf, uio_t *uiop, int ioflag, cred_t *cr,
   2028 	caller_context_t *ct)
   2029 {
   2030 	int (*func)() = NULL;
   2031 	void *arg0 = NULL;
   2032 
   2033 	ASSERT(vf != NULL);
   2034 	vf->fa_fnode--;
   2035 	vsop_find(vf, &func, int, &arg0, vop_write, femop_write);
   2036 	ASSERT(func != NULL);
   2037 	ASSERT(arg0 != NULL);
   2038 	return ((*func)(arg0, uiop, ioflag, cr, ct));
   2039 }
   2040 
   2041 int
   2042 vnext_ioctl(femarg_t *vf, int cmd, intptr_t arg, int flag, cred_t *cr,
   2043 	int *rvalp, caller_context_t *ct)
   2044 {
   2045 	int (*func)() = NULL;
   2046 	void *arg0 = NULL;
   2047 
   2048 	ASSERT(vf != NULL);
   2049 	vf->fa_fnode--;
   2050 	vsop_find(vf, &func, int, &arg0, vop_ioctl, femop_ioctl);
   2051 	ASSERT(func != NULL);
   2052 	ASSERT(arg0 != NULL);
   2053 	return ((*func)(arg0, cmd, arg, flag, cr, rvalp, ct));
   2054 }
   2055 
   2056 int
   2057 vnext_setfl(femarg_t *vf, int oflags, int nflags, cred_t *cr,
   2058 	caller_context_t *ct)
   2059 {
   2060 	int (*func)() = NULL;
   2061 	void *arg0 = NULL;
   2062 
   2063 	ASSERT(vf != NULL);
   2064 	vf->fa_fnode--;
   2065 	vsop_find(vf, &func, int, &arg0, vop_setfl, femop_setfl);
   2066 	ASSERT(func != NULL);
   2067 	ASSERT(arg0 != NULL);
   2068 	return ((*func)(arg0, oflags, nflags, cr, ct));
   2069 }
   2070 
   2071 int
   2072 vnext_getattr(femarg_t *vf, vattr_t *vap, int flags, cred_t *cr,
   2073 	caller_context_t *ct)
   2074 {
   2075 	int (*func)() = NULL;
   2076 	void *arg0 = NULL;
   2077 
   2078 	ASSERT(vf != NULL);
   2079 	vf->fa_fnode--;
   2080 	vsop_find(vf, &func, int, &arg0, vop_getattr, femop_getattr);
   2081 	ASSERT(func != NULL);
   2082 	ASSERT(arg0 != NULL);
   2083 	return ((*func)(arg0, vap, flags, cr, ct));
   2084 }
   2085 
   2086 int
   2087 vnext_setattr(femarg_t *vf, vattr_t *vap, int flags, cred_t *cr,
   2088 	caller_context_t *ct)
   2089 {
   2090 	int (*func)() = NULL;
   2091 	void *arg0 = NULL;
   2092 
   2093 	ASSERT(vf != NULL);
   2094 	vf->fa_fnode--;
   2095 	vsop_find(vf, &func, int, &arg0, vop_setattr, femop_setattr);
   2096 	ASSERT(func != NULL);
   2097 	ASSERT(arg0 != NULL);
   2098 	return ((*func)(arg0, vap, flags, cr, ct));
   2099 }
   2100 
   2101 int
   2102 vnext_access(femarg_t *vf, int mode, int flags, cred_t *cr,
   2103 	caller_context_t *ct)
   2104 {
   2105 	int (*func)() = NULL;
   2106 	void *arg0 = NULL;
   2107 
   2108 	ASSERT(vf != NULL);
   2109 	vf->fa_fnode--;
   2110 	vsop_find(vf, &func, int, &arg0, vop_access, femop_access);
   2111 	ASSERT(func != NULL);
   2112 	ASSERT(arg0 != NULL);
   2113 	return ((*func)(arg0, mode, flags, cr, ct));
   2114 }
   2115 
   2116 int
   2117 vnext_lookup(femarg_t *vf, char *nm, vnode_t **vpp, pathname_t *pnp,
   2118 	int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
   2119 	int *direntflags, pathname_t *realpnp)
   2120 {
   2121 	int (*func)() = NULL;
   2122 	void *arg0 = NULL;
   2123 
   2124 	ASSERT(vf != NULL);
   2125 	vf->fa_fnode--;
   2126 	vsop_find(vf, &func, int, &arg0, vop_lookup, femop_lookup);
   2127 	ASSERT(func != NULL);
   2128 	ASSERT(arg0 != NULL);
   2129 	return ((*func)(arg0, nm, vpp, pnp, flags, rdir, cr, ct,
   2130 		direntflags, realpnp));
   2131 }
   2132 
   2133 int
   2134 vnext_create(femarg_t *vf, char *name, vattr_t *vap, vcexcl_t excl,
   2135 	int mode, vnode_t **vpp, cred_t *cr, int flag, caller_context_t *ct,
   2136 	vsecattr_t *vsecp)
   2137 {
   2138 	int (*func)() = NULL;
   2139 	void *arg0 = NULL;
   2140 
   2141 	ASSERT(vf != NULL);
   2142 	vf->fa_fnode--;
   2143 	vsop_find(vf, &func, int, &arg0, vop_create, femop_create);
   2144 	ASSERT(func != NULL);
   2145 	ASSERT(arg0 != NULL);
   2146 	return ((*func)(arg0, name, vap, excl, mode, vpp, cr, flag, ct, vsecp));
   2147 }
   2148 
   2149 int
   2150 vnext_remove(femarg_t *vf, char *nm, cred_t *cr, caller_context_t *ct,
   2151 	int flags)
   2152 {
   2153 	int (*func)() = NULL;
   2154 	void *arg0 = NULL;
   2155 
   2156 	ASSERT(vf != NULL);
   2157 	vf->fa_fnode--;
   2158 	vsop_find(vf, &func, int, &arg0, vop_remove, femop_remove);
   2159 	ASSERT(func != NULL);
   2160 	ASSERT(arg0 != NULL);
   2161 	return ((*func)(arg0, nm, cr, ct, flags));
   2162 }
   2163 
   2164 int
   2165 vnext_link(femarg_t *vf, vnode_t *svp, char *tnm, cred_t *cr,
   2166 	caller_context_t *ct, int flags)
   2167 {
   2168 	int (*func)() = NULL;
   2169 	void *arg0 = NULL;
   2170 
   2171 	ASSERT(vf != NULL);
   2172 	vf->fa_fnode--;
   2173 	vsop_find(vf, &func, int, &arg0, vop_link, femop_link);
   2174 	ASSERT(func != NULL);
   2175 	ASSERT(arg0 != NULL);
   2176 	return ((*func)(arg0, svp, tnm, cr, ct, flags));
   2177 }
   2178 
   2179 int
   2180 vnext_rename(femarg_t *vf, char *snm, vnode_t *tdvp, char *tnm, cred_t *cr,
   2181 	caller_context_t *ct, int flags)
   2182 {
   2183 	int (*func)() = NULL;
   2184 	void *arg0 = NULL;
   2185 
   2186 	ASSERT(vf != NULL);
   2187 	vf->fa_fnode--;
   2188 	vsop_find(vf, &func, int, &arg0, vop_rename, femop_rename);
   2189 	ASSERT(func != NULL);
   2190 	ASSERT(arg0 != NULL);
   2191 	return ((*func)(arg0, snm, tdvp, tnm, cr, ct, flags));
   2192 }
   2193 
   2194 int
   2195 vnext_mkdir(femarg_t *vf, char *dirname, vattr_t *vap, vnode_t **vpp,
   2196 	cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp)
   2197 {
   2198 	int (*func)() = NULL;
   2199 	void *arg0 = NULL;
   2200 
   2201 	ASSERT(vf != NULL);
   2202 	vf->fa_fnode--;
   2203 	vsop_find(vf, &func, int, &arg0, vop_mkdir, femop_mkdir);
   2204 	ASSERT(func != NULL);
   2205 	ASSERT(arg0 != NULL);
   2206 	return ((*func)(arg0, dirname, vap, vpp, cr, ct, flags, vsecp));
   2207 }
   2208 
   2209 int
   2210 vnext_rmdir(femarg_t *vf, char *nm, vnode_t *cdir, cred_t *cr,
   2211 	caller_context_t *ct, int flags)
   2212 {
   2213 	int (*func)() = NULL;
   2214 	void *arg0 = NULL;
   2215 
   2216 	ASSERT(vf != NULL);
   2217 	vf->fa_fnode--;
   2218 	vsop_find(vf, &func, int, &arg0, vop_rmdir, femop_rmdir);
   2219 	ASSERT(func != NULL);
   2220 	ASSERT(arg0 != NULL);
   2221 	return ((*func)(arg0, nm, cdir, cr, ct, flags));
   2222 }
   2223 
   2224 int
   2225 vnext_readdir(femarg_t *vf, uio_t *uiop, cred_t *cr, int *eofp,
   2226 	caller_context_t *ct, int flags)
   2227 {
   2228 	int (*func)() = NULL;
   2229 	void *arg0 = NULL;
   2230 
   2231 	ASSERT(vf != NULL);
   2232 	vf->fa_fnode--;
   2233 	vsop_find(vf, &func, int, &arg0, vop_readdir, femop_readdir);
   2234 	ASSERT(func != NULL);
   2235 	ASSERT(arg0 != NULL);
   2236 	return ((*func)(arg0, uiop, cr, eofp, ct, flags));
   2237 }
   2238 
   2239 int
   2240 vnext_symlink(femarg_t *vf, char *linkname, vattr_t *vap, char *target,
   2241 	cred_t *cr, caller_context_t *ct, int flags)
   2242 {
   2243 	int (*func)() = NULL;
   2244 	void *arg0 = NULL;
   2245 
   2246 	ASSERT(vf != NULL);
   2247 	vf->fa_fnode--;
   2248 	vsop_find(vf, &func, int, &arg0, vop_symlink, femop_symlink);
   2249 	ASSERT(func != NULL);
   2250 	ASSERT(arg0 != NULL);
   2251 	return ((*func)(arg0, linkname, vap, target, cr, ct, flags));
   2252 }
   2253 
   2254 int
   2255 vnext_readlink(femarg_t *vf, uio_t *uiop, cred_t *cr, caller_context_t *ct)
   2256 {
   2257 	int (*func)() = NULL;
   2258 	void *arg0 = NULL;
   2259 
   2260 	ASSERT(vf != NULL);
   2261 	vf->fa_fnode--;
   2262 	vsop_find(vf, &func, int, &arg0, vop_readlink, femop_readlink);
   2263 	ASSERT(func != NULL);
   2264 	ASSERT(arg0 != NULL);
   2265 	return ((*func)(arg0, uiop, cr, ct));
   2266 }
   2267 
   2268 int
   2269 vnext_fsync(femarg_t *vf, int syncflag, cred_t *cr, caller_context_t *ct)
   2270 {
   2271 	int (*func)() = NULL;
   2272 	void *arg0 = NULL;
   2273 
   2274 	ASSERT(vf != NULL);
   2275 	vf->fa_fnode--;
   2276 	vsop_find(vf, &func, int, &arg0, vop_fsync, femop_fsync);
   2277 	ASSERT(func != NULL);
   2278 	ASSERT(arg0 != NULL);
   2279 	return ((*func)(arg0, syncflag, cr, ct));
   2280 }
   2281 
   2282 void
   2283 vnext_inactive(femarg_t *vf, cred_t *cr, caller_context_t *ct)
   2284 {
   2285 	void (*func)() = NULL;
   2286 	void *arg0 = NULL;
   2287 
   2288 	ASSERT(vf != NULL);
   2289 	vf->fa_fnode--;
   2290 	vsop_find(vf, &func, void, &arg0, vop_inactive, femop_inactive);
   2291 	ASSERT(func != NULL);
   2292 	ASSERT(arg0 != NULL);
   2293 	(*func)(arg0, cr, ct);
   2294 }
   2295 
   2296 int
   2297 vnext_fid(femarg_t *vf, fid_t *fidp, caller_context_t *ct)
   2298 {
   2299 	int (*func)() = NULL;
   2300 	void *arg0 = NULL;
   2301 
   2302 	ASSERT(vf != NULL);
   2303 	vf->fa_fnode--;
   2304 	vsop_find(vf, &func, int, &arg0, vop_fid, femop_fid);
   2305 	ASSERT(func != NULL);
   2306 	ASSERT(arg0 != NULL);
   2307 	return ((*func)(arg0, fidp, ct));
   2308 }
   2309 
   2310 int
   2311 vnext_rwlock(femarg_t *vf, int write_lock, caller_context_t *ct)
   2312 {
   2313 	int (*func)() = NULL;
   2314 	void *arg0 = NULL;
   2315 
   2316 	ASSERT(vf != NULL);
   2317 	vf->fa_fnode--;
   2318 	vsop_find(vf, &func, int, &arg0, vop_rwlock, femop_rwlock);
   2319 	ASSERT(func != NULL);
   2320 	ASSERT(arg0 != NULL);
   2321 	return ((*func)(arg0, write_lock, ct));
   2322 }
   2323 
   2324 void
   2325 vnext_rwunlock(femarg_t *vf, int write_lock, caller_context_t *ct)
   2326 {
   2327 	void (*func)() = NULL;
   2328 	void *arg0 = NULL;
   2329 
   2330 	ASSERT(vf != NULL);
   2331 	vf->fa_fnode--;
   2332 	vsop_find(vf, &func, void, &arg0, vop_rwunlock, femop_rwunlock);
   2333 	ASSERT(func != NULL);
   2334 	ASSERT(arg0 != NULL);
   2335 	(*func)(arg0, write_lock, ct);
   2336 }
   2337 
   2338 int
   2339 vnext_seek(femarg_t *vf, offset_t ooff, offset_t *noffp, caller_context_t *ct)
   2340 {
   2341 	int (*func)() = NULL;
   2342 	void *arg0 = NULL;
   2343 
   2344 	ASSERT(vf != NULL);
   2345 	vf->fa_fnode--;
   2346 	vsop_find(vf, &func, int, &arg0, vop_seek, femop_seek);
   2347 	ASSERT(func != NULL);
   2348 	ASSERT(arg0 != NULL);
   2349 	return ((*func)(arg0, ooff, noffp, ct));
   2350 }
   2351 
   2352 int
   2353 vnext_cmp(femarg_t *vf, vnode_t *vp2, caller_context_t *ct)
   2354 {
   2355 	int (*func)() = NULL;
   2356 	void *arg0 = NULL;
   2357 
   2358 	ASSERT(vf != NULL);
   2359 	vf->fa_fnode--;
   2360 	vsop_find(vf, &func, int, &arg0, vop_cmp, femop_cmp);
   2361 	ASSERT(func != NULL);
   2362 	ASSERT(arg0 != NULL);
   2363 	return ((*func)(arg0, vp2, ct));
   2364 }
   2365 
   2366 int
   2367 vnext_frlock(femarg_t *vf, int cmd, struct flock64 *bfp, int flag,
   2368 	offset_t offset, struct flk_callback *flk_cbp, cred_t *cr,
   2369 	caller_context_t *ct)
   2370 {
   2371 	int (*func)() = NULL;
   2372 	void *arg0 = NULL;
   2373 
   2374 	ASSERT(vf != NULL);
   2375 	vf->fa_fnode--;
   2376 	vsop_find(vf, &func, int, &arg0, vop_frlock, femop_frlock);
   2377 	ASSERT(func != NULL);
   2378 	ASSERT(arg0 != NULL);
   2379 	return ((*func)(arg0, cmd, bfp, flag, offset, flk_cbp, cr, ct));
   2380 }
   2381 
   2382 int
   2383 vnext_space(femarg_t *vf, int cmd, struct flock64 *bfp, int flag,
   2384 	offset_t offset, cred_t *cr, caller_context_t *ct)
   2385 {
   2386 	int (*func)() = NULL;
   2387 	void *arg0 = NULL;
   2388 
   2389 	ASSERT(vf != NULL);
   2390 	vf->fa_fnode--;
   2391 	vsop_find(vf, &func, int, &arg0, vop_space, femop_space);
   2392 	ASSERT(func != NULL);
   2393 	ASSERT(arg0 != NULL);
   2394 	return ((*func)(arg0, cmd, bfp, flag, offset, cr, ct));
   2395 }
   2396 
   2397 int
   2398 vnext_realvp(femarg_t *vf, vnode_t **vpp, caller_context_t *ct)
   2399 {
   2400 	int (*func)() = NULL;
   2401 	void *arg0 = NULL;
   2402 
   2403 	ASSERT(vf != NULL);
   2404 	vf->fa_fnode--;
   2405 	vsop_find(vf, &func, int, &arg0, vop_realvp, femop_realvp);
   2406 	ASSERT(func != NULL);
   2407 	ASSERT(arg0 != NULL);
   2408 	return ((*func)(arg0, vpp, ct));
   2409 }
   2410 
   2411 int
   2412 vnext_getpage(femarg_t *vf, offset_t off, size_t len, uint_t *protp,
   2413 	struct page **plarr, size_t plsz, struct seg *seg, caddr_t addr,
   2414 	enum seg_rw rw, cred_t *cr, caller_context_t *ct)
   2415 {
   2416 	int (*func)() = NULL;
   2417 	void *arg0 = NULL;
   2418 
   2419 	ASSERT(vf != NULL);
   2420 	vf->fa_fnode--;
   2421 	vsop_find(vf, &func, int, &arg0, vop_getpage, femop_getpage);
   2422 	ASSERT(func != NULL);
   2423 	ASSERT(arg0 != NULL);
   2424 	return ((*func)(arg0, off, len, protp, plarr, plsz, seg, addr, rw,
   2425 			cr, ct));
   2426 }
   2427 
   2428 int
   2429 vnext_putpage(femarg_t *vf, offset_t off, size_t len, int flags,
   2430 	cred_t *cr, caller_context_t *ct)
   2431 {
   2432 	int (*func)() = NULL;
   2433 	void *arg0 = NULL;
   2434 
   2435 	ASSERT(vf != NULL);
   2436 	vf->fa_fnode--;
   2437 	vsop_find(vf, &func, int, &arg0, vop_putpage, femop_putpage);
   2438 	ASSERT(func != NULL);
   2439 	ASSERT(arg0 != NULL);
   2440 	return ((*func)(arg0, off, len, flags, cr, ct));
   2441 }
   2442 
   2443 int
   2444 vnext_map(femarg_t *vf, offset_t off, struct as *as, caddr_t *addrp,
   2445 	size_t len, uchar_t prot, uchar_t maxprot, uint_t flags,
   2446 	cred_t *cr, caller_context_t *ct)
   2447 {
   2448 	int (*func)() = NULL;
   2449 	void *arg0 = NULL;
   2450 
   2451 	ASSERT(vf != NULL);
   2452 	vf->fa_fnode--;
   2453 	vsop_find(vf, &func, int, &arg0, vop_map, femop_map);
   2454 	ASSERT(func != NULL);
   2455 	ASSERT(arg0 != NULL);
   2456 	return ((*func)(arg0, off, as, addrp, len, prot, maxprot, flags,
   2457 			cr, ct));
   2458 }
   2459 
   2460 int
   2461 vnext_addmap(femarg_t *vf, offset_t off, struct as *as, caddr_t addr,
   2462 	size_t len, uchar_t prot, uchar_t maxprot, uint_t flags,
   2463 	cred_t *cr, caller_context_t *ct)
   2464 {
   2465 	int (*func)() = NULL;
   2466 	void *arg0 = NULL;
   2467 
   2468 	ASSERT(vf != NULL);
   2469 	vf->fa_fnode--;
   2470 	vsop_find(vf, &func, int, &arg0, vop_addmap, femop_addmap);
   2471 	ASSERT(func != NULL);
   2472 	ASSERT(arg0 != NULL);
   2473 	return ((*func)(arg0, off, as, addr, len, prot, maxprot, flags,
   2474 			cr, ct));
   2475 }
   2476 
   2477 int
   2478 vnext_delmap(femarg_t *vf, offset_t off, struct as *as, caddr_t addr,
   2479 	size_t len, uint_t prot, uint_t maxprot, uint_t flags,
   2480 	cred_t *cr, caller_context_t *ct)
   2481 {
   2482 	int (*func)() = NULL;
   2483 	void *arg0 = NULL;
   2484 
   2485 	ASSERT(vf != NULL);
   2486 	vf->fa_fnode--;
   2487 	vsop_find(vf, &func, int, &arg0, vop_delmap, femop_delmap);
   2488 	ASSERT(func != NULL);
   2489 	ASSERT(arg0 != NULL);
   2490 	return ((*func)(arg0, off, as, addr, len, prot, maxprot, flags,
   2491 			cr, ct));
   2492 }
   2493 
   2494 int
   2495 vnext_poll(femarg_t *vf, short events, int anyyet, short *reventsp,
   2496 	struct pollhead **phpp, caller_context_t *ct)
   2497 {
   2498 	int (*func)() = NULL;
   2499 	void *arg0 = NULL;
   2500 
   2501 	ASSERT(vf != NULL);
   2502 	vf->fa_fnode--;
   2503 	vsop_find(vf, &func, int, &arg0, vop_poll, femop_poll);
   2504 	ASSERT(func != NULL);
   2505 	ASSERT(arg0 != NULL);
   2506 	return ((*func)(arg0, events, anyyet, reventsp, phpp, ct));
   2507 }
   2508 
   2509 int
   2510 vnext_dump(femarg_t *vf, caddr_t addr, int lbdn, int dblks,
   2511 	caller_context_t *ct)
   2512 {
   2513 	int (*func)() = NULL;
   2514 	void *arg0 = NULL;
   2515 
   2516 	ASSERT(vf != NULL);
   2517 	vf->fa_fnode--;
   2518 	vsop_find(vf, &func, int, &arg0, vop_dump, femop_dump);
   2519 	ASSERT(func != NULL);
   2520 	ASSERT(arg0 != NULL);
   2521 	return ((*func)(arg0, addr, lbdn, dblks, ct));
   2522 }
   2523 
   2524 int
   2525 vnext_pathconf(femarg_t *vf, int cmd, ulong_t *valp, cred_t *cr,
   2526 	caller_context_t *ct)
   2527 {
   2528 	int (*func)() = NULL;
   2529 	void *arg0 = NULL;
   2530 
   2531 	ASSERT(vf != NULL);
   2532 	vf->fa_fnode--;
   2533 	vsop_find(vf, &func, int, &arg0, vop_pathconf, femop_pathconf);
   2534 	ASSERT(func != NULL);
   2535 	ASSERT(arg0 != NULL);
   2536 	return ((*func)(arg0, cmd, valp, cr, ct));
   2537 }
   2538 
   2539 int
   2540 vnext_pageio(femarg_t *vf, struct page *pp, u_offset_t io_off,
   2541 	size_t io_len, int flags, cred_t *cr, caller_context_t *ct)
   2542 {
   2543 	int (*func)() = NULL;
   2544 	void *arg0 = NULL;
   2545 
   2546 	ASSERT(vf != NULL);
   2547 	vf->fa_fnode--;
   2548 	vsop_find(vf, &func, int, &arg0, vop_pageio, femop_pageio);
   2549 	ASSERT(func != NULL);
   2550 	ASSERT(arg0 != NULL);
   2551 	return ((*func)(arg0, pp, io_off, io_len, flags, cr, ct));
   2552 }
   2553 
   2554 int
   2555 vnext_dumpctl(femarg_t *vf, int action, int *blkp, caller_context_t *ct)
   2556 {
   2557 	int (*func)() = NULL;
   2558 	void *arg0 = NULL;
   2559 
   2560 	ASSERT(vf != NULL);
   2561 	vf->fa_fnode--;
   2562 	vsop_find(vf, &func, int, &arg0, vop_dumpctl, femop_dumpctl);
   2563 	ASSERT(func != NULL);
   2564 	ASSERT(arg0 != NULL);
   2565 	return ((*func)(arg0, action, blkp, ct));
   2566 }
   2567 
   2568 void
   2569 vnext_dispose(femarg_t *vf, struct page *pp, int flag, int dn, cred_t *cr,
   2570 	caller_context_t *ct)
   2571 {
   2572 	void (*func)() = NULL;
   2573 	void *arg0 = NULL;
   2574 
   2575 	ASSERT(vf != NULL);
   2576 	vf->fa_fnode--;
   2577 	vsop_find(vf, &func, void, &arg0, vop_dispose, femop_dispose);
   2578 	ASSERT(func != NULL);
   2579 	ASSERT(arg0 != NULL);
   2580 	(*func)(arg0, pp, flag, dn, cr, ct);
   2581 }
   2582 
   2583 int
   2584 vnext_setsecattr(femarg_t *vf, vsecattr_t *vsap, int flag, cred_t *cr,
   2585 	caller_context_t *ct)
   2586 {
   2587 	int (*func)() = NULL;
   2588 	void *arg0 = NULL;
   2589 
   2590 	ASSERT(vf != NULL);
   2591 	vf->fa_fnode--;
   2592 	vsop_find(vf, &func, int, &arg0, vop_setsecattr, femop_setsecattr);
   2593 	ASSERT(func != NULL);
   2594 	ASSERT(arg0 != NULL);
   2595 	return ((*func)(arg0, vsap, flag, cr, ct));
   2596 }
   2597 
   2598 int
   2599 vnext_getsecattr(femarg_t *vf, vsecattr_t *vsap, int flag, cred_t *cr,
   2600 	caller_context_t *ct)
   2601 {
   2602 	int (*func)() = NULL;
   2603 	void *arg0 = NULL;
   2604 
   2605 	ASSERT(vf != NULL);
   2606 	vf->fa_fnode--;
   2607 	vsop_find(vf, &func, int, &arg0, vop_getsecattr, femop_getsecattr);
   2608 	ASSERT(func != NULL);
   2609 	ASSERT(arg0 != NULL);
   2610 	return ((*func)(arg0, vsap, flag, cr, ct));
   2611 }
   2612 
   2613 int
   2614 vnext_shrlock(femarg_t *vf, int cmd, struct shrlock *shr, int flag,
   2615 	cred_t *cr, caller_context_t *ct)
   2616 {
   2617 	int (*func)() = NULL;
   2618 	void *arg0 = NULL;
   2619 
   2620 	ASSERT(vf != NULL);
   2621 	vf->fa_fnode--;
   2622 	vsop_find(vf, &func, int, &arg0, vop_shrlock, femop_shrlock);
   2623 	ASSERT(func != NULL);
   2624 	ASSERT(arg0 != NULL);
   2625 	return ((*func)(arg0, cmd, shr, flag, cr, ct));
   2626 }
   2627 
   2628 int
   2629 vnext_vnevent(femarg_t *vf, vnevent_t vnevent, vnode_t *dvp, char *cname,
   2630     caller_context_t *ct)
   2631 {
   2632 	int (*func)() = NULL;
   2633 	void *arg0 = NULL;
   2634 
   2635 	ASSERT(vf != NULL);
   2636 	vf->fa_fnode--;
   2637 	vsop_find(vf, &func, int, &arg0, vop_vnevent, femop_vnevent);
   2638 	ASSERT(func != NULL);
   2639 	ASSERT(arg0 != NULL);
   2640 	return ((*func)(arg0, vnevent, dvp, cname, ct));
   2641 }
   2642 
   2643 int
   2644 vfsnext_mount(fsemarg_t *vf, vnode_t *mvp, struct mounta *uap, cred_t *cr)
   2645 {
   2646 	int (*func)() = NULL;
   2647 	void *arg0 = NULL;
   2648 
   2649 	ASSERT(vf != NULL);
   2650 	vf->fa_fnode--;
   2651 	vfsop_find(vf, &func, int, &arg0, vfs_mount, fsemop_mount);
   2652 	ASSERT(func != NULL);
   2653 	ASSERT(arg0 != NULL);
   2654 	return ((*func)(arg0, mvp, uap, cr));
   2655 }
   2656 
   2657 int
   2658 vfsnext_unmount(fsemarg_t *vf, int flag, cred_t *cr)
   2659 {
   2660 	int (*func)() = NULL;
   2661 	void *arg0 = NULL;
   2662 
   2663 	ASSERT(vf != NULL);
   2664 	vf->fa_fnode--;
   2665 	vfsop_find(vf, &func, int, &arg0, vfs_unmount, fsemop_unmount);
   2666 	ASSERT(func != NULL);
   2667 	ASSERT(arg0 != NULL);
   2668 	return ((*func)(arg0, flag, cr));
   2669 }
   2670 
   2671 int
   2672 vfsnext_root(fsemarg_t *vf, vnode_t **vpp)
   2673 {
   2674 	int (*func)() = NULL;
   2675 	void *arg0 = NULL;
   2676 
   2677 	ASSERT(vf != NULL);
   2678 	vf->fa_fnode--;
   2679 	vfsop_find(vf, &func, int, &arg0, vfs_root, fsemop_root);
   2680 	ASSERT(func != NULL);
   2681 	ASSERT(arg0 != NULL);
   2682 	return ((*func)(arg0, vpp));
   2683 }
   2684 
   2685 int
   2686 vfsnext_statvfs(fsemarg_t *vf, statvfs64_t *sp)
   2687 {
   2688 	int (*func)() = NULL;
   2689 	void *arg0 = NULL;
   2690 
   2691 	ASSERT(vf != NULL);
   2692 	vf->fa_fnode--;
   2693 	vfsop_find(vf, &func, int, &arg0, vfs_statvfs, fsemop_statvfs);
   2694 	ASSERT(func != NULL);
   2695 	ASSERT(arg0 != NULL);
   2696 	return ((*func)(arg0, sp));
   2697 }
   2698 
   2699 int
   2700 vfsnext_sync(fsemarg_t *vf, short flag, cred_t *cr)
   2701 {
   2702 	int (*func)() = NULL;
   2703 	void *arg0 = NULL;
   2704 
   2705 	ASSERT(vf != NULL);
   2706 	vf->fa_fnode--;
   2707 	vfsop_find(vf, &func, int, &arg0, vfs_sync, fsemop_sync);
   2708 	ASSERT(func != NULL);
   2709 	ASSERT(arg0 != NULL);
   2710 	return ((*func)(arg0, flag, cr));
   2711 }
   2712 
   2713 int
   2714 vfsnext_vget(fsemarg_t *vf, vnode_t **vpp, fid_t *fidp)
   2715 {
   2716 	int (*func)() = NULL;
   2717 	void *arg0 = NULL;
   2718 
   2719 	ASSERT(vf != NULL);
   2720 	vf->fa_fnode--;
   2721 	vfsop_find(vf, &func, int, &arg0, vfs_vget, fsemop_vget);
   2722 	ASSERT(func != NULL);
   2723 	ASSERT(arg0 != NULL);
   2724 	return ((*func)(arg0, vpp, fidp));
   2725 }
   2726 
   2727 int
   2728 vfsnext_mountroot(fsemarg_t *vf, enum whymountroot reason)
   2729 {
   2730 	int (*func)() = NULL;
   2731 	void *arg0 = NULL;
   2732 
   2733 	ASSERT(vf != NULL);
   2734 	vf->fa_fnode--;
   2735 	vfsop_find(vf, &func, int, &arg0, vfs_mountroot, fsemop_mountroot);
   2736 	ASSERT(func != NULL);
   2737 	ASSERT(arg0 != NULL);
   2738 	return ((*func)(arg0, reason));
   2739 }
   2740 
   2741 void
   2742 vfsnext_freevfs(fsemarg_t *vf)
   2743 {
   2744 	void (*func)() = NULL;
   2745 	void *arg0 = NULL;
   2746 
   2747 	ASSERT(vf != NULL);
   2748 	vf->fa_fnode--;
   2749 	vfsop_find(vf, &func, void, &arg0, vfs_freevfs, fsemop_freevfs);
   2750 	ASSERT(func != NULL);
   2751 	ASSERT(arg0 != NULL);
   2752 	(*func)(arg0);
   2753 }
   2754 
   2755 int
   2756 vfsnext_vnstate(fsemarg_t *vf, vnode_t *vp, vntrans_t nstate)
   2757 {
   2758 	int (*func)() = NULL;
   2759 	void *arg0 = NULL;
   2760 
   2761 	ASSERT(vf != NULL);
   2762 	vf->fa_fnode--;
   2763 	vfsop_find(vf, &func, int, &arg0, vfs_vnstate, fsemop_vnstate);
   2764 	ASSERT(func != NULL);
   2765 	ASSERT(arg0 != NULL);
   2766 	return ((*func)(arg0, vp, nstate));
   2767 }
   2768 
   2769 
   2770 /*
   2771  * Create a new fem_head and associate with the vnode.
   2772  * To keep the unaugmented vnode access path lock free, we spin
   2773  * update this - create a new one, then try and install it. If
   2774  * we fail to install, release the old one and pretend we succeeded.
   2775  */
   2776 
   2777 static struct fem_head *
   2778 new_femhead(struct fem_head **hp)
   2779 {
   2780 	struct fem_head	*head;
   2781 
   2782 	head = kmem_alloc(sizeof (*head), KM_SLEEP);
   2783 	mutex_init(&head->femh_lock, NULL, MUTEX_DEFAULT, NULL);
   2784 	head->femh_list = NULL;
   2785 	if (casptr(hp, NULL, head) != NULL) {
   2786 		kmem_free(head, sizeof (*head));
   2787 		head = *hp;
   2788 	}
   2789 	return (head);
   2790 }
   2791 
   2792 /*
   2793  * Create a fem_list.  The fem_list that gets returned is in a
   2794  * very rudimentary state and MUST NOT be used until it's initialized
   2795  * (usually by femlist_construct() or fem_dup_list()).  The refcount
   2796  * and size is set properly and top-of-stack is set to the "guard" node
   2797  * just to be consistent.
   2798  *
   2799  * If anyone were to accidentally trying to run on this fem_list before
   2800  * it's initialized then the system would likely panic trying to defererence
   2801  * the (NULL) fn_op pointer.
   2802  *
   2803  */
   2804 static struct fem_list *
   2805 femlist_create(int numnodes)
   2806 {
   2807 	struct fem_list	*sp;
   2808 
   2809 	sp = kmem_alloc(fl_ntob(numnodes), KM_SLEEP);
   2810 	sp->feml_refc  = 1;
   2811 	sp->feml_ssize = numnodes;
   2812 	sp->feml_nodes[0] = FEM_GUARD(FEMTYPE_NULL);
   2813 	sp->feml_tos = 0;
   2814 	return (sp);
   2815 }
   2816 
   2817 /*
   2818  * Construct a new femlist.
   2819  * The list is constructed with the appropriate type of guard to
   2820  * anchor it, and inserts the original ops.
   2821  */
   2822 
   2823 static struct fem_list *
   2824 femlist_construct(void *baseops, int type, int numnodes)
   2825 {
   2826 	struct fem_list	*sp;
   2827 
   2828 	sp = femlist_create(numnodes);
   2829 	sp->feml_nodes[0] = FEM_GUARD(type);
   2830 	sp->feml_nodes[1].fn_op.anon = baseops;
   2831 	sp->feml_nodes[1].fn_available = NULL;
   2832 	sp->feml_nodes[1].fn_av_hold = NULL;
   2833 	sp->feml_nodes[1].fn_av_rele = NULL;
   2834 	sp->feml_tos = 1;
   2835 	return (sp);
   2836 }
   2837 
   2838 /*
   2839  * Duplicate a list.  Copy the original list to the clone.
   2840  *
   2841  * NOTE: The caller must have the fem_head for the lists locked.
   2842  * Assuming the appropriate lock is held and the caller has done the
   2843  * math right, the clone list should be big enough to old the original.
   2844  */
   2845 
   2846 static void
   2847 fem_dup_list(struct fem_list *orig, struct fem_list *clone)
   2848 {
   2849 	int		i;
   2850 
   2851 	ASSERT(clone->feml_ssize >= orig->feml_ssize);
   2852 
   2853 	bcopy(orig->feml_nodes, clone->feml_nodes,
   2854 		sizeof (orig->feml_nodes[0]) * orig->feml_ssize);
   2855 	clone->feml_tos = orig->feml_tos;
   2856 	/*
   2857 	 * Now that we've copied the old list (orig) to the new list (clone),
   2858 	 * we need to walk the new list and put another hold on fn_available.
   2859 	 */
   2860 	for (i = clone->feml_tos; i > 0; i--) {
   2861 		struct fem_node *fnp = &clone->feml_nodes[i];
   2862 
   2863 		if (fnp->fn_av_hold)
   2864 			(*(fnp->fn_av_hold))(fnp->fn_available);
   2865 	}
   2866 }
   2867 
   2868 
   2869 static int
   2870 fem_push_node(
   2871 	struct fem_head **hp,
   2872 	void **baseops,
   2873 	int type,
   2874 	struct fem_node *nnode,
   2875 	femhow_t how)
   2876 {
   2877 	struct fem_head	*hd;
   2878 	struct fem_list	*list;
   2879 	void		*oldops;
   2880 	int		retry;
   2881 	int		error = 0;
   2882 	int		i;
   2883 
   2884 	/* Validate the node */
   2885 	if ((nnode->fn_op.anon == NULL) || (nnode->fn_available == NULL)) {
   2886 		return (EINVAL);
   2887 	}
   2888 
   2889 	if ((hd = *hp) == NULL) { /* construct a proto-list */
   2890 		hd = new_femhead(hp);
   2891 	}
   2892 	/*
   2893 	 * RULE: once a femhead has been pushed onto a object, it cannot be
   2894 	 * removed until the object is destroyed.  It can be deactivated by
   2895 	 * placing the original 'object operations' onto the object, which
   2896 	 * will ignore the femhead.
   2897 	 * The loop will exist when the femh_list has space to push a monitor
   2898 	 * onto it.
   2899 	 */
   2900 	do {
   2901 		retry = 1;
   2902 		list = fem_lock(hd);
   2903 		oldops = *baseops;
   2904 
   2905 		if (list != NULL) {
   2906 			if (list->feml_tos+1 < list->feml_ssize) {
   2907 				retry = 0;
   2908 			} else {
   2909 				struct fem_list	*olist = list;
   2910 
   2911 				fem_addref(olist);
   2912 				fem_unlock(hd);
   2913 				list = femlist_create(olist->feml_ssize * 2);
   2914 				(void) fem_lock(hd);
   2915 				if (hd->femh_list == olist) {
   2916 					if (list->feml_ssize <=
   2917 							olist->feml_ssize) {
   2918 						/*
   2919 						 * We have a new list, but it
   2920 						 * is too small to hold the
   2921 						 * original contents plus the
   2922 						 * one to push.  Release the
   2923 						 * new list and start over.
   2924 						 */
   2925 						fem_release(list);
   2926 						fem_unlock(hd);
   2927 					} else {
   2928 						/*
   2929 						 * Life is good:  Our new list
   2930 						 * is big enough to hold the
   2931 						 * original list (olist) + 1.
   2932 						 */
   2933 						fem_dup_list(olist, list);
   2934 						/* orphan this list */
   2935 						hd->femh_list = list;
   2936 						(void) fem_delref(olist);
   2937 						retry = 0;
   2938 					}
   2939 				} else {
   2940 					/* concurrent update, retry */
   2941 					fem_release(list);
   2942 					fem_unlock(hd);
   2943 				}
   2944 				/* remove the reference we added above */
   2945 				fem_release(olist);
   2946 			}
   2947 		} else {
   2948 			fem_unlock(hd);
   2949 			list = femlist_construct(oldops, type, NNODES_DEFAULT);
   2950 			(void) fem_lock(hd);
   2951 			if (hd->femh_list != NULL || *baseops != oldops) {
   2952 				/* concurrent update, retry */
   2953 				fem_release(list);
   2954 				fem_unlock(hd);
   2955 			} else {
   2956 				hd->femh_list = list;
   2957 				*baseops = FEM_HEAD(type);
   2958 				retry = 0;
   2959 			}
   2960 		}
   2961 	} while (retry);
   2962 
   2963 	ASSERT(mutex_owner(&hd->femh_lock) == curthread);
   2964 	ASSERT(list->feml_tos+1 < list->feml_ssize);
   2965 
   2966 	/*
   2967 	 * The presence of "how" will modify the behavior of how/if
   2968 	 * nodes are pushed.  If it's FORCE, then we can skip
   2969 	 * all the checks and push it on.
   2970 	 */
   2971 	if (how != FORCE) {
   2972 		/* Start at the top and work our way down */
   2973 		for (i = list->feml_tos; i > 0; i--) {
   2974 			void *fn_av = list->feml_nodes[i].fn_available;
   2975 			void *fn_op = list->feml_nodes[i].fn_op.anon;
   2976 
   2977 			/*
   2978 			 * OPARGUNIQ means that this node should not
   2979 			 * be pushed on if a node with the same op/avail
   2980 			 * combination exists.  This situation returns
   2981 			 * EBUSY.
   2982 			 *
   2983 			 * OPUNIQ means that this node should not be
   2984 			 * pushed on if a node with the same op exists.
   2985 			 * This situation also returns EBUSY.
   2986 			 */
   2987 			switch (how) {
   2988 
   2989 			case OPUNIQ:
   2990 				if (fn_op == nnode->fn_op.anon) {
   2991 					error = EBUSY;
   2992 				}
   2993 				break;
   2994 
   2995 			case OPARGUNIQ:
   2996 				if ((fn_op == nnode->fn_op.anon) &&
   2997 				    (fn_av == nnode->fn_available)) {
   2998 					error = EBUSY;
   2999 				}
   3000 				break;
   3001 
   3002 			default:
   3003 				error = EINVAL;	/* Unexpected value */
   3004 				break;
   3005 			}
   3006 
   3007 			if (error)
   3008 				break;
   3009 		}
   3010 	}
   3011 
   3012 	if (error == 0) {
   3013 		/*
   3014 		 * If no errors, slap the node on the list.
   3015 		 * Note: The following is a structure copy.
   3016 		 */
   3017 		list->feml_nodes[++(list->feml_tos)] = *nnode;
   3018 	}
   3019 
   3020 	fem_unlock(hd);
   3021 	return (error);
   3022 }
   3023 
   3024 /*
   3025  * Remove a node by copying the list above it down a notch.
   3026  * If the list is busy, replace it with an idle one and work
   3027  * upon it.
   3028  * A node matches if the opset matches and the datap matches or is
   3029  * null.
   3030  */
   3031 
   3032 static int
   3033 remove_node(struct fem_list *sp, void **baseops, void *opset, void *datap)
   3034 {
   3035 	int	i;
   3036 	struct fem_node	*fn;
   3037 
   3038 	for (i = sp->feml_tos; i > 0; i--) {
   3039 		fn = sp->feml_nodes+i;
   3040 		if (fn->fn_op.anon == opset &&
   3041 		    (fn->fn_available == datap || datap == NULL)) {
   3042 			break;
   3043 		}
   3044 	}
   3045 	if (i == 0) {
   3046 		return (EINVAL);
   3047 	}
   3048 
   3049 	/*
   3050 	 * At this point we have a node in-hand (*fn) that we are about
   3051 	 * to remove by overwriting it and adjusting the stack.  This is
   3052 	 * our last chance to do anything with this node so we do the
   3053 	 * release on the arg.
   3054 	 */
   3055 	if (fn->fn_av_rele)
   3056 		(*(fn->fn_av_rele))(fn->fn_available);
   3057 
   3058 	while (i++ < sp->feml_tos) {
   3059 		sp->feml_nodes[i-1] = sp->feml_nodes[i];
   3060 	}
   3061 	if (--(sp->feml_tos) == 1) { /* Empty, restore ops */
   3062 		*baseops = sp->feml_nodes[1].fn_op.anon;
   3063 	}
   3064 	return (0);
   3065 }
   3066 
   3067 static int
   3068 fem_remove_node(struct fem_head *fh, void **baseops, void *opset, void *datap)
   3069 {
   3070 	struct fem_list *sp;
   3071 	int		error = 0;
   3072 	int		retry;
   3073 
   3074 	if (fh == NULL) {
   3075 		return (EINVAL);
   3076 	}
   3077 
   3078 	do {
   3079 		retry = 0;
   3080 		if ((sp = fem_lock(fh)) == NULL) {
   3081 			fem_unlock(fh);
   3082 			error = EINVAL;
   3083 		} else if (sp->feml_refc == 1) {
   3084 			error = remove_node(sp, baseops, opset, datap);
   3085 			if (sp->feml_tos == 1) {
   3086 				/*
   3087 				 * The top-of-stack was decremented by
   3088 				 * remove_node().  If it got down to 1,
   3089 				 * then the base ops were replaced and we
   3090 				 * call fem_release() which will free the
   3091 				 * fem_list.
   3092 				 */
   3093 				fem_release(sp);
   3094 				fh->femh_list = NULL;
   3095 				/* XXX - Do we need a membar_producer() call? */
   3096 			}
   3097 			fem_unlock(fh);
   3098 		} else {
   3099 			/* busy - install a new one without this monitor */
   3100 			struct fem_list *nsp;	/* New fem_list being cloned */
   3101 
   3102 			fem_addref(sp);
   3103 			fem_unlock(fh);
   3104 			nsp = femlist_create(sp->feml_ssize);
   3105 			if (fem_lock(fh) == sp) {
   3106 				/*
   3107 				 * We popped out of the lock, created a
   3108 				 * list, then relocked.  If we're in here
   3109 				 * then the fem_head points to the same list
   3110 				 * it started with.
   3111 				 */
   3112 				fem_dup_list(sp, nsp);
   3113 				error = remove_node(nsp, baseops, opset, datap);
   3114 				if (error != 0) {
   3115 					fem_release(nsp);
   3116 				} else if (nsp->feml_tos == 1) {
   3117 					/* New list now empty, tear it down */
   3118 					fem_release(nsp);
   3119 					fh->femh_list = NULL;
   3120 				} else {
   3121 					fh->femh_list = nsp;
   3122 				}
   3123 				(void) fem_delref(sp);
   3124 			} else {
   3125 				/* List changed while locked, try again... */
   3126 				fem_release(nsp);
   3127 				retry = 1;
   3128 			}
   3129 			/*
   3130 			 * If error is set, then we tried to remove a node
   3131 			 * from the list, but failed.  This means that we
   3132 			 * will still be using this list so don't release it.
   3133 			 */
   3134 			if (error == 0)
   3135 				fem_release(sp);
   3136 			fem_unlock(fh);
   3137 		}
   3138 	} while (retry);
   3139 	return (error);
   3140 }
   3141 
   3142 
   3143 /*
   3144  * perform operation on each element until one returns non zero
   3145  */
   3146 static int
   3147 fem_walk_list(
   3148 	struct fem_list *sp,
   3149 	int (*f)(struct fem_node *, void *, void *),
   3150 	void *mon,
   3151 	void *arg)
   3152 {
   3153 	int	i;
   3154 
   3155 	ASSERT(sp != NULL);
   3156 	for (i = sp->feml_tos; i > 0; i--) {
   3157 		if ((*f)(sp->feml_nodes+i, mon, arg) != 0) {
   3158 			break;
   3159 		}
   3160 	}
   3161 	return (i);
   3162 }
   3163 
   3164 /*
   3165  * companion comparison functions.
   3166  */
   3167 static int
   3168 fem_compare_mon(struct fem_node *n, void *mon, void *arg)
   3169 {
   3170 	return ((n->fn_op.anon == mon) && (n->fn_available == arg));
   3171 }
   3172 
   3173 /*
   3174  * VNODE interposition.
   3175  */
   3176 
   3177 int
   3178 fem_create(char *name, const struct fs_operation_def *templ,
   3179     fem_t **actual)
   3180 {
   3181 	int	unused_ops = 0;
   3182 	int	e;
   3183 	fem_t	*newf;
   3184 
   3185 	newf = fem_alloc();
   3186 	newf->name = name;
   3187 	newf->templ = templ;
   3188 
   3189 	e =  fs_build_vector(newf, &unused_ops, fem_opdef, templ);
   3190 	if (e != 0) {
   3191 #ifdef DEBUG
   3192 		cmn_err(CE_WARN, "fem_create: error %d building vector", e);
   3193 #endif
   3194 		fem_free(newf);
   3195 	} else {
   3196 		*actual = newf;
   3197 	}
   3198 	return (e);
   3199 }
   3200 
   3201 int
   3202 fem_install(
   3203 	vnode_t *vp,		/* Vnode on which monitor is being installed */
   3204 	fem_t *mon,		/* Monitor operations being installed */
   3205 	void *arg,		/* Opaque data used by monitor */
   3206 	femhow_t how,		/* Installation control */
   3207 	void (*arg_hold)(void *),	/* Hold routine for "arg" */
   3208 	void (*arg_rele)(void *))	/* Release routine for "arg" */
   3209 {
   3210 	int	error;
   3211 	struct fem_node	nnode;
   3212 
   3213 	nnode.fn_available = arg;
   3214 	nnode.fn_op.fem = mon;
   3215 	nnode.fn_av_hold = arg_hold;
   3216 	nnode.fn_av_rele = arg_rele;
   3217 	/*
   3218 	 * If we have a non-NULL hold function, do the hold right away.
   3219 	 * The release is done in remove_node().
   3220 	 */
   3221 	if (arg_hold)
   3222 		(*arg_hold)(arg);
   3223 
   3224 	error = fem_push_node(&vp->v_femhead, (void **)&vp->v_op, FEMTYPE_VNODE,
   3225 			&nnode, how);
   3226 
   3227 	/* If there was an error then the monitor wasn't pushed */
   3228 	if (error && arg_rele)
   3229 		(*arg_rele)(arg);
   3230 
   3231 	return (error);
   3232 }
   3233 
   3234 int
   3235 fem_is_installed(vnode_t *v, fem_t *mon, void *arg)
   3236 {
   3237 	int	e;
   3238 	struct fem_list	*fl;
   3239 
   3240 	fl = fem_get(v->v_femhead);
   3241 	if (fl != NULL) {
   3242 		e = fem_walk_list(fl, fem_compare_mon, (void *)mon, arg);
   3243 		fem_release(fl);
   3244 		return (e);
   3245 	}
   3246 	return (0);
   3247 }
   3248 
   3249 int
   3250 fem_uninstall(vnode_t *v, fem_t *mon, void *arg)
   3251 {
   3252 	int	e;
   3253 	e = fem_remove_node(v->v_femhead, (void **)&v->v_op,
   3254 			(void *)mon, arg);
   3255 	return (e);
   3256 }
   3257 
   3258 void
   3259 fem_setvnops(vnode_t *v, vnodeops_t *newops)
   3260 {
   3261 	vnodeops_t	*r;
   3262 
   3263 	ASSERT(v != NULL);
   3264 	ASSERT(newops != NULL);
   3265 
   3266 	do {
   3267 		r = v->v_op;
   3268 		membar_consumer();
   3269 		if (v->v_femhead != NULL) {
   3270 			struct fem_list	*fl;
   3271 			if ((fl = fem_lock(v->v_femhead)) != NULL) {
   3272 				fl->feml_nodes[1].fn_op.vnode = newops;
   3273 				fem_unlock(v->v_femhead);
   3274 				return;
   3275 			}
   3276 			fem_unlock(v->v_femhead);
   3277 		}
   3278 	} while (casptr(&v->v_op, r, newops) != r);
   3279 }
   3280 
   3281 vnodeops_t *
   3282 fem_getvnops(vnode_t *v)
   3283 {
   3284 	vnodeops_t	*r;
   3285 
   3286 	ASSERT(v != NULL);
   3287 
   3288 	r = v->v_op;
   3289 	membar_consumer();
   3290 	if (v->v_femhead != NULL) {
   3291 		struct fem_list	*fl;
   3292 		if ((fl = fem_lock(v->v_femhead)) != NULL) {
   3293 			r = fl->feml_nodes[1].fn_op.vnode;
   3294 		}
   3295 		fem_unlock(v->v_femhead);
   3296 	}
   3297 	return (r);
   3298 }
   3299 
   3300 
   3301 /*
   3302  * VFS interposition
   3303  */
   3304 int
   3305 fsem_create(char *name, const struct fs_operation_def *templ,
   3306     fsem_t **actual)
   3307 {
   3308 	int	unused_ops = 0;
   3309 	int	e;
   3310 	fsem_t	*newv;
   3311 
   3312 	newv = fsem_alloc();
   3313 	newv->name = (const char *)name;
   3314 	newv->templ = templ;
   3315 
   3316 	e = fs_build_vector(newv, &unused_ops, fsem_opdef, templ);
   3317 	if (e != 0) {
   3318 #ifdef DEBUG
   3319 		cmn_err(CE_WARN, "fsem_create: error %d building vector", e);
   3320 #endif
   3321 		fsem_free(newv);
   3322 	} else {
   3323 		*actual = newv;
   3324 	}
   3325 	return (e);
   3326 }
   3327 
   3328 /*
   3329  * These need to be re-written, but there should be more common bits.
   3330  */
   3331 
   3332 int
   3333 fsem_is_installed(struct vfs *v, fsem_t *mon, void *arg)
   3334 {
   3335 	struct fem_list	*fl;
   3336 
   3337 	if (v->vfs_implp == NULL)
   3338 		return (0);
   3339 
   3340 	fl = fem_get(v->vfs_femhead);
   3341 	if (fl != NULL) {
   3342 		int	e;
   3343 		e = fem_walk_list(fl, fem_compare_mon, (void *)mon, arg);
   3344 		fem_release(fl);
   3345 		return (e);
   3346 	}
   3347 	return (0);
   3348 }
   3349 
   3350 int
   3351 fsem_install(
   3352 	struct vfs *vfsp,	/* VFS on which monitor is being installed */
   3353 	fsem_t *mon,		/* Monitor operations being installed */
   3354 	void *arg,		/* Opaque data used by monitor */
   3355 	femhow_t how,		/* Installation control */
   3356 	void (*arg_hold)(void *),	/* Hold routine for "arg" */
   3357 	void (*arg_rele)(void *))	/* Release routine for "arg" */
   3358 {
   3359 	int	error;
   3360 	struct fem_node	nnode;
   3361 
   3362 	/* If this vfs hasn't been properly initialized, fail the install */
   3363 	if (vfsp->vfs_implp == NULL)
   3364 		return (EINVAL);
   3365 
   3366 	nnode.fn_available = arg;
   3367 	nnode.fn_op.fsem = mon;
   3368 	nnode.fn_av_hold = arg_hold;
   3369 	nnode.fn_av_rele = arg_rele;
   3370 	/*
   3371 	 * If we have a non-NULL hold function, do the hold right away.
   3372 	 * The release is done in remove_node().
   3373 	 */
   3374 	if (arg_hold)
   3375 		(*arg_hold)(arg);
   3376 
   3377 	error = fem_push_node(&vfsp->vfs_femhead, (void **)&vfsp->vfs_op,
   3378 			FEMTYPE_VFS, &nnode, how);
   3379 
   3380 	/* If there was an error then the monitor wasn't pushed */
   3381 	if (error && arg_rele)
   3382 		(*arg_rele)(arg);
   3383 
   3384 	return (error);
   3385 }
   3386 
   3387 int
   3388 fsem_uninstall(struct vfs *v, fsem_t *mon, void *arg)
   3389 {
   3390 	int	e;
   3391 
   3392 	if (v->vfs_implp == NULL)
   3393 		return (EINVAL);
   3394 
   3395 	e = fem_remove_node(v->vfs_femhead, (void **)&v->vfs_op,
   3396 			(void *)mon, arg);
   3397 	return (e);
   3398 }
   3399 
   3400 void
   3401 fsem_setvfsops(vfs_t *v, vfsops_t *newops)
   3402 {
   3403 	vfsops_t	*r;
   3404 
   3405 	ASSERT(v != NULL);
   3406 	ASSERT(newops != NULL);
   3407 	ASSERT(v->vfs_implp);
   3408 
   3409 	do {
   3410 		r = v->vfs_op;
   3411 		membar_consumer();
   3412 		if (v->vfs_femhead != NULL) {
   3413 			struct fem_list	*fl;
   3414 			if ((fl = fem_lock(v->vfs_femhead)) != NULL) {
   3415 				fl->feml_nodes[1].fn_op.vfs = newops;
   3416 				fem_unlock(v->vfs_femhead);
   3417 				return;
   3418 			}
   3419 			fem_unlock(v->vfs_femhead);
   3420 		}
   3421 	} while (casptr(&v->vfs_op, r, newops) != r);
   3422 }
   3423 
   3424 vfsops_t *
   3425 fsem_getvfsops(vfs_t *v)
   3426 {
   3427 	vfsops_t	*r;
   3428 
   3429 	ASSERT(v != NULL);
   3430 	ASSERT(v->vfs_implp);
   3431 
   3432 	r = v->vfs_op;
   3433 	membar_consumer();
   3434 	if (v->vfs_femhead != NULL) {
   3435 		struct fem_list	*fl;
   3436 		if ((fl = fem_lock(v->vfs_femhead)) != NULL) {
   3437 			r = fl->feml_nodes[1].fn_op.vfs;
   3438 		}
   3439 		fem_unlock(v->vfs_femhead);
   3440 	}
   3441 	return (r);
   3442 }
   3443 
   3444 /*
   3445  * Setup FEM.
   3446  */
   3447 void
   3448 fem_init()
   3449 {
   3450 	struct fem_type_info   *fi;
   3451 
   3452 	/*
   3453 	 * This femtype is only used for fem_list creation so we only
   3454 	 * need the "guard" to be initialized so that feml_tos has
   3455 	 * some rudimentary meaning.  A fem_list must not be used until
   3456 	 * it has been initialized (either via femlist_construct() or
   3457 	 * fem_dup_list()).  Anything that tries to use this fem_list
   3458 	 * before it's actually initialized would panic the system as
   3459 	 * soon as "fn_op" (NULL) is dereferenced.
   3460 	 */
   3461 	fi = femtype + FEMTYPE_NULL;
   3462 	fi->errf = fem_err;
   3463 	fi->guard.fn_available = (void *)&fi->guard;
   3464 	fi->guard.fn_av_hold = NULL;
   3465 	fi->guard.fn_av_rele = NULL;
   3466 	fi->guard.fn_op.anon = NULL;
   3467 
   3468 	fi = femtype + FEMTYPE_VNODE;
   3469 	fi->errf = fem_err;
   3470 	fi->head.fn_available = NULL;
   3471 	fi->head.fn_av_hold = NULL;
   3472 	fi->head.fn_av_rele = NULL;
   3473 	(void) vn_make_ops("fem-head", fhead_vn_spec, &fi->head.fn_op.vnode);
   3474 	fi->guard.fn_available = (void *)&fi->guard;
   3475 	fi->guard.fn_av_hold = NULL;
   3476 	fi->guard.fn_av_rele = NULL;
   3477 	(void) fem_create("fem-guard", fem_guard_ops, &fi->guard.fn_op.fem);
   3478 
   3479 	fi = femtype + FEMTYPE_VFS;
   3480 	fi->errf = fsem_err;
   3481 	fi->head.fn_available = NULL;
   3482 	fi->head.fn_av_hold = NULL;
   3483 	fi->head.fn_av_rele = NULL;
   3484 	(void) vfs_makefsops(fshead_vfs_spec, &fi->head.fn_op.vfs);
   3485 
   3486 	fi->guard.fn_available = (void *)&fi->guard;
   3487 	fi->guard.fn_av_hold = NULL;
   3488 	fi->guard.fn_av_rele = NULL;
   3489 	(void) fsem_create("fem-guard", fsem_guard_ops, &fi->guard.fn_op.fsem);
   3490 }
   3491 
   3492 
   3493 int
   3494 fem_err()
   3495 {
   3496 	cmn_err(CE_PANIC, "fem/vnode operations corrupt");
   3497 	return (0);
   3498 }
   3499 
   3500 int
   3501 fsem_err()
   3502 {
   3503 	cmn_err(CE_PANIC, "fem/vfs operations corrupt");
   3504 	return (0);
   3505 }
   3506