fem.c revision 3898:c788126f2a20
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
52typedef 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
62static 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
75int fem_err();
76int fsem_err();
77
78
79#define	_FEMOPDEF(name, member)  \
80	{ VOPNAME_##name, offsetof(fem_t, femop_##member), NULL, fem_err }
81
82static 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
134static 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
186static 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
202static 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) \
230for (;;) { \
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) \
245for (;;) { \
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
269static 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
291static fem_t *
292fem_alloc()
293{
294	fem_t	*p;
295
296	p = (fem_t *)kmem_alloc(sizeof (*p), KM_SLEEP);
297	return (p);
298}
299
300void
301fem_free(fem_t *p)
302{
303	kmem_free(p, sizeof (*p));
304}
305
306static fsem_t *
307fsem_alloc()
308{
309	fsem_t	*p;
310
311	p = (fsem_t *)kmem_alloc(sizeof (*p), KM_SLEEP);
312	return (p);
313}
314
315void
316fsem_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
342static struct fem_list *
343fem_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
353static void
354fem_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
364static void
365fem_addref(struct fem_list *sp)
366{
367	atomic_add_32(&sp->feml_refc, 1);
368}
369
370static uint32_t
371fem_delref(struct fem_list *sp)
372{
373	return (atomic_add_32_nv(&sp->feml_refc, -1));
374}
375
376static struct fem_list *
377fem_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
390static void
391fem_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
430static int
431vhead_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
456static int
457vhead_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
482static int
483vhead_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
509static int
510vhead_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
536static int
537vhead_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
563static int
564vhead_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
589static int
590vhead_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
616static int
617vhead_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
644static int
645vhead_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
671static int
672vhead_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
699static int
700vhead_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
727static int
728vhead_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
754static int
755vhead_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
780static int
781vhead_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
808static int
809vhead_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
835static int
836vhead_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
861static int
862vhead_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
888static int
889vhead_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
916static int
917vhead_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
943static int
944vhead_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
969static void
970vhead_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
994static int
995vhead_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
1020static int
1021vhead_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
1047static void
1048vhead_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
1072static int
1073vhead_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
1098static int
1099vhead_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
1124static int
1125vhead_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
1152static int
1153vhead_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
1179static int
1180vhead_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
1206static int
1207vhead_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
1237static int
1238vhead_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
1264static int
1265vhead_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
1294static int
1295vhead_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
1325static int
1326vhead_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
1355static int
1356vhead_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
1382static int
1383vhead_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
1408static int
1409vhead_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
1435static int
1436vhead_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
1463static int
1464vhead_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
1490static void
1491vhead_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
1515static int
1516vhead_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
1542static int
1543vhead_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
1569static int
1570vhead_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
1597static int
1598vhead_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
1624static int
1625fshead_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
1652static int
1653fshead_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
1680static int
1681fshead_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
1707static int
1708fshead_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
1735static int
1736fshead_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
1762static int
1763fshead_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
1789static int
1790fshead_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
1817static void
1818fshead_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
1843static int
1844fshead_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
1877static 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
1930static 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
1960int
1961vnext_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
1974int
1975vnext_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
1988int
1989vnext_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
2003int
2004vnext_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
2018int
2019vnext_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
2033int
2034vnext_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
2047int
2048vnext_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
2061int
2062vnext_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
2076int
2077vnext_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
2090int
2091vnext_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
2105int
2106vnext_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
2120int
2121vnext_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
2134int
2135vnext_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
2148int
2149vnext_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
2162int
2163vnext_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
2177int
2178vnext_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
2191int
2192vnext_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
2205int
2206vnext_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
2220int
2221vnext_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
2234int
2235vnext_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
2248void
2249vnext_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
2262int
2263vnext_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
2276int
2277vnext_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
2290void
2291vnext_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
2304int
2305vnext_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
2318int
2319vnext_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
2332int
2333vnext_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
2347int
2348vnext_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
2362int
2363vnext_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
2376int
2377vnext_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
2393int
2394vnext_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
2408int
2409vnext_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
2425int
2426vnext_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
2441int
2442vnext_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
2456int
2457vnext_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
2471int
2472vnext_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
2485int
2486vnext_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
2499int
2500vnext_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
2514int
2515vnext_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
2528void
2529vnext_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
2542int
2543vnext_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
2556int
2557vnext_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
2570int
2571vnext_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
2585int
2586vnext_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
2599int
2600vfsnext_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
2613int
2614vfsnext_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
2627int
2628vfsnext_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
2641int
2642vfsnext_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
2655int
2656vfsnext_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
2669int
2670vfsnext_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
2683int
2684vfsnext_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
2697void
2698vfsnext_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
2711int
2712vfsnext_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
2733static struct fem_head *
2734new_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 */
2760static struct fem_list *
2761femlist_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
2779static struct fem_list *
2780femlist_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
2802static void
2803fem_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
2825static int
2826fem_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
2988static int
2989remove_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
3023static int
3024fem_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 */
3102static int
3103fem_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 */
3123static int
3124fem_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
3133int
3134fem_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
3157int
3158fem_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
3190int
3191fem_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
3205int
3206fem_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
3214void
3215fem_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
3237vnodeops_t *
3238fem_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 */
3260int
3261fsem_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
3288int
3289fsem_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
3306int
3307fsem_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
3343int
3344fsem_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
3356void
3357fsem_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
3380vfsops_t *
3381fsem_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 */
3403void
3404fem_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
3449int
3450fem_err()
3451{
3452	cmn_err(CE_PANIC, "fem/vnode operations corrupt");
3453	return (0);
3454}
3455
3456int
3457fsem_err()
3458{
3459	cmn_err(CE_PANIC, "fem/vfs operations corrupt");
3460	return (0);
3461}
3462