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