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