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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 #pragma ident "%Z%%M% %I% %E% SMI" 26 27 #include <sys/types.h> 28 #include <sys/atomic.h> 29 #include <sys/kmem.h> 30 #include <sys/mutex.h> 31 #include <sys/errno.h> 32 #include <sys/param.h> 33 #include <sys/sysmacros.h> 34 #include <sys/systm.h> 35 #include <sys/cmn_err.h> 36 #include <sys/debug.h> 37 38 #include <sys/fem.h> 39 #include <sys/vfs.h> 40 #include <sys/vnode.h> 41 #include <sys/vfs_opreg.h> 42 43 #define NNODES_DEFAULT 8 /* Default number of nodes in a fem_list */ 44 /* 45 * fl_ntob(n) - Fem_list: number of nodes to bytes 46 * Given the number of nodes in a fem_list return the size, in bytes, 47 * of the fem_list structure. 48 */ 49 #define fl_ntob(n) (sizeof (struct fem_list) + \ 50 ((n) - 1) * sizeof (struct fem_node)) 51 52 typedef enum { 53 FEMTYPE_NULL, /* Uninitialized */ 54 FEMTYPE_VNODE, 55 FEMTYPE_VFS, 56 FEMTYPE_NTYPES 57 } femtype_t; 58 59 #define FEM_HEAD(_t) femtype[(_t)].head.fn_op.anon 60 #define FEM_GUARD(_t) femtype[(_t)].guard 61 62 static struct fem_type_info { 63 struct fem_node head; 64 struct fem_node guard; 65 femop_t *errf; 66 } femtype[FEMTYPE_NTYPES]; 67 68 69 /* 70 * For each type, two tables - the translation offset definition, which 71 * is used by fs_build_vector to layout the operation(s) vector; and the 72 * guard_operation_vector which protects from stack under-run. 73 */ 74 75 int fem_err(); 76 int fsem_err(); 77 78 79 #define _FEMOPDEF(name, member) \ 80 { VOPNAME_##name, offsetof(fem_t, femop_##member), NULL, fem_err } 81 82 static fs_operation_trans_def_t fem_opdef[] = { 83 _FEMOPDEF(OPEN, open), 84 _FEMOPDEF(CLOSE, close), 85 _FEMOPDEF(READ, read), 86 _FEMOPDEF(WRITE, write), 87 _FEMOPDEF(IOCTL, ioctl), 88 _FEMOPDEF(SETFL, setfl), 89 _FEMOPDEF(GETATTR, getattr), 90 _FEMOPDEF(SETATTR, setattr), 91 _FEMOPDEF(ACCESS, access), 92 _FEMOPDEF(LOOKUP, lookup), 93 _FEMOPDEF(CREATE, create), 94 _FEMOPDEF(REMOVE, remove), 95 _FEMOPDEF(LINK, link), 96 _FEMOPDEF(RENAME, rename), 97 _FEMOPDEF(MKDIR, mkdir), 98 _FEMOPDEF(RMDIR, rmdir), 99 _FEMOPDEF(READDIR, readdir), 100 _FEMOPDEF(SYMLINK, symlink), 101 _FEMOPDEF(READLINK, readlink), 102 _FEMOPDEF(FSYNC, fsync), 103 _FEMOPDEF(INACTIVE, inactive), 104 _FEMOPDEF(FID, fid), 105 _FEMOPDEF(RWLOCK, rwlock), 106 _FEMOPDEF(RWUNLOCK, rwunlock), 107 _FEMOPDEF(SEEK, seek), 108 _FEMOPDEF(CMP, cmp), 109 _FEMOPDEF(FRLOCK, frlock), 110 _FEMOPDEF(SPACE, space), 111 _FEMOPDEF(REALVP, realvp), 112 _FEMOPDEF(GETPAGE, getpage), 113 _FEMOPDEF(PUTPAGE, putpage), 114 _FEMOPDEF(MAP, map), 115 _FEMOPDEF(ADDMAP, addmap), 116 _FEMOPDEF(DELMAP, delmap), 117 _FEMOPDEF(POLL, poll), 118 _FEMOPDEF(DUMP, dump), 119 _FEMOPDEF(PATHCONF, pathconf), 120 _FEMOPDEF(PAGEIO, pageio), 121 _FEMOPDEF(DUMPCTL, dumpctl), 122 _FEMOPDEF(DISPOSE, dispose), 123 _FEMOPDEF(SETSECATTR, setsecattr), 124 _FEMOPDEF(GETSECATTR, getsecattr), 125 _FEMOPDEF(SHRLOCK, shrlock), 126 _FEMOPDEF(VNEVENT, vnevent), 127 { NULL, 0, NULL, NULL } 128 }; 129 130 131 #define _FEMGUARD(name, ignore) \ 132 { VOPNAME_##name, (femop_t *)fem_err } 133 134 static struct fs_operation_def fem_guard_ops[] = { 135 _FEMGUARD(OPEN, open), 136 _FEMGUARD(CLOSE, close), 137 _FEMGUARD(READ, read), 138 _FEMGUARD(WRITE, write), 139 _FEMGUARD(IOCTL, ioctl), 140 _FEMGUARD(SETFL, setfl), 141 _FEMGUARD(GETATTR, getattr), 142 _FEMGUARD(SETATTR, setattr), 143 _FEMGUARD(ACCESS, access), 144 _FEMGUARD(LOOKUP, lookup), 145 _FEMGUARD(CREATE, create), 146 _FEMGUARD(REMOVE, remove), 147 _FEMGUARD(LINK, link), 148 _FEMGUARD(RENAME, rename), 149 _FEMGUARD(MKDIR, mkdir), 150 _FEMGUARD(RMDIR, rmdir), 151 _FEMGUARD(READDIR, readdir), 152 _FEMGUARD(SYMLINK, symlink), 153 _FEMGUARD(READLINK, readlink), 154 _FEMGUARD(FSYNC, fsync), 155 _FEMGUARD(INACTIVE, inactive), 156 _FEMGUARD(FID, fid), 157 _FEMGUARD(RWLOCK, rwlock), 158 _FEMGUARD(RWUNLOCK, rwunlock), 159 _FEMGUARD(SEEK, seek), 160 _FEMGUARD(CMP, cmp), 161 _FEMGUARD(FRLOCK, frlock), 162 _FEMGUARD(SPACE, space), 163 _FEMGUARD(REALVP, realvp), 164 _FEMGUARD(GETPAGE, getpage), 165 _FEMGUARD(PUTPAGE, putpage), 166 _FEMGUARD(MAP, map), 167 _FEMGUARD(ADDMAP, addmap), 168 _FEMGUARD(DELMAP, delmap), 169 _FEMGUARD(POLL, poll), 170 _FEMGUARD(DUMP, dump), 171 _FEMGUARD(PATHCONF, pathconf), 172 _FEMGUARD(PAGEIO, pageio), 173 _FEMGUARD(DUMPCTL, dumpctl), 174 _FEMGUARD(DISPOSE, dispose), 175 _FEMGUARD(SETSECATTR, setsecattr), 176 _FEMGUARD(GETSECATTR, getsecattr), 177 _FEMGUARD(SHRLOCK, shrlock), 178 _FEMGUARD(VNEVENT, vnevent), 179 { NULL, NULL } 180 }; 181 182 183 #define _FSEMOPDEF(name, member) \ 184 { VFSNAME_##name, offsetof(fsem_t, fsemop_##member), NULL, fsem_err } 185 186 static fs_operation_trans_def_t fsem_opdef[] = { 187 _FSEMOPDEF(MOUNT, mount), 188 _FSEMOPDEF(UNMOUNT, unmount), 189 _FSEMOPDEF(ROOT, root), 190 _FSEMOPDEF(STATVFS, statvfs), 191 _FSEMOPDEF(SYNC, sync), 192 _FSEMOPDEF(VGET, vget), 193 _FSEMOPDEF(MOUNTROOT, mountroot), 194 _FSEMOPDEF(FREEVFS, freevfs), 195 _FSEMOPDEF(VNSTATE, vnstate), 196 { NULL, 0, NULL, NULL } 197 }; 198 199 #define _FSEMGUARD(name, ignore) \ 200 { VFSNAME_##name, (femop_t *)fsem_err } 201 202 static struct fs_operation_def fsem_guard_ops[] = { 203 _FSEMGUARD(MOUNT, mount), 204 _FSEMGUARD(UNMOUNT, unmount), 205 _FSEMGUARD(ROOT, root), 206 _FSEMGUARD(STATVFS, statvfs), 207 _FSEMGUARD(SYNC, sync), 208 _FSEMGUARD(VGET, vget), 209 _FSEMGUARD(MOUNTROOT, mountroot), 210 _FSEMGUARD(FREEVFS, freevfs), 211 _FSEMGUARD(VNSTATE, vnstate), 212 { NULL, NULL} 213 }; 214 215 216 /* 217 * vsop_find, vfsop_find - 218 * 219 * These macros descend the stack until they find either a basic 220 * vnode/vfs operation [ indicated by a null fn_available ] or a 221 * stacked item where this method is non-null [_vsop]. 222 * 223 * The DEBUG one is written with a single function which manually applies 224 * the structure offsets. It can have additional debugging support. 225 */ 226 227 #ifndef DEBUG 228 229 #define vsop_find(ap, func, funct, arg0, _vop, _vsop) \ 230 for (;;) { \ 231 if ((ap)->fa_fnode->fn_available == NULL) { \ 232 *(func) = (funct (*)())((ap)->fa_fnode->fn_op.vnode->_vop); \ 233 *(arg0) = (void *)(ap)->fa_vnode.vp; \ 234 break; \ 235 } else if ((*(func) = (funct (*)())((ap)->fa_fnode->fn_op.fem->_vsop))\ 236 != NULL) { \ 237 *(arg0) = (void *) (ap); \ 238 break; \ 239 } else { \ 240 (ap)->fa_fnode--; \ 241 } \ 242 } \ 243 244 #define vfsop_find(ap, func, funct, arg0, _vop, _vsop) \ 245 for (;;) { \ 246 if ((ap)->fa_fnode->fn_available == NULL) { \ 247 *(func) = (funct (*)())((ap)->fa_fnode->fn_op.vfs->_vop); \ 248 *(arg0) = (void *)(ap)->fa_vnode.vp; \ 249 break; \ 250 } else if ((*(func) = (funct (*)())((ap)->fa_fnode->fn_op.fsem->_vsop))\ 251 != NULL) { \ 252 *(arg0) = (void *) (ap); \ 253 break; \ 254 } else { \ 255 (ap)->fa_fnode--; \ 256 } \ 257 } \ 258 259 #else 260 261 #define vsop_find(ap, func, funct, arg0, _vop, _vsop) \ 262 *(arg0) = _op_find((ap), (void **)(func), \ 263 offsetof(vnodeops_t, _vop), offsetof(fem_t, _vsop)) 264 265 #define vfsop_find(ap, func, funct, arg0, _fop, _fsop) \ 266 *(arg0) = _op_find((ap), (void **)(func), \ 267 offsetof(vfsops_t, _fop), offsetof(fsem_t, _fsop)) 268 269 static void * 270 _op_find(femarg_t *ap, void **fp, int offs0, int offs1) 271 { 272 void *ptr; 273 for (;;) { 274 struct fem_node *fnod = ap->fa_fnode; 275 if (fnod->fn_available == NULL) { 276 *fp = *(void **)((char *)fnod->fn_op.anon + offs0); 277 ptr = (void *)(ap->fa_vnode.anon); 278 break; 279 } else if ((*fp = *(void **)((char *)fnod->fn_op.anon+offs1)) 280 != NULL) { 281 ptr = (void *)(ap); 282 break; 283 } else { 284 ap->fa_fnode--; 285 } 286 } 287 return (ptr); 288 } 289 #endif 290 291 static fem_t * 292 fem_alloc() 293 { 294 fem_t *p; 295 296 p = (fem_t *)kmem_alloc(sizeof (*p), KM_SLEEP); 297 return (p); 298 } 299 300 void 301 fem_free(fem_t *p) 302 { 303 kmem_free(p, sizeof (*p)); 304 } 305 306 static fsem_t * 307 fsem_alloc() 308 { 309 fsem_t *p; 310 311 p = (fsem_t *)kmem_alloc(sizeof (*p), KM_SLEEP); 312 return (p); 313 } 314 315 void 316 fsem_free(fsem_t *p) 317 { 318 kmem_free(p, sizeof (*p)); 319 } 320 321 322 /* 323 * fem_get, fem_release - manage reference counts on the stack. 324 * 325 * The list of monitors can be updated while operations are in 326 * progress on the object. 327 * 328 * The reference count facilitates this by counting the number of 329 * current accessors, and deconstructing the list when it is exhausted. 330 * 331 * fem_lock() is required to: 332 * look at femh_list 333 * update what femh_list points to 334 * update femh_list 335 * increase femh_list->feml_refc. 336 * 337 * the feml_refc can decrement without holding the lock; 338 * when feml_refc becomes zero, the list is destroyed. 339 * 340 */ 341 342 static struct fem_list * 343 fem_lock(struct fem_head *fp) 344 { 345 struct fem_list *sp = NULL; 346 347 ASSERT(fp != NULL); 348 mutex_enter(&fp->femh_lock); 349 sp = fp->femh_list; 350 return (sp); 351 } 352 353 static void 354 fem_unlock(struct fem_head *fp) 355 { 356 ASSERT(fp != NULL); 357 mutex_exit(&fp->femh_lock); 358 } 359 360 /* 361 * Addref can only be called while its head->lock is held. 362 */ 363 364 static void 365 fem_addref(struct fem_list *sp) 366 { 367 atomic_add_32(&sp->feml_refc, 1); 368 } 369 370 static uint32_t 371 fem_delref(struct fem_list *sp) 372 { 373 return (atomic_add_32_nv(&sp->feml_refc, -1)); 374 } 375 376 static struct fem_list * 377 fem_get(struct fem_head *fp) 378 { 379 struct fem_list *sp = NULL; 380 381 if (fp != NULL) { 382 if ((sp = fem_lock(fp)) != NULL) { 383 fem_addref(sp); 384 } 385 fem_unlock(fp); 386 } 387 return (sp); 388 } 389 390 static void 391 fem_release(struct fem_list *sp) 392 { 393 int i; 394 395 ASSERT(sp->feml_refc != 0); 396 if (fem_delref(sp) == 0) { 397 /* 398 * Before freeing the list, we need to release the 399 * caller-provided data. 400 */ 401 for (i = sp->feml_tos; i > 0; i--) { 402 struct fem_node *fnp = &sp->feml_nodes[i]; 403 404 if (fnp->fn_av_rele) 405 (*(fnp->fn_av_rele))(fnp->fn_available); 406 } 407 kmem_free(sp, fl_ntob(sp->feml_ssize)); 408 } 409 } 410 411 412 /* 413 * These are the 'head' operations which perform the interposition. 414 * 415 * This set must be 1:1, onto with the (vnodeops, vfsos). 416 * 417 * If there is a desire to globally disable interposition for a particular 418 * method, the corresponding 'head' routine should unearth the base method 419 * and invoke it directly rather than bypassing the function. 420 * 421 * All the functions are virtually the same, save for names, types & args. 422 * 1. get a reference to the monitor stack for this object. 423 * 2. store the top of stack into the femarg structure. 424 * 3. store the basic object (vnode *, vnode **, vfs *) in the femarg struc. 425 * 4. invoke the "top" method for this object. 426 * 5. release the reference to the monitor stack. 427 * 428 */ 429 430 static int 431 vhead_open(vnode_t **vpp, int mode, cred_t *cr, caller_context_t *ct) 432 { 433 femarg_t farg; 434 struct fem_list *femsp; 435 int (*func)(); 436 void *arg0; 437 int errc; 438 439 if ((femsp = fem_lock((*vpp)->v_femhead)) == NULL) { 440 func = (int (*)()) ((*vpp)->v_op->vop_open); 441 arg0 = (void *)vpp; 442 fem_unlock((*vpp)->v_femhead); 443 errc = (*func)(arg0, mode, cr, ct); 444 } else { 445 fem_addref(femsp); 446 fem_unlock((*vpp)->v_femhead); 447 farg.fa_vnode.vpp = vpp; 448 farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos; 449 vsop_find(&farg, &func, int, &arg0, vop_open, femop_open); 450 errc = (*func)(arg0, mode, cr, ct); 451 fem_release(femsp); 452 } 453 return (errc); 454 } 455 456 static int 457 vhead_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr, 458 caller_context_t *ct) 459 { 460 femarg_t farg; 461 struct fem_list *femsp; 462 int (*func)(); 463 void *arg0; 464 int errc; 465 466 if ((femsp = fem_lock(vp->v_femhead)) == NULL) { 467 func = (int (*)()) (vp->v_op->vop_close); 468 arg0 = vp; 469 fem_unlock(vp->v_femhead); 470 errc = (*func)(arg0, flag, count, offset, cr, ct); 471 } else { 472 fem_addref(femsp); 473 fem_unlock(vp->v_femhead); 474 farg.fa_vnode.vp = vp; 475 farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos; 476 vsop_find(&farg, &func, int, &arg0, vop_close, femop_close); 477 errc = (*func)(arg0, flag, count, offset, cr, ct); 478 fem_release(femsp); 479 } 480 return (errc); 481 } 482 483 static int 484 vhead_read(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr, 485 caller_context_t *ct) 486 { 487 femarg_t farg; 488 struct fem_list *femsp; 489 int (*func)(); 490 void *arg0; 491 int errc; 492 493 if ((femsp = fem_lock(vp->v_femhead)) == NULL) { 494 func = (int (*)()) (vp->v_op->vop_read); 495 arg0 = vp; 496 fem_unlock(vp->v_femhead); 497 errc = (*func)(arg0, uiop, ioflag, cr, ct); 498 } else { 499 fem_addref(femsp); 500 fem_unlock(vp->v_femhead); 501 farg.fa_vnode.vp = vp; 502 farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos; 503 vsop_find(&farg, &func, int, &arg0, vop_read, femop_read); 504 errc = (*func)(arg0, uiop, ioflag, cr, ct); 505 fem_release(femsp); 506 } 507 return (errc); 508 } 509 510 static int 511 vhead_write(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr, 512 caller_context_t *ct) 513 { 514 femarg_t farg; 515 struct fem_list *femsp; 516 int (*func)(); 517 void *arg0; 518 int errc; 519 520 if ((femsp = fem_lock(vp->v_femhead)) == NULL) { 521 func = (int (*)()) (vp->v_op->vop_write); 522 arg0 = vp; 523 fem_unlock(vp->v_femhead); 524 errc = (*func)(arg0, uiop, ioflag, cr, ct); 525 } else { 526 fem_addref(femsp); 527 fem_unlock(vp->v_femhead); 528 farg.fa_vnode.vp = vp; 529 farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos; 530 vsop_find(&farg, &func, int, &arg0, vop_write, femop_write); 531 errc = (*func)(arg0, uiop, ioflag, cr, ct); 532 fem_release(femsp); 533 } 534 return (errc); 535 } 536 537 static int 538 vhead_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, cred_t *cr, 539 int *rvalp, caller_context_t *ct) 540 { 541 femarg_t farg; 542 struct fem_list *femsp; 543 int (*func)(); 544 void *arg0; 545 int errc; 546 547 if ((femsp = fem_lock(vp->v_femhead)) == NULL) { 548 func = (int (*)()) (vp->v_op->vop_ioctl); 549 arg0 = vp; 550 fem_unlock(vp->v_femhead); 551 errc = (*func)(arg0, cmd, arg, flag, cr, rvalp, ct); 552 } else { 553 fem_addref(femsp); 554 fem_unlock(vp->v_femhead); 555 farg.fa_vnode.vp = vp; 556 farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos; 557 vsop_find(&farg, &func, int, &arg0, vop_ioctl, femop_ioctl); 558 errc = (*func)(arg0, cmd, arg, flag, cr, rvalp, ct); 559 fem_release(femsp); 560 } 561 return (errc); 562 } 563 564 static int 565 vhead_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr, 566 caller_context_t *ct) 567 { 568 femarg_t farg; 569 struct fem_list *femsp; 570 int (*func)(); 571 void *arg0; 572 int errc; 573 574 if ((femsp = fem_lock(vp->v_femhead)) == NULL) { 575 func = (int (*)()) (vp->v_op->vop_setfl); 576 arg0 = vp; 577 fem_unlock(vp->v_femhead); 578 errc = (*func)(arg0, oflags, nflags, cr, ct); 579 } else { 580 fem_addref(femsp); 581 fem_unlock(vp->v_femhead); 582 farg.fa_vnode.vp = vp; 583 farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos; 584 vsop_find(&farg, &func, int, &arg0, vop_setfl, femop_setfl); 585 errc = (*func)(arg0, oflags, nflags, cr, ct); 586 fem_release(femsp); 587 } 588 return (errc); 589 } 590 591 static int 592 vhead_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, 593 caller_context_t *ct) 594 { 595 femarg_t farg; 596 struct fem_list *femsp; 597 int (*func)(); 598 void *arg0; 599 int errc; 600 601 if ((femsp = fem_lock(vp->v_femhead)) == NULL) { 602 func = (int (*)()) (vp->v_op->vop_getattr); 603 arg0 = vp; 604 fem_unlock(vp->v_femhead); 605 errc = (*func)(arg0, vap, flags, cr, ct); 606 } else { 607 fem_addref(femsp); 608 fem_unlock(vp->v_femhead); 609 farg.fa_vnode.vp = vp; 610 farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos; 611 vsop_find(&farg, &func, int, &arg0, vop_getattr, 612 femop_getattr); 613 errc = (*func)(arg0, vap, flags, cr, ct); 614 fem_release(femsp); 615 } 616 return (errc); 617 } 618 619 static int 620 vhead_setattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, 621 caller_context_t *ct) 622 { 623 femarg_t farg; 624 struct fem_list *femsp; 625 int (*func)(); 626 void *arg0; 627 int errc; 628 629 if ((femsp = fem_lock(vp->v_femhead)) == NULL) { 630 func = (int (*)()) (vp->v_op->vop_setattr); 631 arg0 = vp; 632 fem_unlock(vp->v_femhead); 633 errc = (*func)(arg0, vap, flags, cr, ct); 634 } else { 635 fem_addref(femsp); 636 fem_unlock(vp->v_femhead); 637 farg.fa_vnode.vp = vp; 638 farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos; 639 vsop_find(&farg, &func, int, &arg0, vop_setattr, 640 femop_setattr); 641 errc = (*func)(arg0, vap, flags, cr, ct); 642 fem_release(femsp); 643 } 644 return (errc); 645 } 646 647 static int 648 vhead_access(vnode_t *vp, int mode, int flags, cred_t *cr, 649 caller_context_t *ct) 650 { 651 femarg_t farg; 652 struct fem_list *femsp; 653 int (*func)(); 654 void *arg0; 655 int errc; 656 657 if ((femsp = fem_lock(vp->v_femhead)) == NULL) { 658 func = (int (*)()) (vp->v_op->vop_access); 659 arg0 = vp; 660 fem_unlock(vp->v_femhead); 661 errc = (*func)(arg0, mode, flags, cr, ct); 662 } else { 663 fem_addref(femsp); 664 fem_unlock(vp->v_femhead); 665 farg.fa_vnode.vp = vp; 666 farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos; 667 vsop_find(&farg, &func, int, &arg0, vop_access, 668 femop_access); 669 errc = (*func)(arg0, mode, flags, cr, ct); 670 fem_release(femsp); 671 } 672 return (errc); 673 } 674 675 static int 676 vhead_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, pathname_t *pnp, 677 int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct, 678 int *direntflags, pathname_t *realpnp) 679 { 680 femarg_t farg; 681 struct fem_list *femsp; 682 int (*func)(); 683 void *arg0; 684 int errc; 685 686 if ((femsp = fem_lock(dvp->v_femhead)) == NULL) { 687 func = (int (*)()) (dvp->v_op->vop_lookup); 688 arg0 = dvp; 689 fem_unlock(dvp->v_femhead); 690 errc = (*func)(arg0, nm, vpp, pnp, flags, rdir, cr, ct, 691 direntflags, realpnp); 692 } else { 693 fem_addref(femsp); 694 fem_unlock(dvp->v_femhead); 695 farg.fa_vnode.vp = dvp; 696 farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos; 697 vsop_find(&farg, &func, int, &arg0, vop_lookup, 698 femop_lookup); 699 errc = (*func)(arg0, nm, vpp, pnp, flags, rdir, cr, ct, 700 direntflags, realpnp); 701 fem_release(femsp); 702 } 703 return (errc); 704 } 705 706 static int 707 vhead_create(vnode_t *dvp, char *name, vattr_t *vap, vcexcl_t excl, 708 int mode, vnode_t **vpp, cred_t *cr, int flag, caller_context_t *ct, 709 vsecattr_t *vsecp) 710 { 711 femarg_t farg; 712 struct fem_list *femsp; 713 int (*func)(); 714 void *arg0; 715 int errc; 716 717 if ((femsp = fem_lock(dvp->v_femhead)) == NULL) { 718 func = (int (*)()) (dvp->v_op->vop_create); 719 arg0 = dvp; 720 fem_unlock(dvp->v_femhead); 721 errc = (*func)(arg0, name, vap, excl, mode, vpp, cr, flag, 722 ct, vsecp); 723 } else { 724 fem_addref(femsp); 725 fem_unlock(dvp->v_femhead); 726 farg.fa_vnode.vp = dvp; 727 farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos; 728 vsop_find(&farg, &func, int, &arg0, vop_create, 729 femop_create); 730 errc = (*func)(arg0, name, vap, excl, mode, vpp, cr, flag, 731 ct, vsecp); 732 fem_release(femsp); 733 } 734 return (errc); 735 } 736 737 static int 738 vhead_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct, 739 int flags) 740 { 741 femarg_t farg; 742 struct fem_list *femsp; 743 int (*func)(); 744 void *arg0; 745 int errc; 746 747 if ((femsp = fem_lock(dvp->v_femhead)) == NULL) { 748 func = (int (*)()) (dvp->v_op->vop_remove); 749 arg0 = dvp; 750 fem_unlock(dvp->v_femhead); 751 errc = (*func)(arg0, nm, cr, ct, flags); 752 } else { 753 fem_addref(femsp); 754 fem_unlock(dvp->v_femhead); 755 farg.fa_vnode.vp = dvp; 756 farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos; 757 vsop_find(&farg, &func, int, &arg0, vop_remove, 758 femop_remove); 759 errc = (*func)(arg0, nm, cr, ct, flags); 760 fem_release(femsp); 761 } 762 return (errc); 763 } 764 765 static int 766 vhead_link(vnode_t *tdvp, vnode_t *svp, char *tnm, cred_t *cr, 767 caller_context_t *ct, int flags) 768 { 769 femarg_t farg; 770 struct fem_list *femsp; 771 int (*func)(); 772 void *arg0; 773 int errc; 774 775 if ((femsp = fem_lock(tdvp->v_femhead)) == NULL) { 776 func = (int (*)()) (tdvp->v_op->vop_link); 777 arg0 = tdvp; 778 fem_unlock(tdvp->v_femhead); 779 errc = (*func)(arg0, svp, tnm, cr, ct, flags); 780 } else { 781 fem_addref(femsp); 782 fem_unlock(tdvp->v_femhead); 783 farg.fa_vnode.vp = tdvp; 784 farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos; 785 vsop_find(&farg, &func, int, &arg0, vop_link, femop_link); 786 errc = (*func)(arg0, svp, tnm, cr, ct, flags); 787 fem_release(femsp); 788 } 789 return (errc); 790 } 791 792 static int 793 vhead_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, 794 cred_t *cr, caller_context_t *ct, int flags) 795 { 796 femarg_t farg; 797 struct fem_list *femsp; 798 int (*func)(); 799 void *arg0; 800 int errc; 801 802 if ((femsp = fem_lock(sdvp->v_femhead)) == NULL) { 803 func = (int (*)()) (sdvp->v_op->vop_rename); 804 arg0 = sdvp; 805 fem_unlock(sdvp->v_femhead); 806 errc = (*func)(arg0, snm, tdvp, tnm, cr, ct, flags); 807 } else { 808 fem_addref(femsp); 809 fem_unlock(sdvp->v_femhead); 810 farg.fa_vnode.vp = sdvp; 811 farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos; 812 vsop_find(&farg, &func, int, &arg0, vop_rename, 813 femop_rename); 814 errc = (*func)(arg0, snm, tdvp, tnm, cr, ct, flags); 815 fem_release(femsp); 816 } 817 return (errc); 818 } 819 820 static int 821 vhead_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t **vpp, 822 cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp) 823 { 824 femarg_t farg; 825 struct fem_list *femsp; 826 int (*func)(); 827 void *arg0; 828 int errc; 829 830 if ((femsp = fem_lock(dvp->v_femhead)) == NULL) { 831 func = (int (*)()) (dvp->v_op->vop_mkdir); 832 arg0 = dvp; 833 fem_unlock(dvp->v_femhead); 834 errc = (*func)(arg0, dirname, vap, vpp, cr, ct, flags, vsecp); 835 } else { 836 fem_addref(femsp); 837 fem_unlock(dvp->v_femhead); 838 farg.fa_vnode.vp = dvp; 839 farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos; 840 vsop_find(&farg, &func, int, &arg0, vop_mkdir, femop_mkdir); 841 errc = (*func)(arg0, dirname, vap, vpp, cr, ct, flags, vsecp); 842 fem_release(femsp); 843 } 844 return (errc); 845 } 846 847 static int 848 vhead_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr, 849 caller_context_t *ct, int flags) 850 { 851 femarg_t farg; 852 struct fem_list *femsp; 853 int (*func)(); 854 void *arg0; 855 int errc; 856 857 if ((femsp = fem_lock(dvp->v_femhead)) == NULL) { 858 func = (int (*)()) (dvp->v_op->vop_rmdir); 859 arg0 = dvp; 860 fem_unlock(dvp->v_femhead); 861 errc = (*func)(arg0, nm, cdir, cr, ct, flags); 862 } else { 863 fem_addref(femsp); 864 fem_unlock(dvp->v_femhead); 865 farg.fa_vnode.vp = dvp; 866 farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos; 867 vsop_find(&farg, &func, int, &arg0, vop_rmdir, femop_rmdir); 868 errc = (*func)(arg0, nm, cdir, cr, ct, flags); 869 fem_release(femsp); 870 } 871 return (errc); 872 } 873 874 static int 875 vhead_readdir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp, 876 caller_context_t *ct, int flags) 877 { 878 femarg_t farg; 879 struct fem_list *femsp; 880 int (*func)(); 881 void *arg0; 882 int errc; 883 884 if ((femsp = fem_lock(vp->v_femhead)) == NULL) { 885 func = (int (*)()) (vp->v_op->vop_readdir); 886 arg0 = vp; 887 fem_unlock(vp->v_femhead); 888 errc = (*func)(arg0, uiop, cr, eofp, ct, flags); 889 } else { 890 fem_addref(femsp); 891 fem_unlock(vp->v_femhead); 892 farg.fa_vnode.vp = vp; 893 farg.fa_fnode = femsp->feml_nodes + femsp->feml_tos; 894 vsop_find(&farg, &func, int, &arg0, vop_readdir, 895 femop_readdir); 896 errc = (*func)(arg0, uiop, cr, eofp, ct, flags); 897 fem_release(