xref: /titanic_50/usr/src/uts/common/fs/fem.c (revision 015a6ef6781cc3ceba8ad3bfbae98449b6002a1f)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 #pragma ident	"%Z%%M%	%I%	%E% SMI"
26 
27 #include <sys/types.h>
28 #include <sys/atomic.h>
29 #include <sys/kmem.h>
30 #include <sys/mutex.h>
31 #include <sys/errno.h>
32 #include <sys/param.h>
33 #include <sys/sysmacros.h>
34 #include <sys/systm.h>
35 #include <sys/cmn_err.h>
36 #include <sys/debug.h>
37 
38 #include <sys/fem.h>
39 #include <sys/vfs.h>
40 #include <sys/vnode.h>
41 #include <sys/vfs_opreg.h>
42 
43 #define	NNODES_DEFAULT	8	/* Default number of nodes in a fem_list */
44 /*
45  * fl_ntob(n) - Fem_list: number of nodes to bytes
46  * Given the number of nodes in a fem_list return the size, in bytes,
47  * of the fem_list structure.
48  */
49 #define	fl_ntob(n)	(sizeof (struct fem_list) + \
50 			((n) - 1) * sizeof (struct fem_node))
51 
52 typedef enum {
53 	FEMTYPE_NULL,	/* Uninitialized */
54 	FEMTYPE_VNODE,
55 	FEMTYPE_VFS,
56 	FEMTYPE_NTYPES
57 } femtype_t;
58 
59 #define	FEM_HEAD(_t) femtype[(_t)].head.fn_op.anon
60 #define	FEM_GUARD(_t) femtype[(_t)].guard
61 
62 static struct fem_type_info {
63 	struct fem_node		head;
64 	struct fem_node		guard;
65 	femop_t			*errf;
66 }	femtype[FEMTYPE_NTYPES];
67 
68 
69 /*
70  * For each type, two tables - the translation offset definition, which
71  * is used by fs_build_vector to layout the operation(s) vector; and the
72  * guard_operation_vector which protects from stack under-run.
73  */
74 
75 int fem_err();
76 int fsem_err();
77 
78 
79 #define	_FEMOPDEF(name, member)  \
80 	{ VOPNAME_##name, offsetof(fem_t, femop_##member), NULL, fem_err }
81 
82 static fs_operation_trans_def_t	fem_opdef[] = {
83 	_FEMOPDEF(OPEN,		open),
84 	_FEMOPDEF(CLOSE,	close),
85 	_FEMOPDEF(READ,		read),
86 	_FEMOPDEF(WRITE,	write),
87 	_FEMOPDEF(IOCTL,	ioctl),
88 	_FEMOPDEF(SETFL,	setfl),
89 	_FEMOPDEF(GETATTR,	getattr),
90 	_FEMOPDEF(SETATTR,	setattr),
91 	_FEMOPDEF(ACCESS,	access),
92 	_FEMOPDEF(LOOKUP,	lookup),
93 	_FEMOPDEF(CREATE,	create),
94 	_FEMOPDEF(REMOVE,	remove),
95 	_FEMOPDEF(LINK,		link),
96 	_FEMOPDEF(RENAME,	rename),
97 	_FEMOPDEF(MKDIR,	mkdir),
98 	_FEMOPDEF(RMDIR,	rmdir),
99 	_FEMOPDEF(READDIR,	readdir),
100 	_FEMOPDEF(SYMLINK,	symlink),
101 	_FEMOPDEF(READLINK,	readlink),
102 	_FEMOPDEF(FSYNC,	fsync),
103 	_FEMOPDEF(INACTIVE,	inactive),
104 	_FEMOPDEF(FID,		fid),
105 	_FEMOPDEF(RWLOCK,	rwlock),
106 	_FEMOPDEF(RWUNLOCK,	rwunlock),
107 	_FEMOPDEF(SEEK,		seek),
108 	_FEMOPDEF(CMP,		cmp),
109 	_FEMOPDEF(FRLOCK,	frlock),
110 	_FEMOPDEF(SPACE,	space),
111 	_FEMOPDEF(REALVP,	realvp),
112 	_FEMOPDEF(GETPAGE,	getpage),
113 	_FEMOPDEF(PUTPAGE,	putpage),
114 	_FEMOPDEF(MAP,		map),
115 	_FEMOPDEF(ADDMAP,	addmap),
116 	_FEMOPDEF(DELMAP,	delmap),
117 	_FEMOPDEF(POLL,		poll),
118 	_FEMOPDEF(DUMP,		dump),
119 	_FEMOPDEF(PATHCONF,	pathconf),
120 	_FEMOPDEF(PAGEIO,	pageio),
121 	_FEMOPDEF(DUMPCTL,	dumpctl),
122 	_FEMOPDEF(DISPOSE,	dispose),
123 	_FEMOPDEF(SETSECATTR,	setsecattr),
124 	_FEMOPDEF(GETSECATTR,	getsecattr),
125 	_FEMOPDEF(SHRLOCK,	shrlock),
126 	_FEMOPDEF(VNEVENT,	vnevent),
127 	{ NULL, 0, NULL, NULL }
128 };
129 
130 
131 #define	_FEMGUARD(name, ignore)  \
132 	{ VOPNAME_##name, (femop_t *)fem_err }
133 
134 static struct fs_operation_def fem_guard_ops[] = {
135 	_FEMGUARD(OPEN,		open),
136 	_FEMGUARD(CLOSE,	close),
137 	_FEMGUARD(READ,		read),
138 	_FEMGUARD(WRITE,	write),
139 	_FEMGUARD(IOCTL,	ioctl),
140 	_FEMGUARD(SETFL,	setfl),
141 	_FEMGUARD(GETATTR,	getattr),
142 	_FEMGUARD(SETATTR,	setattr),
143 	_FEMGUARD(ACCESS,	access),
144 	_FEMGUARD(LOOKUP,	lookup),
145 	_FEMGUARD(CREATE,	create),
146 	_FEMGUARD(REMOVE,	remove),
147 	_FEMGUARD(LINK,		link),
148 	_FEMGUARD(RENAME,	rename),
149 	_FEMGUARD(MKDIR,	mkdir),
150 	_FEMGUARD(RMDIR,	rmdir),
151 	_FEMGUARD(READDIR,	readdir),
152 	_FEMGUARD(SYMLINK,	symlink),
153 	_FEMGUARD(READLINK,	readlink),
154 	_FEMGUARD(FSYNC,	fsync),
155 	_FEMGUARD(INACTIVE,	inactive),
156 	_FEMGUARD(FID,		fid),
157 	_FEMGUARD(RWLOCK,	rwlock),
158 	_FEMGUARD(RWUNLOCK,	rwunlock),
159 	_FEMGUARD(SEEK,		seek),
160 	_FEMGUARD(CMP,		cmp),
161 	_FEMGUARD(FRLOCK,	frlock),
162 	_FEMGUARD(SPACE,	space),
163 	_FEMGUARD(REALVP,	realvp),
164 	_FEMGUARD(GETPAGE,	getpage),
165 	_FEMGUARD(PUTPAGE,	putpage),
166 	_FEMGUARD(MAP,		map),
167 	_FEMGUARD(ADDMAP,	addmap),
168 	_FEMGUARD(DELMAP,	delmap),
169 	_FEMGUARD(POLL,		poll),
170 	_FEMGUARD(DUMP,		dump),
171 	_FEMGUARD(PATHCONF,	pathconf),
172 	_FEMGUARD(PAGEIO,	pageio),
173 	_FEMGUARD(DUMPCTL,	dumpctl),
174 	_FEMGUARD(DISPOSE,	dispose),
175 	_FEMGUARD(SETSECATTR,	setsecattr),
176 	_FEMGUARD(GETSECATTR,	getsecattr),
177 	_FEMGUARD(SHRLOCK,	shrlock),
178 	_FEMGUARD(VNEVENT,	vnevent),
179 	{ NULL, NULL }
180 };
181 
182 
183 #define	_FSEMOPDEF(name, member)  \
184 	{ VFSNAME_##name, offsetof(fsem_t, fsemop_##member), NULL, fsem_err }
185 
186 static fs_operation_trans_def_t fsem_opdef[] = {
187 	_FSEMOPDEF(MOUNT, 	mount),
188 	_FSEMOPDEF(UNMOUNT,	unmount),
189 	_FSEMOPDEF(ROOT,	root),
190 	_FSEMOPDEF(STATVFS,	statvfs),
191 	_FSEMOPDEF(SYNC,	sync),
192 	_FSEMOPDEF(VGET,	vget),
193 	_FSEMOPDEF(MOUNTROOT,	mountroot),
194 	_FSEMOPDEF(FREEVFS,	freevfs),
195 	_FSEMOPDEF(VNSTATE,	vnstate),
196 	{ NULL, 0, NULL, NULL }
197 };
198 
199 #define	_FSEMGUARD(name, ignore)  \
200 	{ VFSNAME_##name, (femop_t *)fsem_err }
201 
202 static struct fs_operation_def fsem_guard_ops[] = {
203 	_FSEMGUARD(MOUNT, 	mount),
204 	_FSEMGUARD(UNMOUNT,	unmount),
205 	_FSEMGUARD(ROOT,	root),
206 	_FSEMGUARD(STATVFS,	statvfs),
207 	_FSEMGUARD(SYNC,	sync),
208 	_FSEMGUARD(VGET,	vget),
209 	_FSEMGUARD(MOUNTROOT,	mountroot),
210 	_FSEMGUARD(FREEVFS,	freevfs),
211 	_FSEMGUARD(VNSTATE,	vnstate),
212 	{ NULL, NULL}
213 };
214 
215 
216 /*
217  * vsop_find, vfsop_find -
218  *
219  * These macros descend the stack until they find either a basic
220  * vnode/vfs operation [ indicated by a null fn_available ] or a
221  * stacked item where this method is non-null [_vsop].
222  *
223  * The DEBUG one is written with a single function which manually applies
224  * the structure offsets.  It can have additional debugging support.
225  */
226 
227 #ifndef DEBUG
228 
229 #define	vsop_find(ap, func, funct, arg0, _vop, _vsop) \
230 for (;;) { \
231 	if ((ap)->fa_fnode->fn_available == NULL) { \
232 		*(func) = (funct (*)())((ap)->fa_fnode->fn_op.vnode->_vop); \
233 		*(arg0) = (void *)(ap)->fa_vnode.vp; \
234 		break;	\
235 	} else if ((*(func) = (funct (*)())((ap)->fa_fnode->fn_op.fem->_vsop))\
236 		    != NULL) { \
237 		*(arg0) = (void *) (ap); \
238 		break;	\
239 	} else { \
240 		(ap)->fa_fnode--; \
241 	} \
242 } \
243 
244 #define	vfsop_find(ap, func, funct, arg0, _vop, _vsop) \
245 for (;;) { \
246 	if ((ap)->fa_fnode->fn_available == NULL) { \
247 		*(func) = (funct (*)())((ap)->fa_fnode->fn_op.vfs->_vop); \
248 		*(arg0) = (void *)(ap)->fa_vnode.vp; \
249 		break; \
250 	} else if ((*(func) = (funct (*)())((ap)->fa_fnode->fn_op.fsem->_vsop))\
251 		    != NULL) { \
252 		*(arg0) = (void *) (ap); \
253 		break; \
254 	} else { \
255 		(ap)->fa_fnode--; \
256 	} \
257 } \
258 
259 #else
260 
261 #define	vsop_find(ap, func, funct, arg0, _vop, _vsop) \
262 	*(arg0) = _op_find((ap), (void **)(func), \
263 			offsetof(vnodeops_t, _vop), offsetof(fem_t, _vsop))
264 
265 #define	vfsop_find(ap, func, funct, arg0, _fop, _fsop) \
266 	*(arg0) = _op_find((ap), (void **)(func), \
267 			offsetof(vfsops_t, _fop), offsetof(fsem_t, _fsop))
268 
269 static void *
270 _op_find(femarg_t *ap, void **fp, int offs0, int offs1)
271 {
272 	void *ptr;
273 	for (;;) {
274 		struct fem_node	*fnod = ap->fa_fnode;
275 		if (fnod->fn_available == NULL) {
276 			*fp = *(void **)((char *)fnod->fn_op.anon + offs0);
277 			ptr = (void *)(ap->fa_vnode.anon);
278 			break;
279 		} else if ((*fp = *(void **)((char *)fnod->fn_op.anon+offs1))
280 		    != NULL) {
281 			ptr = (void *)(ap);
282 			break;
283 		} else {
284 			ap->fa_fnode--;
285 		}
286 	}
287 	return (ptr);
288 }
289 #endif
290 
291 static fem_t *
292 fem_alloc()
293 {
294 	fem_t	*p;
295 
296 	p = (fem_t *)kmem_alloc(sizeof (*p), KM_SLEEP);
297 	return (p);
298 }
299 
300 void
301 fem_free(fem_t *p)
302 {
303 	kmem_free(p, sizeof (*p));
304 }
305 
306 static fsem_t *
307 fsem_alloc()
308 {
309 	fsem_t	*p;
310 
311 	p = (fsem_t *)kmem_alloc(sizeof (*p), KM_SLEEP);
312 	return (p);
313 }
314 
315 void
316 fsem_free(fsem_t *p)
317 {
318 	kmem_free(p, sizeof (*p));
319 }
320 
321 
322 /*
323  * fem_get, fem_release - manage reference counts on the stack.
324  *
325  * The list of monitors can be updated while operations are in
326  * progress on the object.
327  *
328  * The reference count facilitates this by counting the number of
329  * current accessors, and deconstructing the list when it is exhausted.
330  *
331  * fem_lock() is required to:
332  *	look at femh_list
333  *	update what femh_list points to
334  *	update femh_list
335  *	increase femh_list->feml_refc.
336  *
337  * the feml_refc can decrement without holding the lock;
338  * when feml_refc becomes zero, the list is destroyed.
339  *
340  */
341 
342 static struct fem_list *
343 fem_lock(struct fem_head *fp)
344 {
345 	struct fem_list	*sp = NULL;
346 
347 	ASSERT(fp != NULL);
348 	mutex_enter(&fp->femh_lock);
349 	sp = fp->femh_list;
350 	return (sp);
351 }
352 
353 static void
354 fem_unlock(struct fem_head *fp)
355 {
356 	ASSERT(fp != NULL);
357 	mutex_exit(&fp->femh_lock);
358 }
359 
360 /*
361  * Addref can only be called while its head->lock is held.
362  */
363 
364 static void
365 fem_addref(struct fem_list *sp)
366 {
367 	atomic_add_32(&sp->feml_refc, 1);
368 }
369 
370 static uint32_t
371 fem_delref(struct fem_list *sp)
372 {
373 	return (atomic_add_32_nv(&sp->feml_refc, -1));
374 }
375 
376 static struct fem_list *
377 fem_get(struct fem_head *fp)
378 {
379 	struct fem_list *sp = NULL;
380 
381 	if (fp != NULL) {
382 		if ((sp = fem_lock(fp)) != NULL) {
383 			fem_addref(sp);
384 		}
385 		fem_unlock(fp);
386 	}
387 	return (sp);
388 }
389 
390 static void
391 fem_release(struct fem_list *sp)
392 {
393 	int	i;
394 
395 	ASSERT(sp->feml_refc != 0);
396 	if (fem_delref(sp) == 0) {
397 		/*
398 		 * Before freeing the list, we need to release the
399 		 * caller-provided data.
400 		 */
401 		for (i = sp->feml_tos; i > 0; i--) {
402 			struct fem_node *fnp = &sp->feml_nodes[i];
403 
404 			if (fnp->fn_av_rele)
405 				(*(fnp->fn_av_rele))(fnp->fn_available);
406 		}
407 		kmem_free(sp, fl_ntob(sp->feml_ssize));
408 	}
409 }
410 
411 
412 /*
413  * These are the 'head' operations which perform the interposition.
414  *
415  * This set must be 1:1, onto with the (vnodeops, vfsos).
416  *
417  * If there is a desire to globally disable interposition for a particular
418  * method, the corresponding 'head' routine should unearth the base method
419  * and invoke it directly rather than bypassing the function.
420  *
421  * All the functions are virtually the same, save for names, types & args.
422  *  1. get a reference to the monitor stack for this object.
423  *  2. store the top of stack into the femarg structure.
424  *  3. store the basic object (vnode *, vnode **, vfs *) in the femarg struc.
425  *  4. invoke the "top" method for this object.
426  *  5. release the reference to the monitor stack.
427  *
428  */
429 
430 static int
431 vhead_open(vnode_t **vpp, int mode, cred_t *cr, caller_context_t *ct)
432 {
433 	femarg_t	farg;
434 	struct fem_list	*femsp;
435 	int		(*func)();
436 	void		*arg0;
437 	int		errc;
438 
439 	if ((femsp = fem_lock((*vpp)->v_femhead)) == NULL) {
440 		func = (int (*)()) ((*vpp)->v_op->vop_open);
441 		arg0 = (void *)vpp;
442 		fem_unlock((*vpp)->v_femhead);
443 		errc = (*func)(arg0, mode, cr, ct);
444 	} else {
445 		fem_addref(femsp);
446 		fem_unlock((*vpp)->v_femhead);
447 		farg.fa_vnode.vpp = vpp;
448 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
449 		vsop_find(&farg, &func, int, &arg0, vop_open, femop_open);
450 		errc = (*func)(arg0, mode, cr, ct);
451 		fem_release(femsp);
452 	}
453 	return (errc);
454 }
455 
456 static int
457 vhead_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
458 	caller_context_t *ct)
459 {
460 	femarg_t	farg;
461 	struct fem_list	*femsp;
462 	int		(*func)();
463 	void		*arg0;
464 	int		errc;
465 
466 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
467 		func = (int (*)()) (vp->v_op->vop_close);
468 		arg0 = vp;
469 		fem_unlock(vp->v_femhead);
470 		errc = (*func)(arg0, flag, count, offset, cr, ct);
471 	} else {
472 		fem_addref(femsp);
473 		fem_unlock(vp->v_femhead);
474 		farg.fa_vnode.vp = vp;
475 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
476 		vsop_find(&farg, &func, int, &arg0, vop_close, femop_close);
477 		errc = (*func)(arg0, flag, count, offset, cr, ct);
478 		fem_release(femsp);
479 	}
480 	return (errc);
481 }
482 
483 static int
484 vhead_read(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr,
485 	caller_context_t *ct)
486 {
487 	femarg_t	farg;
488 	struct fem_list	*femsp;
489 	int		(*func)();
490 	void		*arg0;
491 	int		errc;
492 
493 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
494 		func = (int (*)()) (vp->v_op->vop_read);
495 		arg0 = vp;
496 		fem_unlock(vp->v_femhead);
497 		errc = (*func)(arg0, uiop, ioflag, cr, ct);
498 	} else {
499 		fem_addref(femsp);
500 		fem_unlock(vp->v_femhead);
501 		farg.fa_vnode.vp = vp;
502 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
503 		vsop_find(&farg, &func, int, &arg0, vop_read, femop_read);
504 		errc = (*func)(arg0, uiop, ioflag, cr, ct);
505 		fem_release(femsp);
506 	}
507 	return (errc);
508 }
509 
510 static int
511 vhead_write(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr,
512 	caller_context_t *ct)
513 {
514 	femarg_t	farg;
515 	struct fem_list	*femsp;
516 	int		(*func)();
517 	void		*arg0;
518 	int		errc;
519 
520 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
521 		func = (int (*)()) (vp->v_op->vop_write);
522 		arg0 = vp;
523 		fem_unlock(vp->v_femhead);
524 		errc = (*func)(arg0, uiop, ioflag, cr, ct);
525 	} else {
526 		fem_addref(femsp);
527 		fem_unlock(vp->v_femhead);
528 		farg.fa_vnode.vp = vp;
529 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
530 		vsop_find(&farg, &func, int, &arg0, vop_write, femop_write);
531 		errc = (*func)(arg0, uiop, ioflag, cr, ct);
532 		fem_release(femsp);
533 	}
534 	return (errc);
535 }
536 
537 static int
538 vhead_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr,
539 	int *rvalp, caller_context_t *ct)
540 {
541 	femarg_t	farg;
542 	struct fem_list	*femsp;
543 	int		(*func)();
544 	void		*arg0;
545 	int		errc;
546 
547 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
548 		func = (int (*)()) (vp->v_op->vop_ioctl);
549 		arg0 = vp;
550 		fem_unlock(vp->v_femhead);
551 		errc = (*func)(arg0, cmd, arg, flag, cr, rvalp, ct);
552 	} else {
553 		fem_addref(femsp);
554 		fem_unlock(vp->v_femhead);
555 		farg.fa_vnode.vp = vp;
556 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
557 		vsop_find(&farg, &func, int, &arg0, vop_ioctl, femop_ioctl);
558 		errc = (*func)(arg0, cmd, arg, flag, cr, rvalp, ct);
559 		fem_release(femsp);
560 	}
561 	return (errc);
562 }
563 
564 static int
565 vhead_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr,
566 	caller_context_t *ct)
567 {
568 	femarg_t	farg;
569 	struct fem_list	*femsp;
570 	int		(*func)();
571 	void		*arg0;
572 	int		errc;
573 
574 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
575 		func = (int (*)()) (vp->v_op->vop_setfl);
576 		arg0 = vp;
577 		fem_unlock(vp->v_femhead);
578 		errc = (*func)(arg0, oflags, nflags, cr, ct);
579 	} else {
580 		fem_addref(femsp);
581 		fem_unlock(vp->v_femhead);
582 		farg.fa_vnode.vp = vp;
583 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
584 		vsop_find(&farg, &func, int, &arg0, vop_setfl, femop_setfl);
585 		errc = (*func)(arg0, oflags, nflags, cr, ct);
586 		fem_release(femsp);
587 	}
588 	return (errc);
589 }
590 
591 static int
592 vhead_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
593 	caller_context_t *ct)
594 {
595 	femarg_t	farg;
596 	struct fem_list	*femsp;
597 	int		(*func)();
598 	void		*arg0;
599 	int		errc;
600 
601 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
602 		func = (int (*)()) (vp->v_op->vop_getattr);
603 		arg0 = vp;
604 		fem_unlock(vp->v_femhead);
605 		errc = (*func)(arg0, vap, flags, cr, ct);
606 	} else {
607 		fem_addref(femsp);
608 		fem_unlock(vp->v_femhead);
609 		farg.fa_vnode.vp = vp;
610 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
611 		vsop_find(&farg, &func, int, &arg0, vop_getattr,
612 		    femop_getattr);
613 		errc = (*func)(arg0, vap, flags, cr, ct);
614 		fem_release(femsp);
615 	}
616 	return (errc);
617 }
618 
619 static int
620 vhead_setattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
621 	caller_context_t *ct)
622 {
623 	femarg_t	farg;
624 	struct fem_list	*femsp;
625 	int		(*func)();
626 	void		*arg0;
627 	int		errc;
628 
629 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
630 		func = (int (*)()) (vp->v_op->vop_setattr);
631 		arg0 = vp;
632 		fem_unlock(vp->v_femhead);
633 		errc = (*func)(arg0, vap, flags, cr, ct);
634 	} else {
635 		fem_addref(femsp);
636 		fem_unlock(vp->v_femhead);
637 		farg.fa_vnode.vp = vp;
638 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
639 		vsop_find(&farg, &func, int, &arg0, vop_setattr,
640 		    femop_setattr);
641 		errc = (*func)(arg0, vap, flags, cr, ct);
642 		fem_release(femsp);
643 	}
644 	return (errc);
645 }
646 
647 static int
648 vhead_access(vnode_t *vp, int mode, int flags, cred_t *cr,
649 	caller_context_t *ct)
650 {
651 	femarg_t	farg;
652 	struct fem_list	*femsp;
653 	int		(*func)();
654 	void		*arg0;
655 	int		errc;
656 
657 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
658 		func = (int (*)()) (vp->v_op->vop_access);
659 		arg0 = vp;
660 		fem_unlock(vp->v_femhead);
661 		errc = (*func)(arg0, mode, flags, cr, ct);
662 	} else {
663 		fem_addref(femsp);
664 		fem_unlock(vp->v_femhead);
665 		farg.fa_vnode.vp = vp;
666 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
667 		vsop_find(&farg, &func, int, &arg0, vop_access,
668 		    femop_access);
669 		errc = (*func)(arg0, mode, flags, cr, ct);
670 		fem_release(femsp);
671 	}
672 	return (errc);
673 }
674 
675 static int
676 vhead_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp,
677 	int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
678 	int *direntflags, pathname_t *realpnp)
679 {
680 	femarg_t	farg;
681 	struct fem_list	*femsp;
682 	int		(*func)();
683 	void		*arg0;
684 	int		errc;
685 
686 	if ((femsp = fem_lock(dvp->v_femhead)) == NULL) {
687 		func = (int (*)()) (dvp->v_op->vop_lookup);
688 		arg0 = dvp;
689 		fem_unlock(dvp->v_femhead);
690 		errc = (*func)(arg0, nm, vpp, pnp, flags, rdir, cr, ct,
691 		    direntflags, realpnp);
692 	} else {
693 		fem_addref(femsp);
694 		fem_unlock(dvp->v_femhead);
695 		farg.fa_vnode.vp = dvp;
696 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
697 		vsop_find(&farg, &func, int, &arg0, vop_lookup,
698 		    femop_lookup);
699 		errc = (*func)(arg0, nm, vpp, pnp, flags, rdir, cr, ct,
700 		    direntflags, realpnp);
701 		fem_release(femsp);
702 	}
703 	return (errc);
704 }
705 
706 static int
707 vhead_create(vnode_t *dvp, char *name, vattr_t *vap, vcexcl_t excl,
708 	int mode, vnode_t **vpp, cred_t *cr, int flag, caller_context_t *ct,
709 	vsecattr_t *vsecp)
710 {
711 	femarg_t	farg;
712 	struct fem_list	*femsp;
713 	int		(*func)();
714 	void		*arg0;
715 	int		errc;
716 
717 	if ((femsp = fem_lock(dvp->v_femhead)) == NULL) {
718 		func = (int (*)()) (dvp->v_op->vop_create);
719 		arg0 = dvp;
720 		fem_unlock(dvp->v_femhead);
721 		errc = (*func)(arg0, name, vap, excl, mode, vpp, cr, flag,
722 		    ct, vsecp);
723 	} else {
724 		fem_addref(femsp);
725 		fem_unlock(dvp->v_femhead);
726 		farg.fa_vnode.vp = dvp;
727 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
728 		vsop_find(&farg, &func, int, &arg0, vop_create,
729 		    femop_create);
730 		errc = (*func)(arg0, name, vap, excl, mode, vpp, cr, flag,
731 		    ct, vsecp);
732 		fem_release(femsp);
733 	}
734 	return (errc);
735 }
736 
737 static int
738 vhead_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct,
739 	int flags)
740 {
741 	femarg_t	farg;
742 	struct fem_list	*femsp;
743 	int		(*func)();
744 	void		*arg0;
745 	int		errc;
746 
747 	if ((femsp = fem_lock(dvp->v_femhead)) == NULL) {
748 		func = (int (*)()) (dvp->v_op->vop_remove);
749 		arg0 = dvp;
750 		fem_unlock(dvp->v_femhead);
751 		errc = (*func)(arg0, nm, cr, ct, flags);
752 	} else {
753 		fem_addref(femsp);
754 		fem_unlock(dvp->v_femhead);
755 		farg.fa_vnode.vp = dvp;
756 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
757 		vsop_find(&farg, &func, int, &arg0, vop_remove,
758 		    femop_remove);
759 		errc = (*func)(arg0, nm, cr, ct, flags);
760 		fem_release(femsp);
761 	}
762 	return (errc);
763 }
764 
765 static int
766 vhead_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr,
767 	caller_context_t *ct, int flags)
768 {
769 	femarg_t	farg;
770 	struct fem_list	*femsp;
771 	int		(*func)();
772 	void		*arg0;
773 	int		errc;
774 
775 	if ((femsp = fem_lock(tdvp->v_femhead)) == NULL) {
776 		func = (int (*)()) (tdvp->v_op->vop_link);
777 		arg0 = tdvp;
778 		fem_unlock(tdvp->v_femhead);
779 		errc = (*func)(arg0, svp, tnm, cr, ct, flags);
780 	} else {
781 		fem_addref(femsp);
782 		fem_unlock(tdvp->v_femhead);
783 		farg.fa_vnode.vp = tdvp;
784 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
785 		vsop_find(&farg, &func, int, &arg0, vop_link, femop_link);
786 		errc = (*func)(arg0, svp, tnm, cr, ct, flags);
787 		fem_release(femsp);
788 	}
789 	return (errc);
790 }
791 
792 static int
793 vhead_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
794 	cred_t *cr, caller_context_t *ct, int flags)
795 {
796 	femarg_t	farg;
797 	struct fem_list	*femsp;
798 	int		(*func)();
799 	void		*arg0;
800 	int		errc;
801 
802 	if ((femsp = fem_lock(sdvp->v_femhead)) == NULL) {
803 		func = (int (*)()) (sdvp->v_op->vop_rename);
804 		arg0 = sdvp;
805 		fem_unlock(sdvp->v_femhead);
806 		errc = (*func)(arg0, snm, tdvp, tnm, cr, ct, flags);
807 	} else {
808 		fem_addref(femsp);
809 		fem_unlock(sdvp->v_femhead);
810 		farg.fa_vnode.vp = sdvp;
811 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
812 		vsop_find(&farg, &func, int, &arg0, vop_rename,
813 		    femop_rename);
814 		errc = (*func)(arg0, snm, tdvp, tnm, cr, ct, flags);
815 		fem_release(femsp);
816 	}
817 	return (errc);
818 }
819 
820 static int
821 vhead_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t **vpp,
822 	cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp)
823 {
824 	femarg_t	farg;
825 	struct fem_list	*femsp;
826 	int		(*func)();
827 	void		*arg0;
828 	int		errc;
829 
830 	if ((femsp = fem_lock(dvp->v_femhead)) == NULL) {
831 		func = (int (*)()) (dvp->v_op->vop_mkdir);
832 		arg0 = dvp;
833 		fem_unlock(dvp->v_femhead);
834 		errc = (*func)(arg0, dirname, vap, vpp, cr, ct, flags, vsecp);
835 	} else {
836 		fem_addref(femsp);
837 		fem_unlock(dvp->v_femhead);
838 		farg.fa_vnode.vp = dvp;
839 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
840 		vsop_find(&farg, &func, int, &arg0, vop_mkdir, femop_mkdir);
841 		errc = (*func)(arg0, dirname, vap, vpp, cr, ct, flags, vsecp);
842 		fem_release(femsp);
843 	}
844 	return (errc);
845 }
846 
847 static int
848 vhead_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
849 	caller_context_t *ct, int flags)
850 {
851 	femarg_t	farg;
852 	struct fem_list	*femsp;
853 	int		(*func)();
854 	void		*arg0;
855 	int		errc;
856 
857 	if ((femsp = fem_lock(dvp->v_femhead)) == NULL) {
858 		func = (int (*)()) (dvp->v_op->vop_rmdir);
859 		arg0 = dvp;
860 		fem_unlock(dvp->v_femhead);
861 		errc = (*func)(arg0, nm, cdir, cr, ct, flags);
862 	} else {
863 		fem_addref(femsp);
864 		fem_unlock(dvp->v_femhead);
865 		farg.fa_vnode.vp = dvp;
866 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
867 		vsop_find(&farg, &func, int, &arg0, vop_rmdir, femop_rmdir);
868 		errc = (*func)(arg0, nm, cdir, cr, ct, flags);
869 		fem_release(femsp);
870 	}
871 	return (errc);
872 }
873 
874 static int
875 vhead_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp,
876 	caller_context_t *ct, int flags)
877 {
878 	femarg_t	farg;
879 	struct fem_list	*femsp;
880 	int		(*func)();
881 	void		*arg0;
882 	int		errc;
883 
884 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
885 		func = (int (*)()) (vp->v_op->vop_readdir);
886 		arg0 = vp;
887 		fem_unlock(vp->v_femhead);
888 		errc = (*func)(arg0, uiop, cr, eofp, ct, flags);
889 	} else {
890 		fem_addref(femsp);
891 		fem_unlock(vp->v_femhead);
892 		farg.fa_vnode.vp = vp;
893 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
894 		vsop_find(&farg, &func, int, &arg0, vop_readdir,
895 		    femop_readdir);
896 		errc = (*func)(arg0, uiop, cr, eofp, ct, flags);
897 		fem_release(femsp);
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, offset_t lbdn, offset_t dblks,
1401     caller_context_t *ct)
1402 {
1403 	femarg_t	farg;
1404 	struct fem_list	*femsp;
1405 	int		(*func)();
1406 	void		*arg0;
1407 	int		errc;
1408 
1409 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
1410 		func = (int (*)()) (vp->v_op->vop_dump);
1411 		arg0 = vp;
1412 		fem_unlock(vp->v_femhead);
1413 		errc = (*func)(arg0, addr, lbdn, dblks, ct);
1414 	} else {
1415 		fem_addref(femsp);
1416 		fem_unlock(vp->v_femhead);
1417 		farg.fa_vnode.vp = vp;
1418 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
1419 		vsop_find(&farg, &func, int, &arg0, vop_dump, femop_dump);
1420 		errc = (*func)(arg0, addr, lbdn, dblks, ct);
1421 		fem_release(femsp);
1422 	}
1423 	return (errc);
1424 }
1425 
1426 static int
1427 vhead_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
1428 	caller_context_t *ct)
1429 {
1430 	femarg_t	farg;
1431 	struct fem_list	*femsp;
1432 	int		(*func)();
1433 	void		*arg0;
1434 	int		errc;
1435 
1436 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
1437 		func = (int (*)()) (vp->v_op->vop_pathconf);
1438 		arg0 = vp;
1439 		fem_unlock(vp->v_femhead);
1440 		errc = (*func)(arg0, cmd, valp, cr, ct);
1441 	} else {
1442 		fem_addref(femsp);
1443 		fem_unlock(vp->v_femhead);
1444 		farg.fa_vnode.vp = vp;
1445 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
1446 		vsop_find(&farg, &func, int, &arg0, vop_pathconf,
1447 		    femop_pathconf);
1448 		errc = (*func)(arg0, cmd, valp, cr, ct);
1449 		fem_release(femsp);
1450 	}
1451 	return (errc);
1452 }
1453 
1454 static int
1455 vhead_pageio(vnode_t *vp, struct page *pp, u_offset_t io_off,
1456 	size_t io_len, int flags, cred_t *cr, caller_context_t *ct)
1457 {
1458 	femarg_t	farg;
1459 	struct fem_list	*femsp;
1460 	int		(*func)();
1461 	void		*arg0;
1462 	int		errc;
1463 
1464 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
1465 		func = (int (*)()) (vp->v_op->vop_pageio);
1466 		arg0 = vp;
1467 		fem_unlock(vp->v_femhead);
1468 		errc = (*func)(arg0, pp, io_off, io_len, flags, cr, ct);
1469 	} else {
1470 		fem_addref(femsp);
1471 		fem_unlock(vp->v_femhead);
1472 		farg.fa_vnode.vp = vp;
1473 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
1474 		vsop_find(&farg, &func, int, &arg0, vop_pageio,
1475 		    femop_pageio);
1476 		errc = (*func)(arg0, pp, io_off, io_len, flags, cr, ct);
1477 		fem_release(femsp);
1478 	}
1479 	return (errc);
1480 }
1481 
1482 static int
1483 vhead_dumpctl(vnode_t *vp, int action, offset_t *blkp, caller_context_t *ct)
1484 {
1485 	femarg_t	farg;
1486 	struct fem_list	*femsp;
1487 	int		(*func)();
1488 	void		*arg0;
1489 	int		errc;
1490 
1491 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
1492 		func = (int (*)()) (vp->v_op->vop_dumpctl);
1493 		arg0 = vp;
1494 		fem_unlock(vp->v_femhead);
1495 		errc = (*func)(arg0, action, blkp, ct);
1496 	} else {
1497 		fem_addref(femsp);
1498 		fem_unlock(vp->v_femhead);
1499 		farg.fa_vnode.vp = vp;
1500 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
1501 		vsop_find(&farg, &func, int, &arg0, vop_dumpctl,
1502 		    femop_dumpctl);
1503 		errc = (*func)(arg0, action, blkp, ct);
1504 		fem_release(femsp);
1505 	}
1506 	return (errc);
1507 }
1508 
1509 static void
1510 vhead_dispose(vnode_t *vp, struct page *pp, int flag, int dn, cred_t *cr,
1511 	caller_context_t *ct)
1512 {
1513 	femarg_t	farg;
1514 	struct fem_list	*femsp;
1515 	void		(*func)();
1516 	void		*arg0;
1517 
1518 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
1519 		func = (void (*)()) (vp->v_op->vop_dispose);
1520 		arg0 = vp;
1521 		fem_unlock(vp->v_femhead);
1522 		(*func)(arg0, pp, flag, dn, cr, ct);
1523 	} else {
1524 		fem_addref(femsp);
1525 		fem_unlock(vp->v_femhead);
1526 		farg.fa_vnode.vp = vp;
1527 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
1528 		vsop_find(&farg, &func, void, &arg0, vop_dispose,
1529 		    femop_dispose);
1530 		(*func)(arg0, pp, flag, dn, cr, ct);
1531 		fem_release(femsp);
1532 	}
1533 }
1534 
1535 static int
1536 vhead_setsecattr(vnode_t *vp, vsecattr_t *vsap, int flag, cred_t *cr,
1537 	caller_context_t *ct)
1538 {
1539 	femarg_t	farg;
1540 	struct fem_list	*femsp;
1541 	int		(*func)();
1542 	void		*arg0;
1543 	int		errc;
1544 
1545 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
1546 		func = (int (*)()) (vp->v_op->vop_setsecattr);
1547 		arg0 = vp;
1548 		fem_unlock(vp->v_femhead);
1549 		errc = (*func)(arg0, vsap, flag, cr, ct);
1550 	} else {
1551 		fem_addref(femsp);
1552 		fem_unlock(vp->v_femhead);
1553 		farg.fa_vnode.vp = vp;
1554 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
1555 		vsop_find(&farg, &func, int, &arg0, vop_setsecattr,
1556 		    femop_setsecattr);
1557 		errc = (*func)(arg0, vsap, flag, cr, ct);
1558 		fem_release(femsp);
1559 	}
1560 	return (errc);
1561 }
1562 
1563 static int
1564 vhead_getsecattr(vnode_t *vp, vsecattr_t *vsap, int flag, cred_t *cr,
1565 	caller_context_t *ct)
1566 {
1567 	femarg_t	farg;
1568 	struct fem_list	*femsp;
1569 	int		(*func)();
1570 	void		*arg0;
1571 	int		errc;
1572 
1573 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
1574 		func = (int (*)()) (vp->v_op->vop_getsecattr);
1575 		arg0 = vp;
1576 		fem_unlock(vp->v_femhead);
1577 		errc = (*func)(arg0, vsap, flag, cr, ct);
1578 	} else {
1579 		fem_addref(femsp);
1580 		fem_unlock(vp->v_femhead);
1581 		farg.fa_vnode.vp = vp;
1582 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
1583 		vsop_find(&farg, &func, int, &arg0, vop_getsecattr,
1584 		    femop_getsecattr);
1585 		errc = (*func)(arg0, vsap, flag, cr, ct);
1586 		fem_release(femsp);
1587 	}
1588 	return (errc);
1589 }
1590 
1591 static int
1592 vhead_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag,
1593 	cred_t *cr, caller_context_t *ct)
1594 {
1595 	femarg_t	farg;
1596 	struct fem_list	*femsp;
1597 	int		(*func)();
1598 	void		*arg0;
1599 	int		errc;
1600 
1601 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
1602 		func = (int (*)()) (vp->v_op->vop_shrlock);
1603 		arg0 = vp;
1604 		fem_unlock(vp->v_femhead);
1605 		errc = (*func)(arg0, cmd, shr, flag, cr, ct);
1606 	} else {
1607 		fem_addref(femsp);
1608 		fem_unlock(vp->v_femhead);
1609 		farg.fa_vnode.vp = vp;
1610 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
1611 		vsop_find(&farg, &func, int, &arg0, vop_shrlock,
1612 		    femop_shrlock);
1613 		errc = (*func)(arg0, cmd, shr, flag, cr, ct);
1614 		fem_release(femsp);
1615 	}
1616 	return (errc);
1617 }
1618 
1619 static int
1620 vhead_vnevent(vnode_t *vp, vnevent_t vnevent, vnode_t *dvp, char *cname,
1621     caller_context_t *ct)
1622 {
1623 	femarg_t	farg;
1624 	struct fem_list	*femsp;
1625 	int		(*func)();
1626 	void		*arg0;
1627 	int		errc;
1628 
1629 	if ((femsp = fem_lock(vp->v_femhead)) == NULL) {
1630 		func = (int (*)()) (vp->v_op->vop_vnevent);
1631 		arg0 = vp;
1632 		fem_unlock(vp->v_femhead);
1633 		errc = (*func)(arg0, vnevent, dvp, cname, ct);
1634 	} else {
1635 		fem_addref(femsp);
1636 		fem_unlock(vp->v_femhead);
1637 		farg.fa_vnode.vp = vp;
1638 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
1639 		vsop_find(&farg, &func, int, &arg0, vop_vnevent,
1640 		    femop_vnevent);
1641 		errc = (*func)(arg0, vnevent, dvp, cname, ct);
1642 		fem_release(femsp);
1643 	}
1644 	return (errc);
1645 }
1646 
1647 static int
1648 fshead_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
1649 {
1650 	fsemarg_t	farg;
1651 	struct fem_list	*femsp;
1652 	int		(*func)();
1653 	void		*arg0;
1654 	int		errc;
1655 
1656 	ASSERT(vfsp->vfs_implp);
1657 
1658 	if ((femsp = fem_lock(vfsp->vfs_femhead)) == NULL) {
1659 		func = (int (*)()) vfsp->vfs_op->vfs_mount;
1660 		fem_unlock(vfsp->vfs_femhead);
1661 		errc = (*func)(vfsp, mvp, uap, cr);
1662 	} else {
1663 		fem_addref(femsp);
1664 		fem_unlock(vfsp->vfs_femhead);
1665 		farg.fa_vnode.vfsp = vfsp;
1666 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
1667 		vfsop_find(&farg, &func, int, &arg0, vfs_mount,
1668 		    fsemop_mount);
1669 		errc = (*func)(arg0, mvp, uap, cr);
1670 		fem_release(femsp);
1671 	}
1672 	return (errc);
1673 }
1674 
1675 static int
1676 fshead_unmount(vfs_t *vfsp, int flag, cred_t *cr)
1677 {
1678 	fsemarg_t	farg;
1679 	struct fem_list	*femsp;
1680 	int		(*func)();
1681 	void		*arg0;
1682 	int		errc;
1683 
1684 	ASSERT(vfsp->vfs_implp);
1685 
1686 	if ((femsp = fem_lock(vfsp->vfs_femhead)) == NULL) {
1687 		func = (int (*)()) vfsp->vfs_op->vfs_unmount;
1688 		fem_unlock(vfsp->vfs_femhead);
1689 		errc = (*func)(vfsp, flag, cr);
1690 	} else {
1691 		fem_addref(femsp);
1692 		fem_unlock(vfsp->vfs_femhead);
1693 		farg.fa_vnode.vfsp = vfsp;
1694 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
1695 		vfsop_find(&farg, &func, int, &arg0, vfs_unmount,
1696 		    fsemop_unmount);
1697 		errc = (*func)(arg0, flag, cr);
1698 		fem_release(femsp);
1699 	}
1700 	return (errc);
1701 }
1702 
1703 static int
1704 fshead_root(vfs_t *vfsp, vnode_t **vpp)
1705 {
1706 	fsemarg_t	farg;
1707 	struct fem_list	*femsp;
1708 	int		(*func)();
1709 	void		*arg0;
1710 	int		errc;
1711 
1712 	ASSERT(vfsp->vfs_implp);
1713 
1714 	if ((femsp = fem_lock(vfsp->vfs_femhead)) == NULL) {
1715 		func = (int (*)()) vfsp->vfs_op->vfs_root;
1716 		fem_unlock(vfsp->vfs_femhead);
1717 		errc = (*func)(vfsp, vpp);
1718 	} else {
1719 		fem_addref(femsp);
1720 		fem_unlock(vfsp->vfs_femhead);
1721 		farg.fa_vnode.vfsp = vfsp;
1722 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
1723 		vfsop_find(&farg, &func, int, &arg0, vfs_root, fsemop_root);
1724 		errc = (*func)(arg0, vpp);
1725 		fem_release(femsp);
1726 	}
1727 	return (errc);
1728 }
1729 
1730 static int
1731 fshead_statvfs(vfs_t *vfsp, statvfs64_t *sp)
1732 {
1733 	fsemarg_t	farg;
1734 	struct fem_list	*femsp;
1735 	int		(*func)();
1736 	void		*arg0;
1737 	int		errc;
1738 
1739 	ASSERT(vfsp->vfs_implp);
1740 
1741 	if ((femsp = fem_lock(vfsp->vfs_femhead)) == NULL) {
1742 		func = (int (*)()) vfsp->vfs_op->vfs_statvfs;
1743 		fem_unlock(vfsp->vfs_femhead);
1744 		errc = (*func)(vfsp, sp);
1745 	} else {
1746 		fem_addref(femsp);
1747 		fem_unlock(vfsp->vfs_femhead);
1748 		farg.fa_vnode.vfsp = vfsp;
1749 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
1750 		vfsop_find(&farg, &func, int, &arg0, vfs_statvfs,
1751 		    fsemop_statvfs);
1752 		errc = (*func)(arg0, sp);
1753 		fem_release(femsp);
1754 	}
1755 	return (errc);
1756 }
1757 
1758 static int
1759 fshead_sync(vfs_t *vfsp, short flag, cred_t *cr)
1760 {
1761 	fsemarg_t	farg;
1762 	struct fem_list	*femsp;
1763 	int		(*func)();
1764 	void		*arg0;
1765 	int		errc;
1766 
1767 	ASSERT(vfsp->vfs_implp);
1768 
1769 	if ((femsp = fem_lock(vfsp->vfs_femhead)) == NULL) {
1770 		func = (int (*)()) vfsp->vfs_op->vfs_sync;
1771 		fem_unlock(vfsp->vfs_femhead);
1772 		errc = (*func)(vfsp, flag, cr);
1773 	} else {
1774 		fem_addref(femsp);
1775 		fem_unlock(vfsp->vfs_femhead);
1776 		farg.fa_vnode.vfsp = vfsp;
1777 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
1778 		vfsop_find(&farg, &func, int, &arg0, vfs_sync, fsemop_sync);
1779 		errc = (*func)(arg0, flag, cr);
1780 		fem_release(femsp);
1781 	}
1782 	return (errc);
1783 }
1784 
1785 static int
1786 fshead_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp)
1787 {
1788 	fsemarg_t	farg;
1789 	struct fem_list	*femsp;
1790 	int		(*func)();
1791 	void		*arg0;
1792 	int		errc;
1793 
1794 	ASSERT(vfsp->vfs_implp);
1795 
1796 	if ((femsp = fem_lock(vfsp->vfs_femhead)) == NULL) {
1797 		func = (int (*)()) vfsp->vfs_op->vfs_vget;
1798 		fem_unlock(vfsp->vfs_femhead);
1799 		errc = (*func)(vfsp, vpp, fidp);
1800 	} else {
1801 		fem_addref(femsp);
1802 		fem_unlock(vfsp->vfs_femhead);
1803 		farg.fa_vnode.vfsp = vfsp;
1804 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
1805 		vfsop_find(&farg, &func, int, &arg0, vfs_vget, fsemop_vget);
1806 		errc = (*func)(arg0, vpp, fidp);
1807 		fem_release(femsp);
1808 	}
1809 	return (errc);
1810 }
1811 
1812 static int
1813 fshead_mountroot(vfs_t *vfsp, enum whymountroot reason)
1814 {
1815 	fsemarg_t	farg;
1816 	struct fem_list	*femsp;
1817 	int		(*func)();
1818 	void		*arg0;
1819 	int		errc;
1820 
1821 	ASSERT(vfsp->vfs_implp);
1822 
1823 	if ((femsp = fem_lock(vfsp->vfs_femhead)) == NULL) {
1824 		func = (int (*)()) vfsp->vfs_op->vfs_mountroot;
1825 		fem_unlock(vfsp->vfs_femhead);
1826 		errc = (*func)(vfsp, reason);
1827 	} else {
1828 		fem_addref(femsp);
1829 		fem_unlock(vfsp->vfs_femhead);
1830 		farg.fa_vnode.vfsp = vfsp;
1831 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
1832 		vfsop_find(&farg, &func, int, &arg0, vfs_mountroot,
1833 		    fsemop_mountroot);
1834 		errc = (*func)(arg0, reason);
1835 		fem_release(femsp);
1836 	}
1837 	return (errc);
1838 }
1839 
1840 static void
1841 fshead_freevfs(vfs_t *vfsp)
1842 {
1843 	fsemarg_t	farg;
1844 	struct fem_list	*femsp;
1845 	void		(*func)();
1846 	void		*arg0;
1847 
1848 	ASSERT(vfsp->vfs_implp);
1849 
1850 	if ((femsp = fem_lock(vfsp->vfs_femhead)) == NULL) {
1851 		func = (void (*)()) vfsp->vfs_op->vfs_freevfs;
1852 		fem_unlock(vfsp->vfs_femhead);
1853 		(*func)(vfsp);
1854 	} else {
1855 		fem_addref(femsp);
1856 		fem_unlock(vfsp->vfs_femhead);
1857 		farg.fa_vnode.vfsp = vfsp;
1858 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
1859 		vfsop_find(&farg, &func, void, &arg0, vfs_freevfs,
1860 		    fsemop_freevfs);
1861 		(*func)(arg0);
1862 		fem_release(femsp);
1863 	}
1864 }
1865 
1866 static int
1867 fshead_vnstate(vfs_t *vfsp, vnode_t *vp, vntrans_t nstate)
1868 {
1869 	fsemarg_t	farg;
1870 	struct fem_list	*femsp;
1871 	int		(*func)();
1872 	void		*arg0;
1873 	int		errc;
1874 
1875 	ASSERT(vfsp->vfs_implp);
1876 
1877 	if ((femsp = fem_lock(vfsp->vfs_femhead)) == NULL) {
1878 		func = (int (*)()) vfsp->vfs_op->vfs_vnstate;
1879 		fem_unlock(vfsp->vfs_femhead);
1880 		errc = (*func)(vfsp, vp, nstate);
1881 	} else {
1882 		fem_addref(femsp);
1883 		fem_unlock(vfsp->vfs_femhead);
1884 		farg.fa_vnode.vfsp = vfsp;
1885 		farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos;
1886 		vfsop_find(&farg, &func, int, &arg0, vfs_vnstate,
1887 		    fsemop_vnstate);
1888 		errc = (*func)(arg0, vp, nstate);
1889 		fem_release(femsp);
1890 	}
1891 	return (errc);
1892 }
1893 
1894 
1895 /*
1896  * specification table for the vhead vnode operations.
1897  * It is an error for any operations to be missing.
1898  */
1899 
1900 static struct fs_operation_def fhead_vn_spec[] = {
1901 	{ VOPNAME_OPEN, (femop_t *)vhead_open },
1902 	{ VOPNAME_CLOSE, (femop_t *)vhead_close },
1903 	{ VOPNAME_READ, (femop_t *)vhead_read },
1904 	{ VOPNAME_WRITE, (femop_t *)vhead_write },
1905 	{ VOPNAME_IOCTL, (femop_t *)vhead_ioctl },
1906 	{ VOPNAME_SETFL, (femop_t *)vhead_setfl },
1907 	{ VOPNAME_GETATTR, (femop_t *)vhead_getattr },
1908 	{ VOPNAME_SETATTR, (femop_t *)vhead_setattr },
1909 	{ VOPNAME_ACCESS, (femop_t *)vhead_access },
1910 	{ VOPNAME_LOOKUP, (femop_t *)vhead_lookup },
1911 	{ VOPNAME_CREATE, (femop_t *)vhead_create },
1912 	{ VOPNAME_REMOVE, (femop_t *)vhead_remove },
1913 	{ VOPNAME_LINK, (femop_t *)vhead_link },
1914 	{ VOPNAME_RENAME, (femop_t *)vhead_rename },
1915 	{ VOPNAME_MKDIR, (femop_t *)vhead_mkdir },
1916 	{ VOPNAME_RMDIR, (femop_t *)vhead_rmdir },
1917 	{ VOPNAME_READDIR, (femop_t *)vhead_readdir },
1918 	{ VOPNAME_SYMLINK, (femop_t *)vhead_symlink },
1919 	{ VOPNAME_READLINK, (femop_t *)vhead_readlink },
1920 	{ VOPNAME_FSYNC, (femop_t *)vhead_fsync },
1921 	{ VOPNAME_INACTIVE, (femop_t *)vhead_inactive },
1922 	{ VOPNAME_FID, (femop_t *)vhead_fid },
1923 	{ VOPNAME_RWLOCK, (femop_t *)vhead_rwlock },
1924 	{ VOPNAME_RWUNLOCK, (femop_t *)vhead_rwunlock },
1925 	{ VOPNAME_SEEK, (femop_t *)vhead_seek },
1926 	{ VOPNAME_CMP, (femop_t *)vhead_cmp },
1927 	{ VOPNAME_FRLOCK, (femop_t *)vhead_frlock },
1928 	{ VOPNAME_SPACE, (femop_t *)vhead_space },
1929 	{ VOPNAME_REALVP, (femop_t *)vhead_realvp },
1930 	{ VOPNAME_GETPAGE, (femop_t *)vhead_getpage },
1931 	{ VOPNAME_PUTPAGE, (femop_t *)vhead_putpage },
1932 	{ VOPNAME_MAP, (femop_t *)vhead_map },
1933 	{ VOPNAME_ADDMAP, (femop_t *)vhead_addmap },
1934 	{ VOPNAME_DELMAP, (femop_t *)vhead_delmap },
1935 	{ VOPNAME_POLL, (femop_t *)vhead_poll },
1936 	{ VOPNAME_DUMP, (femop_t *)vhead_dump },
1937 	{ VOPNAME_PATHCONF, (femop_t *)vhead_pathconf },
1938 	{ VOPNAME_PAGEIO, (femop_t *)vhead_pageio },
1939 	{ VOPNAME_DUMPCTL, (femop_t *)vhead_dumpctl },
1940 	{ VOPNAME_DISPOSE, (femop_t *)vhead_dispose },
1941 	{ VOPNAME_SETSECATTR, (femop_t *)vhead_setsecattr },
1942 	{ VOPNAME_GETSECATTR, (femop_t *)vhead_getsecattr },
1943 	{ VOPNAME_SHRLOCK, (femop_t *)vhead_shrlock },
1944 	{ VOPNAME_VNEVENT, (femop_t *)vhead_vnevent },
1945 	{	NULL,	NULL	}
1946 };
1947 
1948 /*
1949  * specification table for the vfshead vnode operations.
1950  * It is an error for any operations to be missing.
1951  */
1952 
1953 static struct fs_operation_def fshead_vfs_spec[]  = {
1954 	{ VFSNAME_MOUNT, (femop_t *)fshead_mount },
1955 	{ VFSNAME_UNMOUNT, (femop_t *)fshead_unmount },
1956 	{ VFSNAME_ROOT, (femop_t *)fshead_root },
1957 	{ VFSNAME_STATVFS, (femop_t *)fshead_statvfs },
1958 	{ VFSNAME_SYNC, (femop_t *)fshead_sync },
1959 	{ VFSNAME_VGET, (femop_t *)fshead_vget },
1960 	{ VFSNAME_MOUNTROOT, (femop_t *)fshead_mountroot },
1961 	{ VFSNAME_FREEVFS, (femop_t *)fshead_freevfs },
1962 	{ VFSNAME_VNSTATE, (femop_t *)fshead_vnstate },
1963 	{	NULL,	NULL	}
1964 };
1965 
1966 /*
1967  * This set of routines transfer control to the next stacked monitor.
1968  *
1969  * Each routine is identical except for naming, types and arguments.
1970  *
1971  * The basic steps are:
1972  * 1.  Decrease the stack pointer by one.
1973  * 2.  If the current item is a base operation (vnode, vfs), goto 5.
1974  * 3.  If the current item does not have a corresponding operation, goto 1
1975  * 4.  Return by invoking the current item with the argument handle.
1976  * 5.  Return by invoking the base operation with the base object.
1977  *
1978  * for each classification, there needs to be at least one "next" operation
1979  * for each "head"operation.
1980  *
1981  */
1982 
1983 int
1984 vnext_open(femarg_t *vf, int mode, cred_t *cr, caller_context_t *ct)
1985 {
1986 	int (*func)() = NULL;
1987 	void *arg0 = NULL;
1988 
1989 	ASSERT(vf != NULL);
1990 	vf->fa_fnode--;
1991 	vsop_find(vf, &func, int, &arg0, vop_open, femop_open);
1992 	ASSERT(func != NULL);
1993 	ASSERT(arg0 != NULL);
1994 	return ((*func)(arg0, mode, cr, ct));
1995 }
1996 
1997 int
1998 vnext_close(femarg_t *vf, int flag, int count, offset_t offset, cred_t *cr,
1999 	caller_context_t *ct)
2000 {
2001 	int (*func)() = NULL;
2002 	void *arg0 = NULL;
2003 
2004 	ASSERT(vf != NULL);
2005 	vf->fa_fnode--;
2006 	vsop_find(vf, &func, int, &arg0, vop_close, femop_close);
2007 	ASSERT(func != NULL);
2008 	ASSERT(arg0 != NULL);
2009 	return ((*func)(arg0, flag, count, offset, cr, ct));
2010 }
2011 
2012 int
2013 vnext_read(femarg_t *vf, uio_t *uiop, int ioflag, cred_t *cr,
2014 	caller_context_t *ct)
2015 {
2016 	int (*func)() = NULL;
2017 	void *arg0 = NULL;
2018 
2019 	ASSERT(vf != NULL);
2020 	vf->fa_fnode--;
2021 	vsop_find(vf, &func, int, &arg0, vop_read, femop_read);
2022 	ASSERT(func != NULL);
2023 	ASSERT(arg0 != NULL);
2024 	return ((*func)(arg0, uiop, ioflag, cr, ct));
2025 }
2026 
2027 int
2028 vnext_write(femarg_t *vf, uio_t *uiop, int ioflag, cred_t *cr,
2029 	caller_context_t *ct)
2030 {
2031 	int (*func)() = NULL;
2032 	void *arg0 = NULL;
2033 
2034 	ASSERT(vf != NULL);
2035 	vf->fa_fnode--;
2036 	vsop_find(vf, &func, int, &arg0, vop_write, femop_write);
2037 	ASSERT(func != NULL);
2038 	ASSERT(arg0 != NULL);
2039 	return ((*func)(arg0, uiop, ioflag, cr, ct));
2040 }
2041 
2042 int
2043 vnext_ioctl(femarg_t *vf, int cmd, intptr_t arg, int flag, cred_t *cr,
2044 	int *rvalp, caller_context_t *ct)
2045 {
2046 	int (*func)() = NULL;
2047 	void *arg0 = NULL;
2048 
2049 	ASSERT(vf != NULL);
2050 	vf->fa_fnode--;
2051 	vsop_find(vf, &func, int, &arg0, vop_ioctl, femop_ioctl);
2052 	ASSERT(func != NULL);
2053 	ASSERT(arg0 != NULL);
2054 	return ((*func)(arg0, cmd, arg, flag, cr, rvalp, ct));
2055 }
2056 
2057 int
2058 vnext_setfl(femarg_t *vf, int oflags, int nflags, cred_t *cr,
2059 	caller_context_t *ct)
2060 {
2061 	int (*func)() = NULL;
2062 	void *arg0 = NULL;
2063 
2064 	ASSERT(vf != NULL);
2065 	vf->fa_fnode--;
2066 	vsop_find(vf, &func, int, &arg0, vop_setfl, femop_setfl);
2067 	ASSERT(func != NULL);
2068 	ASSERT(arg0 != NULL);
2069 	return ((*func)(arg0, oflags, nflags, cr, ct));
2070 }
2071 
2072 int
2073 vnext_getattr(femarg_t *vf, vattr_t *vap, int flags, cred_t *cr,
2074 	caller_context_t *ct)
2075 {
2076 	int (*func)() = NULL;
2077 	void *arg0 = NULL;
2078 
2079 	ASSERT(vf != NULL);
2080 	vf->fa_fnode--;
2081 	vsop_find(vf, &func, int, &arg0, vop_getattr, femop_getattr);
2082 	ASSERT(func != NULL);
2083 	ASSERT(arg0 != NULL);
2084 	return ((*func)(arg0, vap, flags, cr, ct));
2085 }
2086 
2087 int
2088 vnext_setattr(femarg_t *vf, vattr_t *vap, int flags, cred_t *cr,
2089 	caller_context_t *ct)
2090 {
2091 	int (*func)() = NULL;
2092 	void *arg0 = NULL;
2093 
2094 	ASSERT(vf != NULL);
2095 	vf->fa_fnode--;
2096 	vsop_find(vf, &func, int, &arg0, vop_setattr, femop_setattr);
2097 	ASSERT(func != NULL);
2098 	ASSERT(arg0 != NULL);
2099 	return ((*func)(arg0, vap, flags, cr, ct));
2100 }
2101 
2102 int
2103 vnext_access(femarg_t *vf, int mode, int flags, cred_t *cr,
2104 	caller_context_t *ct)
2105 {
2106 	int (*func)() = NULL;
2107 	void *arg0 = NULL;
2108 
2109 	ASSERT(vf != NULL);
2110 	vf->fa_fnode--;
2111 	vsop_find(vf, &func, int, &arg0, vop_access, femop_access);
2112 	ASSERT(func != NULL);
2113 	ASSERT(arg0 != NULL);
2114 	return ((*func)(arg0, mode, flags, cr, ct));
2115 }
2116 
2117 int
2118 vnext_lookup(femarg_t *vf, char *nm, vnode_t **vpp, pathname_t *pnp,
2119 	int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
2120 	int *direntflags, pathname_t *realpnp)
2121 {
2122 	int (*func)() = NULL;
2123 	void *arg0 = NULL;
2124 
2125 	ASSERT(vf != NULL);
2126 	vf->fa_fnode--;
2127 	vsop_find(vf, &func, int, &arg0, vop_lookup, femop_lookup);
2128 	ASSERT(func != NULL);
2129 	ASSERT(arg0 != NULL);
2130 	return ((*func)(arg0, nm, vpp, pnp, flags, rdir, cr, ct,
2131 	    direntflags, realpnp));
2132 }
2133 
2134 int
2135 vnext_create(femarg_t *vf, char *name, vattr_t *vap, vcexcl_t excl,
2136 	int mode, vnode_t **vpp, cred_t *cr, int flag, caller_context_t *ct,
2137 	vsecattr_t *vsecp)
2138 {
2139 	int (*func)() = NULL;
2140 	void *arg0 = NULL;
2141 
2142 	ASSERT(vf != NULL);
2143 	vf->fa_fnode--;
2144 	vsop_find(vf, &func, int, &arg0, vop_create, femop_create);
2145 	ASSERT(func != NULL);
2146 	ASSERT(arg0 != NULL);
2147 	return ((*func)(arg0, name, vap, excl, mode, vpp, cr, flag, ct, vsecp));
2148 }
2149 
2150 int
2151 vnext_remove(femarg_t *vf, char *nm, cred_t *cr, caller_context_t *ct,
2152 	int flags)
2153 {
2154 	int (*func)() = NULL;
2155 	void *arg0 = NULL;
2156 
2157 	ASSERT(vf != NULL);
2158 	vf->fa_fnode--;
2159 	vsop_find(vf, &func, int, &arg0, vop_remove, femop_remove);
2160 	ASSERT(func != NULL);
2161 	ASSERT(arg0 != NULL);
2162 	return ((*func)(arg0, nm, cr, ct, flags));
2163 }
2164 
2165 int
2166 vnext_link(femarg_t *vf, vnode_t *svp, char *tnm, cred_t *cr,
2167 	caller_context_t *ct, int flags)
2168 {
2169 	int (*func)() = NULL;
2170 	void *arg0 = NULL;
2171 
2172 	ASSERT(vf != NULL);
2173 	vf->fa_fnode--;
2174 	vsop_find(vf, &func, int, &arg0, vop_link, femop_link);
2175 	ASSERT(func != NULL);
2176 	ASSERT(arg0 != NULL);
2177 	return ((*func)(arg0, svp, tnm, cr, ct, flags));
2178 }
2179 
2180 int
2181 vnext_rename(femarg_t *vf, char *snm, vnode_t *tdvp, char *tnm, cred_t *cr,
2182 	caller_context_t *ct, int flags)
2183 {
2184 	int (*func)() = NULL;
2185 	void *arg0 = NULL;
2186 
2187 	ASSERT(vf != NULL);
2188 	vf->fa_fnode--;
2189 	vsop_find(vf, &func, int, &arg0, vop_rename, femop_rename);
2190 	ASSERT(func != NULL);
2191 	ASSERT(arg0 != NULL);
2192 	return ((*func)(arg0, snm, tdvp, tnm, cr, ct, flags));
2193 }
2194 
2195 int
2196 vnext_mkdir(femarg_t *vf, char *dirname, vattr_t *vap, vnode_t **vpp,
2197 	cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp)
2198 {
2199 	int (*func)() = NULL;
2200 	void *arg0 = NULL;
2201 
2202 	ASSERT(vf != NULL);
2203 	vf->fa_fnode--;
2204 	vsop_find(vf, &func, int, &arg0, vop_mkdir, femop_mkdir);
2205 	ASSERT(func != NULL);
2206 	ASSERT(arg0 != NULL);
2207 	return ((*func)(arg0, dirname, vap, vpp, cr, ct, flags, vsecp));
2208 }
2209 
2210 int
2211 vnext_rmdir(femarg_t *vf, char *nm, vnode_t *cdir, cred_t *cr,
2212 	caller_context_t *ct, int flags)
2213 {
2214 	int (*func)() = NULL;
2215 	void *arg0 = NULL;
2216 
2217 	ASSERT(vf != NULL);
2218 	vf->fa_fnode--;
2219 	vsop_find(vf, &func, int, &arg0, vop_rmdir, femop_rmdir);
2220 	ASSERT(func != NULL);
2221 	ASSERT(arg0 != NULL);
2222 	return ((*func)(arg0, nm, cdir, cr, ct, flags));
2223 }
2224 
2225 int
2226 vnext_readdir(femarg_t *vf, uio_t *uiop, cred_t *cr, int *eofp,
2227 	caller_context_t *ct, int flags)
2228 {
2229 	int (*func)() = NULL;
2230 	void *arg0 = NULL;
2231 
2232 	ASSERT(vf != NULL);
2233 	vf->fa_fnode--;
2234 	vsop_find(vf, &func, int, &arg0, vop_readdir, femop_readdir);
2235 	ASSERT(func != NULL);
2236 	ASSERT(arg0 != NULL);
2237 	return ((*func)(arg0, uiop, cr, eofp, ct, flags));
2238 }
2239 
2240 int
2241 vnext_symlink(femarg_t *vf, char *linkname, vattr_t *vap, char *target,
2242 	cred_t *cr, caller_context_t *ct, int flags)
2243 {
2244 	int (*func)() = NULL;
2245 	void *arg0 = NULL;
2246 
2247 	ASSERT(vf != NULL);
2248 	vf->fa_fnode--;
2249 	vsop_find(vf, &func, int, &arg0, vop_symlink, femop_symlink);
2250 	ASSERT(func != NULL);
2251 	ASSERT(arg0 != NULL);
2252 	return ((*func)(arg0, linkname, vap, target, cr, ct, flags));
2253 }
2254 
2255 int
2256 vnext_readlink(femarg_t *vf, uio_t *uiop, cred_t *cr, caller_context_t *ct)
2257 {
2258 	int (*func)() = NULL;
2259 	void *arg0 = NULL;
2260 
2261 	ASSERT(vf != NULL);
2262 	vf->fa_fnode--;
2263 	vsop_find(vf, &func, int, &arg0, vop_readlink, femop_readlink);
2264 	ASSERT(func != NULL);
2265 	ASSERT(arg0 != NULL);
2266 	return ((*func)(arg0, uiop, cr, ct));
2267 }
2268 
2269 int
2270 vnext_fsync(femarg_t *vf, int syncflag, cred_t *cr, caller_context_t *ct)
2271 {
2272 	int (*func)() = NULL;
2273 	void *arg0 = NULL;
2274 
2275 	ASSERT(vf != NULL);
2276 	vf->fa_fnode--;
2277 	vsop_find(vf, &func, int, &arg0, vop_fsync, femop_fsync);
2278 	ASSERT(func != NULL);
2279 	ASSERT(arg0 != NULL);
2280 	return ((*func)(arg0, syncflag, cr, ct));
2281 }
2282 
2283 void
2284 vnext_inactive(femarg_t *vf, cred_t *cr, caller_context_t *ct)
2285 {
2286 	void (*func)() = NULL;
2287 	void *arg0 = NULL;
2288 
2289 	ASSERT(vf != NULL);
2290 	vf->fa_fnode--;
2291 	vsop_find(vf, &func, void, &arg0, vop_inactive, femop_inactive);
2292 	ASSERT(func != NULL);
2293 	ASSERT(arg0 != NULL);
2294 	(*func)(arg0, cr, ct);
2295 }
2296 
2297 int
2298 vnext_fid(femarg_t *vf, fid_t *fidp, caller_context_t *ct)
2299 {
2300 	int (*func)() = NULL;
2301 	void *arg0 = NULL;
2302 
2303 	ASSERT(vf != NULL);
2304 	vf->fa_fnode--;
2305 	vsop_find(vf, &func, int, &arg0, vop_fid, femop_fid);
2306 	ASSERT(func != NULL);
2307 	ASSERT(arg0 != NULL);
2308 	return ((*func)(arg0, fidp, ct));
2309 }
2310 
2311 int
2312 vnext_rwlock(femarg_t *vf, int write_lock, caller_context_t *ct)
2313 {
2314 	int (*func)() = NULL;
2315 	void *arg0 = NULL;
2316 
2317 	ASSERT(vf != NULL);
2318 	vf->fa_fnode--;
2319 	vsop_find(vf, &func, int, &arg0, vop_rwlock, femop_rwlock);
2320 	ASSERT(func != NULL);
2321 	ASSERT(arg0 != NULL);
2322 	return ((*func)(arg0, write_lock, ct));
2323 }
2324 
2325 void
2326 vnext_rwunlock(femarg_t *vf, int write_lock, caller_context_t *ct)
2327 {
2328 	void (*func)() = NULL;
2329 	void *arg0 = NULL;
2330 
2331 	ASSERT(vf != NULL);
2332 	vf->fa_fnode--;
2333 	vsop_find(vf, &func, void, &arg0, vop_rwunlock, femop_rwunlock);
2334 	ASSERT(func != NULL);
2335 	ASSERT(arg0 != NULL);
2336 	(*func)(arg0, write_lock, ct);
2337 }
2338 
2339 int
2340 vnext_seek(femarg_t *vf, offset_t ooff, offset_t *noffp, caller_context_t *ct)
2341 {
2342 	int (*func)() = NULL;
2343 	void *arg0 = NULL;
2344 
2345 	ASSERT(vf != NULL);
2346 	vf->fa_fnode--;
2347 	vsop_find(vf, &func, int, &arg0, vop_seek, femop_seek);
2348 	ASSERT(func != NULL);
2349 	ASSERT(arg0 != NULL);
2350 	return ((*func)(arg0, ooff, noffp, ct));
2351 }
2352 
2353 int
2354 vnext_cmp(femarg_t *vf, vnode_t *vp2, caller_context_t *ct)
2355 {
2356 	int (*func)() = NULL;
2357 	void *arg0 = NULL;
2358 
2359 	ASSERT(vf != NULL);
2360 	vf->fa_fnode--;
2361 	vsop_find(vf, &func, int, &arg0, vop_cmp, femop_cmp);
2362 	ASSERT(func != NULL);
2363 	ASSERT(arg0 != NULL);
2364 	return ((*func)(arg0, vp2, ct));
2365 }
2366 
2367 int
2368 vnext_frlock(femarg_t *vf, int cmd, struct flock64 *bfp, int flag,
2369 	offset_t offset, struct flk_callback *flk_cbp, cred_t *cr,
2370 	caller_context_t *ct)
2371 {
2372 	int (*func)() = NULL;
2373 	void *arg0 = NULL;
2374 
2375 	ASSERT(vf != NULL);
2376 	vf->fa_fnode--;
2377 	vsop_find(vf, &func, int, &arg0, vop_frlock, femop_frlock);
2378 	ASSERT(func != NULL);
2379 	ASSERT(arg0 != NULL);
2380 	return ((*func)(arg0, cmd, bfp, flag, offset, flk_cbp, cr, ct));
2381 }
2382 
2383 int
2384 vnext_space(femarg_t *vf, int cmd, struct flock64 *bfp, int flag,
2385 	offset_t offset, cred_t *cr, caller_context_t *ct)
2386 {
2387 	int (*func)() = NULL;
2388 	void *arg0 = NULL;
2389 
2390 	ASSERT(vf != NULL);
2391 	vf->fa_fnode--;
2392 	vsop_find(vf, &func, int, &arg0, vop_space, femop_space);
2393 	ASSERT(func != NULL);
2394 	ASSERT(arg0 != NULL);
2395 	return ((*func)(arg0, cmd, bfp, flag, offset, cr, ct));
2396 }
2397 
2398 int
2399 vnext_realvp(femarg_t *vf, vnode_t **vpp, caller_context_t *ct)
2400 {
2401 	int (*func)() = NULL;
2402 	void *arg0 = NULL;
2403 
2404 	ASSERT(vf != NULL);
2405 	vf->fa_fnode--;
2406 	vsop_find(vf, &func, int, &arg0, vop_realvp, femop_realvp);
2407 	ASSERT(func != NULL);
2408 	ASSERT(arg0 != NULL);
2409 	return ((*func)(arg0, vpp, ct));
2410 }
2411 
2412 int
2413 vnext_getpage(femarg_t *vf, offset_t off, size_t len, uint_t *protp,
2414 	struct page **plarr, size_t plsz, struct seg *seg, caddr_t addr,
2415 	enum seg_rw rw, cred_t *cr, caller_context_t *ct)
2416 {
2417 	int (*func)() = NULL;
2418 	void *arg0 = NULL;
2419 
2420 	ASSERT(vf != NULL);
2421 	vf->fa_fnode--;
2422 	vsop_find(vf, &func, int, &arg0, vop_getpage, femop_getpage);
2423 	ASSERT(func != NULL);
2424 	ASSERT(arg0 != NULL);
2425 	return ((*func)(arg0, off, len, protp, plarr, plsz, seg, addr, rw,
2426 	    cr, ct));
2427 }
2428 
2429 int
2430 vnext_putpage(femarg_t *vf, offset_t off, size_t len, int flags,
2431 	cred_t *cr, caller_context_t *ct)
2432 {
2433 	int (*func)() = NULL;
2434 	void *arg0 = NULL;
2435 
2436 	ASSERT(vf != NULL);
2437 	vf->fa_fnode--;
2438 	vsop_find(vf, &func, int, &arg0, vop_putpage, femop_putpage);
2439 	ASSERT(func != NULL);
2440 	ASSERT(arg0 != NULL);
2441 	return ((*func)(arg0, off, len, flags, cr, ct));
2442 }
2443 
2444 int
2445 vnext_map(femarg_t *vf, offset_t off, struct as *as, caddr_t *addrp,
2446 	size_t len, uchar_t prot, uchar_t maxprot, uint_t flags,
2447 	cred_t *cr, caller_context_t *ct)
2448 {
2449 	int (*func)() = NULL;
2450 	void *arg0 = NULL;
2451 
2452 	ASSERT(vf != NULL);
2453 	vf->fa_fnode--;
2454 	vsop_find(vf, &func, int, &arg0, vop_map, femop_map);
2455 	ASSERT(func != NULL);
2456 	ASSERT(arg0 != NULL);
2457 	return ((*func)(arg0, off, as, addrp, len, prot, maxprot, flags,
2458 	    cr, ct));
2459 }
2460 
2461 int
2462 vnext_addmap(femarg_t *vf, offset_t off, struct as *as, caddr_t addr,
2463 	size_t len, uchar_t prot, uchar_t maxprot, uint_t flags,
2464 	cred_t *cr, caller_context_t *ct)
2465 {
2466 	int (*func)() = NULL;
2467 	void *arg0 = NULL;
2468 
2469 	ASSERT(vf != NULL);
2470 	vf->fa_fnode--;
2471 	vsop_find(vf, &func, int, &arg0, vop_addmap, femop_addmap);
2472 	ASSERT(func != NULL);
2473 	ASSERT(arg0 != NULL);
2474 	return ((*func)(arg0, off, as, addr, len, prot, maxprot, flags,
2475 	    cr, ct));
2476 }
2477 
2478 int
2479 vnext_delmap(femarg_t *vf, offset_t off, struct as *as, caddr_t addr,
2480 	size_t len, uint_t prot, uint_t maxprot, uint_t flags,
2481 	cred_t *cr, caller_context_t *ct)
2482 {
2483 	int (*func)() = NULL;
2484 	void *arg0 = NULL;
2485 
2486 	ASSERT(vf != NULL);
2487 	vf->fa_fnode--;
2488 	vsop_find(vf, &func, int, &arg0, vop_delmap, femop_delmap);
2489 	ASSERT(func != NULL);
2490 	ASSERT(arg0 != NULL);
2491 	return ((*func)(arg0, off, as, addr, len, prot, maxprot, flags,
2492 	    cr, ct));
2493 }
2494 
2495 int
2496 vnext_poll(femarg_t *vf, short events, int anyyet, short *reventsp,
2497 	struct pollhead **phpp, caller_context_t *ct)
2498 {
2499 	int (*func)() = NULL;
2500 	void *arg0 = NULL;
2501 
2502 	ASSERT(vf != NULL);
2503 	vf->fa_fnode--;
2504 	vsop_find(vf, &func, int, &arg0, vop_poll, femop_poll);
2505 	ASSERT(func != NULL);
2506 	ASSERT(arg0 != NULL);
2507 	return ((*func)(arg0, events, anyyet, reventsp, phpp, ct));
2508 }
2509 
2510 int
2511 vnext_dump(femarg_t *vf, caddr_t addr, offset_t lbdn, offset_t dblks,
2512 	caller_context_t *ct)
2513 {
2514 	int (*func)() = NULL;
2515 	void *arg0 = NULL;
2516 
2517 	ASSERT(vf != NULL);
2518 	vf->fa_fnode--;
2519 	vsop_find(vf, &func, int, &arg0, vop_dump, femop_dump);
2520 	ASSERT(func != NULL);
2521 	ASSERT(arg0 != NULL);
2522 	return ((*func)(arg0, addr, lbdn, dblks, ct));
2523 }
2524 
2525 int
2526 vnext_pathconf(femarg_t *vf, int cmd, ulong_t *valp, cred_t *cr,
2527 	caller_context_t *ct)
2528 {
2529 	int (*func)() = NULL;
2530 	void *arg0 = NULL;
2531 
2532 	ASSERT(vf != NULL);
2533 	vf->fa_fnode--;
2534 	vsop_find(vf, &func, int, &arg0, vop_pathconf, femop_pathconf);
2535 	ASSERT(func != NULL);
2536 	ASSERT(arg0 != NULL);
2537 	return ((*func)(arg0, cmd, valp, cr, ct));
2538 }
2539 
2540 int
2541 vnext_pageio(femarg_t *vf, struct page *pp, u_offset_t io_off,
2542 	size_t io_len, int flags, cred_t *cr, caller_context_t *ct)
2543 {
2544 	int (*func)() = NULL;
2545 	void *arg0 = NULL;
2546 
2547 	ASSERT(vf != NULL);
2548 	vf->fa_fnode--;
2549 	vsop_find(vf, &func, int, &arg0, vop_pageio, femop_pageio);
2550 	ASSERT(func != NULL);
2551 	ASSERT(arg0 != NULL);
2552 	return ((*func)(arg0, pp, io_off, io_len, flags, cr, ct));
2553 }
2554 
2555 int
2556 vnext_dumpctl(femarg_t *vf, int action, offset_t *blkp, caller_context_t *ct)
2557 {
2558 	int (*func)() = NULL;
2559 	void *arg0 = NULL;
2560 
2561 	ASSERT(vf != NULL);
2562 	vf->fa_fnode--;
2563 	vsop_find(vf, &func, int, &arg0, vop_dumpctl, femop_dumpctl);
2564 	ASSERT(func != NULL);
2565 	ASSERT(arg0 != NULL);
2566 	return ((*func)(arg0, action, blkp, ct));
2567 }
2568 
2569 void
2570 vnext_dispose(femarg_t *vf, struct page *pp, int flag, int dn, cred_t *cr,
2571 	caller_context_t *ct)
2572 {
2573 	void (*func)() = NULL;
2574 	void *arg0 = NULL;
2575 
2576 	ASSERT(vf != NULL);
2577 	vf->fa_fnode--;
2578 	vsop_find(vf, &func, void, &arg0, vop_dispose, femop_dispose);
2579 	ASSERT(func != NULL);
2580 	ASSERT(arg0 != NULL);
2581 	(*func)(arg0, pp, flag, dn, cr, ct);
2582 }
2583 
2584 int
2585 vnext_setsecattr(femarg_t *vf, vsecattr_t *vsap, int flag, cred_t *cr,
2586 	caller_context_t *ct)
2587 {
2588 	int (*func)() = NULL;
2589 	void *arg0 = NULL;
2590 
2591 	ASSERT(vf != NULL);
2592 	vf->fa_fnode--;
2593 	vsop_find(vf, &func, int, &arg0, vop_setsecattr, femop_setsecattr);
2594 	ASSERT(func != NULL);
2595 	ASSERT(arg0 != NULL);
2596 	return ((*func)(arg0, vsap, flag, cr, ct));
2597 }
2598 
2599 int
2600 vnext_getsecattr(femarg_t *vf, vsecattr_t *vsap, int flag, cred_t *cr,
2601 	caller_context_t *ct)
2602 {
2603 	int (*func)() = NULL;
2604 	void *arg0 = NULL;
2605 
2606 	ASSERT(vf != NULL);
2607 	vf->fa_fnode--;
2608 	vsop_find(vf, &func, int, &arg0, vop_getsecattr, femop_getsecattr);
2609 	ASSERT(func != NULL);
2610 	ASSERT(arg0 != NULL);
2611 	return ((*func)(arg0, vsap, flag, cr, ct));
2612 }
2613 
2614 int
2615 vnext_shrlock(femarg_t *vf, int cmd, struct shrlock *shr, int flag,
2616 	cred_t *cr, caller_context_t *ct)
2617 {
2618 	int (*func)() = NULL;
2619 	void *arg0 = NULL;
2620 
2621 	ASSERT(vf != NULL);
2622 	vf->fa_fnode--;
2623 	vsop_find(vf, &func, int, &arg0, vop_shrlock, femop_shrlock);
2624 	ASSERT(func != NULL);
2625 	ASSERT(arg0 != NULL);
2626 	return ((*func)(arg0, cmd, shr, flag, cr, ct));
2627 }
2628 
2629 int
2630 vnext_vnevent(femarg_t *vf, vnevent_t vnevent, vnode_t *dvp, char *cname,
2631     caller_context_t *ct)
2632 {
2633 	int (*func)() = NULL;
2634 	void *arg0 = NULL;
2635 
2636 	ASSERT(vf != NULL);
2637 	vf->fa_fnode--;
2638 	vsop_find(vf, &func, int, &arg0, vop_vnevent, femop_vnevent);
2639 	ASSERT(func != NULL);
2640 	ASSERT(arg0 != NULL);
2641 	return ((*func)(arg0, vnevent, dvp, cname, ct));
2642 }
2643 
2644 int
2645 vfsnext_mount(fsemarg_t *vf, vnode_t *mvp, struct mounta *uap, cred_t *cr)
2646 {
2647 	int (*func)() = NULL;
2648 	void *arg0 = NULL;
2649 
2650 	ASSERT(vf != NULL);
2651 	vf->fa_fnode--;
2652 	vfsop_find(vf, &func, int, &arg0, vfs_mount, fsemop_mount);
2653 	ASSERT(func != NULL);
2654 	ASSERT(arg0 != NULL);
2655 	return ((*func)(arg0, mvp, uap, cr));
2656 }
2657 
2658 int
2659 vfsnext_unmount(fsemarg_t *vf, int flag, cred_t *cr)
2660 {
2661 	int (*func)() = NULL;
2662 	void *arg0 = NULL;
2663 
2664 	ASSERT(vf != NULL);
2665 	vf->fa_fnode--;
2666 	vfsop_find(vf, &func, int, &arg0, vfs_unmount, fsemop_unmount);
2667 	ASSERT(func != NULL);
2668 	ASSERT(arg0 != NULL);
2669 	return ((*func)(arg0, flag, cr));
2670 }
2671 
2672 int
2673 vfsnext_root(fsemarg_t *vf, vnode_t **vpp)
2674 {
2675 	int (*func)() = NULL;
2676 	void *arg0 = NULL;
2677 
2678 	ASSERT(vf != NULL);
2679 	vf->fa_fnode--;
2680 	vfsop_find(vf, &func, int, &arg0, vfs_root, fsemop_root);
2681 	ASSERT(func != NULL);
2682 	ASSERT(arg0 != NULL);
2683 	return ((*func)(arg0, vpp));
2684 }
2685 
2686 int
2687 vfsnext_statvfs(fsemarg_t *vf, statvfs64_t *sp)
2688 {
2689 	int (*func)() = NULL;
2690 	void *arg0 = NULL;
2691 
2692 	ASSERT(vf != NULL);
2693 	vf->fa_fnode--;
2694 	vfsop_find(vf, &func, int, &arg0, vfs_statvfs, fsemop_statvfs);
2695 	ASSERT(func != NULL);
2696 	ASSERT(arg0 != NULL);
2697 	return ((*func)(arg0, sp));
2698 }
2699 
2700 int
2701 vfsnext_sync(fsemarg_t *vf, short flag, cred_t *cr)
2702 {
2703 	int (*func)() = NULL;
2704 	void *arg0 = NULL;
2705 
2706 	ASSERT(vf != NULL);
2707 	vf->fa_fnode--;
2708 	vfsop_find(vf, &func, int, &arg0, vfs_sync, fsemop_sync);
2709 	ASSERT(func != NULL);
2710 	ASSERT(arg0 != NULL);
2711 	return ((*func)(arg0, flag, cr));
2712 }
2713 
2714 int
2715 vfsnext_vget(fsemarg_t *vf, vnode_t **vpp, fid_t *fidp)
2716 {
2717 	int (*func)() = NULL;
2718 	void *arg0 = NULL;
2719 
2720 	ASSERT(vf != NULL);
2721 	vf->fa_fnode--;
2722 	vfsop_find(vf, &func, int, &arg0, vfs_vget, fsemop_vget);
2723 	ASSERT(func != NULL);
2724 	ASSERT(arg0 != NULL);
2725 	return ((*func)(arg0, vpp, fidp));
2726 }
2727 
2728 int
2729 vfsnext_mountroot(fsemarg_t *vf, enum whymountroot reason)
2730 {
2731 	int (*func)() = NULL;
2732 	void *arg0 = NULL;
2733 
2734 	ASSERT(vf != NULL);
2735 	vf->fa_fnode--;
2736 	vfsop_find(vf, &func, int, &arg0, vfs_mountroot, fsemop_mountroot);
2737 	ASSERT(func != NULL);
2738 	ASSERT(arg0 != NULL);
2739 	return ((*func)(arg0, reason));
2740 }
2741 
2742 void
2743 vfsnext_freevfs(fsemarg_t *vf)
2744 {
2745 	void (*func)() = NULL;
2746 	void *arg0 = NULL;
2747 
2748 	ASSERT(vf != NULL);
2749 	vf->fa_fnode--;
2750 	vfsop_find(vf, &func, void, &arg0, vfs_freevfs, fsemop_freevfs);
2751 	ASSERT(func != NULL);
2752 	ASSERT(arg0 != NULL);
2753 	(*func)(arg0);
2754 }
2755 
2756 int
2757 vfsnext_vnstate(fsemarg_t *vf, vnode_t *vp, vntrans_t nstate)
2758 {
2759 	int (*func)() = NULL;
2760 	void *arg0 = NULL;
2761 
2762 	ASSERT(vf != NULL);
2763 	vf->fa_fnode--;
2764 	vfsop_find(vf, &func, int, &arg0, vfs_vnstate, fsemop_vnstate);
2765 	ASSERT(func != NULL);
2766 	ASSERT(arg0 != NULL);
2767 	return ((*func)(arg0, vp, nstate));
2768 }
2769 
2770 
2771 /*
2772  * Create a new fem_head and associate with the vnode.
2773  * To keep the unaugmented vnode access path lock free, we spin
2774  * update this - create a new one, then try and install it. If
2775  * we fail to install, release the old one and pretend we succeeded.
2776  */
2777 
2778 static struct fem_head *
2779 new_femhead(struct fem_head **hp)
2780 {
2781 	struct fem_head	*head;
2782 
2783 	head = kmem_alloc(sizeof (*head), KM_SLEEP);
2784 	mutex_init(&head->femh_lock, NULL, MUTEX_DEFAULT, NULL);
2785 	head->femh_list = NULL;
2786 	if (casptr(hp, NULL, head) != NULL) {
2787 		kmem_free(head, sizeof (*head));
2788 		head = *hp;
2789 	}
2790 	return (head);
2791 }
2792 
2793 /*
2794  * Create a fem_list.  The fem_list that gets returned is in a
2795  * very rudimentary state and MUST NOT be used until it's initialized
2796  * (usually by femlist_construct() or fem_dup_list()).  The refcount
2797  * and size is set properly and top-of-stack is set to the "guard" node
2798  * just to be consistent.
2799  *
2800  * If anyone were to accidentally trying to run on this fem_list before
2801  * it's initialized then the system would likely panic trying to defererence
2802  * the (NULL) fn_op pointer.
2803  *
2804  */
2805 static struct fem_list *
2806 femlist_create(int numnodes)
2807 {
2808 	struct fem_list	*sp;
2809 
2810 	sp = kmem_alloc(fl_ntob(numnodes), KM_SLEEP);
2811 	sp->feml_refc  = 1;
2812 	sp->feml_ssize = numnodes;
2813 	sp->feml_nodes[0] = FEM_GUARD(FEMTYPE_NULL);
2814 	sp->feml_tos = 0;
2815 	return (sp);
2816 }
2817 
2818 /*
2819  * Construct a new femlist.
2820  * The list is constructed with the appropriate type of guard to
2821  * anchor it, and inserts the original ops.
2822  */
2823 
2824 static struct fem_list *
2825 femlist_construct(void *baseops, int type, int numnodes)
2826 {
2827 	struct fem_list	*sp;
2828 
2829 	sp = femlist_create(numnodes);
2830 	sp->feml_nodes[0] = FEM_GUARD(type);
2831 	sp->feml_nodes[1].fn_op.anon = baseops;
2832 	sp->feml_nodes[1].fn_available = NULL;
2833 	sp->feml_nodes[1].fn_av_hold = NULL;
2834 	sp->feml_nodes[1].fn_av_rele = NULL;
2835 	sp->feml_tos = 1;
2836 	return (sp);
2837 }
2838 
2839 /*
2840  * Duplicate a list.  Copy the original list to the clone.
2841  *
2842  * NOTE: The caller must have the fem_head for the lists locked.
2843  * Assuming the appropriate lock is held and the caller has done the
2844  * math right, the clone list should be big enough to old the original.
2845  */
2846 
2847 static void
2848 fem_dup_list(struct fem_list *orig, struct fem_list *clone)
2849 {
2850 	int		i;
2851 
2852 	ASSERT(clone->feml_ssize >= orig->feml_ssize);
2853 
2854 	bcopy(orig->feml_nodes, clone->feml_nodes,
2855 	    sizeof (orig->feml_nodes[0]) * orig->feml_ssize);
2856 	clone->feml_tos = orig->feml_tos;
2857 	/*
2858 	 * Now that we've copied the old list (orig) to the new list (clone),
2859 	 * we need to walk the new list and put another hold on fn_available.
2860 	 */
2861 	for (i = clone->feml_tos; i > 0; i--) {
2862 		struct fem_node *fnp = &clone->feml_nodes[i];
2863 
2864 		if (fnp->fn_av_hold)
2865 			(*(fnp->fn_av_hold))(fnp->fn_available);
2866 	}
2867 }
2868 
2869 
2870 static int
2871 fem_push_node(
2872 	struct fem_head **hp,
2873 	void **baseops,
2874 	int type,
2875 	struct fem_node *nnode,
2876 	femhow_t how)
2877 {
2878 	struct fem_head	*hd;
2879 	struct fem_list	*list;
2880 	void		*oldops;
2881 	int		retry;
2882 	int		error = 0;
2883 	int		i;
2884 
2885 	/* Validate the node */
2886 	if ((nnode->fn_op.anon == NULL) || (nnode->fn_available == NULL)) {
2887 		return (EINVAL);
2888 	}
2889 
2890 	if ((hd = *hp) == NULL) { /* construct a proto-list */
2891 		hd = new_femhead(hp);
2892 	}
2893 	/*
2894 	 * RULE: once a femhead has been pushed onto a object, it cannot be
2895 	 * removed until the object is destroyed.  It can be deactivated by
2896 	 * placing the original 'object operations' onto the object, which
2897 	 * will ignore the femhead.
2898 	 * The loop will exist when the femh_list has space to push a monitor
2899 	 * onto it.
2900 	 */
2901 	do {
2902 		retry = 1;
2903 		list = fem_lock(hd);
2904 		oldops = *baseops;
2905 
2906 		if (list != NULL) {
2907 			if (list->feml_tos+1 < list->feml_ssize) {
2908 				retry = 0;
2909 			} else {
2910 				struct fem_list	*olist = list;
2911 
2912 				fem_addref(olist);
2913 				fem_unlock(hd);
2914 				list = femlist_create(olist->feml_ssize * 2);
2915 				(void) fem_lock(hd);
2916 				if (hd->femh_list == olist) {
2917 					if (list->feml_ssize <=
2918 					    olist->feml_ssize) {
2919 						/*
2920 						 * We have a new list, but it
2921 						 * is too small to hold the
2922 						 * original contents plus the
2923 						 * one to push.  Release the
2924 						 * new list and start over.
2925 						 */
2926 						fem_release(list);
2927 						fem_unlock(hd);
2928 					} else {
2929 						/*
2930 						 * Life is good:  Our new list
2931 						 * is big enough to hold the
2932 						 * original list (olist) + 1.
2933 						 */
2934 						fem_dup_list(olist, list);
2935 						/* orphan this list */
2936 						hd->femh_list = list;
2937 						(void) fem_delref(olist);
2938 						retry = 0;
2939 					}
2940 				} else {
2941 					/* concurrent update, retry */
2942 					fem_release(list);
2943 					fem_unlock(hd);
2944 				}
2945 				/* remove the reference we added above */
2946 				fem_release(olist);
2947 			}
2948 		} else {
2949 			fem_unlock(hd);
2950 			list = femlist_construct(oldops, type, NNODES_DEFAULT);
2951 			(void) fem_lock(hd);
2952 			if (hd->femh_list != NULL || *baseops != oldops) {
2953 				/* concurrent update, retry */
2954 				fem_release(list);
2955 				fem_unlock(hd);
2956 			} else {
2957 				hd->femh_list = list;
2958 				*baseops = FEM_HEAD(type);
2959 				retry = 0;
2960 			}
2961 		}
2962 	} while (retry);
2963 
2964 	ASSERT(mutex_owner(&hd->femh_lock) == curthread);
2965 	ASSERT(list->feml_tos+1 < list->feml_ssize);
2966 
2967 	/*
2968 	 * The presence of "how" will modify the behavior of how/if
2969 	 * nodes are pushed.  If it's FORCE, then we can skip
2970 	 * all the checks and push it on.
2971 	 */
2972 	if (how != FORCE) {
2973 		/* Start at the top and work our way down */
2974 		for (i = list->feml_tos; i > 0; i--) {
2975 			void *fn_av = list->feml_nodes[i].fn_available;
2976 			void *fn_op = list->feml_nodes[i].fn_op.anon;
2977 
2978 			/*
2979 			 * OPARGUNIQ means that this node should not
2980 			 * be pushed on if a node with the same op/avail
2981 			 * combination exists.  This situation returns
2982 			 * EBUSY.
2983 			 *
2984 			 * OPUNIQ means that this node should not be
2985 			 * pushed on if a node with the same op exists.
2986 			 * This situation also returns EBUSY.
2987 			 */
2988 			switch (how) {
2989 
2990 			case OPUNIQ:
2991 				if (fn_op == nnode->fn_op.anon) {
2992 					error = EBUSY;
2993 				}
2994 				break;
2995 
2996 			case OPARGUNIQ:
2997 				if ((fn_op == nnode->fn_op.anon) &&
2998 				    (fn_av == nnode->fn_available)) {
2999 					error = EBUSY;
3000 				}
3001 				break;
3002 
3003 			default:
3004 				error = EINVAL;	/* Unexpected value */
3005 				break;
3006 			}
3007 
3008 			if (error)
3009 				break;
3010 		}
3011 	}
3012 
3013 	if (error == 0) {
3014 		/*
3015 		 * If no errors, slap the node on the list.
3016 		 * Note: The following is a structure copy.
3017 		 */
3018 		list->feml_nodes[++(list->feml_tos)] = *nnode;
3019 	}
3020 
3021 	fem_unlock(hd);
3022 	return (error);
3023 }
3024 
3025 /*
3026  * Remove a node by copying the list above it down a notch.
3027  * If the list is busy, replace it with an idle one and work
3028  * upon it.
3029  * A node matches if the opset matches and the datap matches or is
3030  * null.
3031  */
3032 
3033 static int
3034 remove_node(struct fem_list *sp, void **baseops, void *opset, void *datap)
3035 {
3036 	int	i;
3037 	struct fem_node	*fn;
3038 
3039 	for (i = sp->feml_tos; i > 0; i--) {
3040 		fn = sp->feml_nodes+i;
3041 		if (fn->fn_op.anon == opset &&
3042 		    (fn->fn_available == datap || datap == NULL)) {
3043 			break;
3044 		}
3045 	}
3046 	if (i == 0) {
3047 		return (EINVAL);
3048 	}
3049 
3050 	/*
3051 	 * At this point we have a node in-hand (*fn) that we are about
3052 	 * to remove by overwriting it and adjusting the stack.  This is
3053 	 * our last chance to do anything with this node so we do the
3054 	 * release on the arg.
3055 	 */
3056 	if (fn->fn_av_rele)
3057 		(*(fn->fn_av_rele))(fn->fn_available);
3058 
3059 	while (i++ < sp->feml_tos) {
3060 		sp->feml_nodes[i-1] = sp->feml_nodes[i];
3061 	}
3062 	if (--(sp->feml_tos) == 1) { /* Empty, restore ops */
3063 		*baseops = sp->feml_nodes[1].fn_op.anon;
3064 	}
3065 	return (0);
3066 }
3067 
3068 static int
3069 fem_remove_node(struct fem_head *fh, void **baseops, void *opset, void *datap)
3070 {
3071 	struct fem_list *sp;
3072 	int		error = 0;
3073 	int		retry;
3074 
3075 	if (fh == NULL) {
3076 		return (EINVAL);
3077 	}
3078 
3079 	do {
3080 		retry = 0;
3081 		if ((sp = fem_lock(fh)) == NULL) {
3082 			fem_unlock(fh);
3083 			error = EINVAL;
3084 		} else if (sp->feml_refc == 1) {
3085 			error = remove_node(sp, baseops, opset, datap);
3086 			if (sp->feml_tos == 1) {
3087 				/*
3088 				 * The top-of-stack was decremented by
3089 				 * remove_node().  If it got down to 1,
3090 				 * then the base ops were replaced and we
3091 				 * call fem_release() which will free the
3092 				 * fem_list.
3093 				 */
3094 				fem_release(sp);
3095 				fh->femh_list = NULL;
3096 				/* XXX - Do we need a membar_producer() call? */
3097 			}
3098 			fem_unlock(fh);
3099 		} else {
3100 			/* busy - install a new one without this monitor */
3101 			struct fem_list *nsp;	/* New fem_list being cloned */
3102 
3103 			fem_addref(sp);
3104 			fem_unlock(fh);
3105 			nsp = femlist_create(sp->feml_ssize);
3106 			if (fem_lock(fh) == sp) {
3107 				/*
3108 				 * We popped out of the lock, created a
3109 				 * list, then relocked.  If we're in here
3110 				 * then the fem_head points to the same list
3111 				 * it started with.
3112 				 */
3113 				fem_dup_list(sp, nsp);
3114 				error = remove_node(nsp, baseops, opset, datap);
3115 				if (error != 0) {
3116 					fem_release(nsp);
3117 				} else if (nsp->feml_tos == 1) {
3118 					/* New list now empty, tear it down */
3119 					fem_release(nsp);
3120 					fh->femh_list = NULL;
3121 				} else {
3122 					fh->femh_list = nsp;
3123 				}
3124 				(void) fem_delref(sp);
3125 			} else {
3126 				/* List changed while locked, try again... */
3127 				fem_release(nsp);
3128 				retry = 1;
3129 			}
3130 			/*
3131 			 * If error is set, then we tried to remove a node
3132 			 * from the list, but failed.  This means that we
3133 			 * will still be using this list so don't release it.
3134 			 */
3135 			if (error == 0)
3136 				fem_release(sp);
3137 			fem_unlock(fh);
3138 		}
3139 	} while (retry);
3140 	return (error);
3141 }
3142 
3143 
3144 /*
3145  * perform operation on each element until one returns non zero
3146  */
3147 static int
3148 fem_walk_list(
3149 	struct fem_list *sp,
3150 	int (*f)(struct fem_node *, void *, void *),
3151 	void *mon,
3152 	void *arg)
3153 {
3154 	int	i;
3155 
3156 	ASSERT(sp != NULL);
3157 	for (i = sp->feml_tos; i > 0; i--) {
3158 		if ((*f)(sp->feml_nodes+i, mon, arg) != 0) {
3159 			break;
3160 		}
3161 	}
3162 	return (i);
3163 }
3164 
3165 /*
3166  * companion comparison functions.
3167  */
3168 static int
3169 fem_compare_mon(struct fem_node *n, void *mon, void *arg)
3170 {
3171 	return ((n->fn_op.anon == mon) && (n->fn_available == arg));
3172 }
3173 
3174 /*
3175  * VNODE interposition.
3176  */
3177 
3178 int
3179 fem_create(char *name, const struct fs_operation_def *templ,
3180     fem_t **actual)
3181 {
3182 	int	unused_ops = 0;
3183 	int	e;
3184 	fem_t	*newf;
3185 
3186 	newf = fem_alloc();
3187 	newf->name = name;
3188 	newf->templ = templ;
3189 
3190 	e =  fs_build_vector(newf, &unused_ops, fem_opdef, templ);
3191 	if (e != 0) {
3192 #ifdef DEBUG
3193 		cmn_err(CE_WARN, "fem_create: error %d building vector", e);
3194 #endif
3195 		fem_free(newf);
3196 	} else {
3197 		*actual = newf;
3198 	}
3199 	return (e);
3200 }
3201 
3202 int
3203 fem_install(
3204 	vnode_t *vp,		/* Vnode on which monitor is being installed */
3205 	fem_t *mon,		/* Monitor operations being installed */
3206 	void *arg,		/* Opaque data used by monitor */
3207 	femhow_t how,		/* Installation control */
3208 	void (*arg_hold)(void *),	/* Hold routine for "arg" */
3209 	void (*arg_rele)(void *))	/* Release routine for "arg" */
3210 {
3211 	int	error;
3212 	struct fem_node	nnode;
3213 
3214 	nnode.fn_available = arg;
3215 	nnode.fn_op.fem = mon;
3216 	nnode.fn_av_hold = arg_hold;
3217 	nnode.fn_av_rele = arg_rele;
3218 	/*
3219 	 * If we have a non-NULL hold function, do the hold right away.
3220 	 * The release is done in remove_node().
3221 	 */
3222 	if (arg_hold)
3223 		(*arg_hold)(arg);
3224 
3225 	error = fem_push_node(&vp->v_femhead, (void **)&vp->v_op, FEMTYPE_VNODE,
3226 	    &nnode, how);
3227 
3228 	/* If there was an error then the monitor wasn't pushed */
3229 	if (error && arg_rele)
3230 		(*arg_rele)(arg);
3231 
3232 	return (error);
3233 }
3234 
3235 int
3236 fem_is_installed(vnode_t *v, fem_t *mon, void *arg)
3237 {
3238 	int	e;
3239 	struct fem_list	*fl;
3240 
3241 	fl = fem_get(v->v_femhead);
3242 	if (fl != NULL) {
3243 		e = fem_walk_list(fl, fem_compare_mon, (void *)mon, arg);
3244 		fem_release(fl);
3245 		return (e);
3246 	}
3247 	return (0);
3248 }
3249 
3250 int
3251 fem_uninstall(vnode_t *v, fem_t *mon, void *arg)
3252 {
3253 	int	e;
3254 	e = fem_remove_node(v->v_femhead, (void **)&v->v_op,
3255 	    (void *)mon, arg);
3256 	return (e);
3257 }
3258 
3259 void
3260 fem_setvnops(vnode_t *v, vnodeops_t *newops)
3261 {
3262 	vnodeops_t	*r;
3263 
3264 	ASSERT(v != NULL);
3265 	ASSERT(newops != NULL);
3266 
3267 	do {
3268 		r = v->v_op;
3269 		membar_consumer();
3270 		if (v->v_femhead != NULL) {
3271 			struct fem_list	*fl;
3272 			if ((fl = fem_lock(v->v_femhead)) != NULL) {
3273 				fl->feml_nodes[1].fn_op.vnode = newops;
3274 				fem_unlock(v->v_femhead);
3275 				return;
3276 			}
3277 			fem_unlock(v->v_femhead);
3278 		}
3279 	} while (casptr(&v->v_op, r, newops) != r);
3280 }
3281 
3282 vnodeops_t *
3283 fem_getvnops(vnode_t *v)
3284 {
3285 	vnodeops_t	*r;
3286 
3287 	ASSERT(v != NULL);
3288 
3289 	r = v->v_op;
3290 	membar_consumer();
3291 	if (v->v_femhead != NULL) {
3292 		struct fem_list	*fl;
3293 		if ((fl = fem_lock(v->v_femhead)) != NULL) {
3294 			r = fl->feml_nodes[1].fn_op.vnode;
3295 		}
3296 		fem_unlock(v->v_femhead);
3297 	}
3298 	return (r);
3299 }
3300 
3301 
3302 /*
3303  * VFS interposition
3304  */
3305 int
3306 fsem_create(char *name, const struct fs_operation_def *templ,
3307     fsem_t **actual)
3308 {
3309 	int	unused_ops = 0;
3310 	int	e;
3311 	fsem_t	*newv;
3312 
3313 	newv = fsem_alloc();
3314 	newv->name = (const char *)name;
3315 	newv->templ = templ;
3316 
3317 	e = fs_build_vector(newv, &unused_ops, fsem_opdef, templ);
3318 	if (e != 0) {
3319 #ifdef DEBUG
3320 		cmn_err(CE_WARN, "fsem_create: error %d building vector", e);
3321 #endif
3322 		fsem_free(newv);
3323 	} else {
3324 		*actual = newv;
3325 	}
3326 	return (e);
3327 }
3328 
3329 /*
3330  * These need to be re-written, but there should be more common bits.
3331  */
3332 
3333 int
3334 fsem_is_installed(struct vfs *v, fsem_t *mon, void *arg)
3335 {
3336 	struct fem_list	*fl;
3337 
3338 	if (v->vfs_implp == NULL)
3339 		return (0);
3340 
3341 	fl = fem_get(v->vfs_femhead);
3342 	if (fl != NULL) {
3343 		int	e;
3344 		e = fem_walk_list(fl, fem_compare_mon, (void *)mon, arg);
3345 		fem_release(fl);
3346 		return (e);
3347 	}
3348 	return (0);
3349 }
3350 
3351 int
3352 fsem_install(
3353 	struct vfs *vfsp,	/* VFS on which monitor is being installed */
3354 	fsem_t *mon,		/* Monitor operations being installed */
3355 	void *arg,		/* Opaque data used by monitor */
3356 	femhow_t how,		/* Installation control */
3357 	void (*arg_hold)(void *),	/* Hold routine for "arg" */
3358 	void (*arg_rele)(void *))	/* Release routine for "arg" */
3359 {
3360 	int	error;
3361 	struct fem_node	nnode;
3362 
3363 	/* If this vfs hasn't been properly initialized, fail the install */
3364 	if (vfsp->vfs_implp == NULL)
3365 		return (EINVAL);
3366 
3367 	nnode.fn_available = arg;
3368 	nnode.fn_op.fsem = mon;
3369 	nnode.fn_av_hold = arg_hold;
3370 	nnode.fn_av_rele = arg_rele;
3371 	/*
3372 	 * If we have a non-NULL hold function, do the hold right away.
3373 	 * The release is done in remove_node().
3374 	 */
3375 	if (arg_hold)
3376 		(*arg_hold)(arg);
3377 
3378 	error = fem_push_node(&vfsp->vfs_femhead, (void **)&vfsp->vfs_op,
3379 	    FEMTYPE_VFS, &nnode, how);
3380 
3381 	/* If there was an error then the monitor wasn't pushed */
3382 	if (error && arg_rele)
3383 		(*arg_rele)(arg);
3384 
3385 	return (error);
3386 }
3387 
3388 int
3389 fsem_uninstall(struct vfs *v, fsem_t *mon, void *arg)
3390 {
3391 	int	e;
3392 
3393 	if (v->vfs_implp == NULL)
3394 		return (EINVAL);
3395 
3396 	e = fem_remove_node(v->vfs_femhead, (void **)&v->vfs_op,
3397 	    (void *)mon, arg);
3398 	return (e);
3399 }
3400 
3401 void
3402 fsem_setvfsops(vfs_t *v, vfsops_t *newops)
3403 {
3404 	vfsops_t	*r;
3405 
3406 	ASSERT(v != NULL);
3407 	ASSERT(newops != NULL);
3408 	ASSERT(v->vfs_implp);
3409 
3410 	do {
3411 		r = v->vfs_op;
3412 		membar_consumer();
3413 		if (v->vfs_femhead != NULL) {
3414 			struct fem_list	*fl;
3415 			if ((fl = fem_lock(v->vfs_femhead)) != NULL) {
3416 				fl->feml_nodes[1].fn_op.vfs = newops;
3417 				fem_unlock(v->vfs_femhead);
3418 				return;
3419 			}
3420 			fem_unlock(v->vfs_femhead);
3421 		}
3422 	} while (casptr(&v->vfs_op, r, newops) != r);
3423 }
3424 
3425 vfsops_t *
3426 fsem_getvfsops(vfs_t *v)
3427 {
3428 	vfsops_t	*r;
3429 
3430 	ASSERT(v != NULL);
3431 	ASSERT(v->vfs_implp);
3432 
3433 	r = v->vfs_op;
3434 	membar_consumer();
3435 	if (v->vfs_femhead != NULL) {
3436 		struct fem_list	*fl;
3437 		if ((fl = fem_lock(v->vfs_femhead)) != NULL) {
3438 			r = fl->feml_nodes[1].fn_op.vfs;
3439 		}
3440 		fem_unlock(v->vfs_femhead);
3441 	}
3442 	return (r);
3443 }
3444 
3445 /*
3446  * Setup FEM.
3447  */
3448 void
3449 fem_init()
3450 {
3451 	struct fem_type_info   *fi;
3452 
3453 	/*
3454 	 * This femtype is only used for fem_list creation so we only
3455 	 * need the "guard" to be initialized so that feml_tos has
3456 	 * some rudimentary meaning.  A fem_list must not be used until
3457 	 * it has been initialized (either via femlist_construct() or
3458 	 * fem_dup_list()).  Anything that tries to use this fem_list
3459 	 * before it's actually initialized would panic the system as
3460 	 * soon as "fn_op" (NULL) is dereferenced.
3461 	 */
3462 	fi = femtype + FEMTYPE_NULL;
3463 	fi->errf = fem_err;
3464 	fi->guard.fn_available = (void *)&fi->guard;
3465 	fi->guard.fn_av_hold = NULL;
3466 	fi->guard.fn_av_rele = NULL;
3467 	fi->guard.fn_op.anon = NULL;
3468 
3469 	fi = femtype + FEMTYPE_VNODE;
3470 	fi->errf = fem_err;
3471 	fi->head.fn_available = NULL;
3472 	fi->head.fn_av_hold = NULL;
3473 	fi->head.fn_av_rele = NULL;
3474 	(void) vn_make_ops("fem-head", fhead_vn_spec, &fi->head.fn_op.vnode);
3475 	fi->guard.fn_available = (void *)&fi->guard;
3476 	fi->guard.fn_av_hold = NULL;
3477 	fi->guard.fn_av_rele = NULL;
3478 	(void) fem_create("fem-guard", fem_guard_ops, &fi->guard.fn_op.fem);
3479 
3480 	fi = femtype + FEMTYPE_VFS;
3481 	fi->errf = fsem_err;
3482 	fi->head.fn_available = NULL;
3483 	fi->head.fn_av_hold = NULL;
3484 	fi->head.fn_av_rele = NULL;
3485 	(void) vfs_makefsops(fshead_vfs_spec, &fi->head.fn_op.vfs);
3486 
3487 	fi->guard.fn_available = (void *)&fi->guard;
3488 	fi->guard.fn_av_hold = NULL;
3489 	fi->guard.fn_av_rele = NULL;
3490 	(void) fsem_create("fem-guard", fsem_guard_ops, &fi->guard.fn_op.fsem);
3491 }
3492 
3493 
3494 int
3495 fem_err()
3496 {
3497 	cmn_err(CE_PANIC, "fem/vnode operations corrupt");
3498 	return (0);
3499 }
3500 
3501 int
3502 fsem_err()
3503 {
3504 	cmn_err(CE_PANIC, "fem/vfs operations corrupt");
3505 	return (0);
3506 }
3507