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