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