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