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