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