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