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 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 22 /* All Rights Reserved */ 23 24 25 /* 26 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. 27 */ 28 29 /* 30 * Generic vnode operations. 31 */ 32 #include <sys/types.h> 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/errno.h> 36 #include <sys/fcntl.h> 37 #include <sys/flock.h> 38 #include <sys/statvfs.h> 39 #include <sys/vfs.h> 40 #include <sys/vnode.h> 41 #include <sys/proc.h> 42 #include <sys/user.h> 43 #include <sys/unistd.h> 44 #include <sys/cred.h> 45 #include <sys/poll.h> 46 #include <sys/debug.h> 47 #include <sys/cmn_err.h> 48 #include <sys/stream.h> 49 #include <fs/fs_subr.h> 50 #include <fs/fs_reparse.h> 51 #include <sys/door.h> 52 #include <sys/acl.h> 53 #include <sys/share.h> 54 #include <sys/file.h> 55 #include <sys/kmem.h> 56 #include <sys/file.h> 57 #include <sys/nbmlock.h> 58 #include <acl/acl_common.h> 59 #include <sys/pathname.h> 60 61 static callb_cpr_t *frlock_serialize_blocked(flk_cb_when_t, void *); 62 63 /* 64 * Tunable to limit the number of retry to recover from STALE error. 65 */ 66 int fs_estale_retry = 5; 67 68 /* 69 * supports for reparse point door upcall 70 */ 71 static door_handle_t reparsed_door; 72 static kmutex_t reparsed_door_lock; 73 74 /* 75 * The associated operation is not supported by the file system. 76 */ 77 int 78 fs_nosys() 79 { 80 return (ENOSYS); 81 } 82 83 /* 84 * The associated operation is invalid (on this vnode). 85 */ 86 int 87 fs_inval() 88 { 89 return (EINVAL); 90 } 91 92 /* 93 * The associated operation is valid only for directories. 94 */ 95 int 96 fs_notdir() 97 { 98 return (ENOTDIR); 99 } 100 101 /* 102 * Free the file system specific resources. For the file systems that 103 * do not support the forced unmount, it will be a nop function. 104 */ 105 106 /*ARGSUSED*/ 107 void 108 fs_freevfs(vfs_t *vfsp) 109 { 110 } 111 112 /* ARGSUSED */ 113 int 114 fs_nosys_map(struct vnode *vp, 115 offset_t off, 116 struct as *as, 117 caddr_t *addrp, 118 size_t len, 119 uchar_t prot, 120 uchar_t maxprot, 121 uint_t flags, 122 struct cred *cr, 123 caller_context_t *ct) 124 { 125 return (ENOSYS); 126 } 127 128 /* ARGSUSED */ 129 int 130 fs_nosys_addmap(struct vnode *vp, 131 offset_t off, 132 struct as *as, 133 caddr_t addr, 134 size_t len, 135 uchar_t prot, 136 uchar_t maxprot, 137 uint_t flags, 138 struct cred *cr, 139 caller_context_t *ct) 140 { 141 return (ENOSYS); 142 } 143 144 /* ARGSUSED */ 145 int 146 fs_nosys_poll(vnode_t *vp, 147 register short events, 148 int anyyet, 149 register short *reventsp, 150 struct pollhead **phpp, 151 caller_context_t *ct) 152 { 153 return (ENOSYS); 154 } 155 156 157 /* 158 * The file system has nothing to sync to disk. However, the 159 * VFS_SYNC operation must not fail. 160 */ 161 /* ARGSUSED */ 162 int 163 fs_sync(struct vfs *vfspp, short flag, cred_t *cr) 164 { 165 return (0); 166 } 167 168 /* 169 * Does nothing but VOP_FSYNC must not fail. 170 */ 171 /* ARGSUSED */ 172 int 173 fs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct) 174 { 175 return (0); 176 } 177 178 /* 179 * Does nothing but VOP_PUTPAGE must not fail. 180 */ 181 /* ARGSUSED */ 182 int 183 fs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr, 184 caller_context_t *ctp) 185 { 186 return (0); 187 } 188 189 /* 190 * Does nothing but VOP_IOCTL must not fail. 191 */ 192 /* ARGSUSED */ 193 int 194 fs_ioctl(vnode_t *vp, int com, intptr_t data, int flag, cred_t *cred, 195 int *rvalp) 196 { 197 return (0); 198 } 199 200 /* 201 * Read/write lock/unlock. Does nothing. 202 */ 203 /* ARGSUSED */ 204 int 205 fs_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp) 206 { 207 return (-1); 208 } 209 210 /* ARGSUSED */ 211 void 212 fs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp) 213 { 214 } 215 216 /* 217 * Compare two vnodes. 218 */ 219 /*ARGSUSED2*/ 220 int 221 fs_cmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct) 222 { 223 return (vp1 == vp2); 224 } 225 226 /* 227 * No-op seek operation. 228 */ 229 /* ARGSUSED */ 230 int 231 fs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct) 232 { 233 return ((*noffp < 0 || *noffp > MAXOFFSET_T) ? EINVAL : 0); 234 } 235 236 /* 237 * File and record locking. 238 */ 239 /* ARGSUSED */ 240 int 241 fs_frlock(register vnode_t *vp, int cmd, struct flock64 *bfp, int flag, 242 offset_t offset, flk_callback_t *flk_cbp, cred_t *cr, 243 caller_context_t *ct) 244 { 245 int frcmd; 246 int nlmid; 247 int error = 0; 248 flk_callback_t serialize_callback; 249 int serialize = 0; 250 v_mode_t mode; 251 252 switch (cmd) { 253 254 case F_GETLK: 255 case F_O_GETLK: 256 if (flag & F_REMOTELOCK) { 257 frcmd = RCMDLCK; 258 } else if (flag & F_PXFSLOCK) { 259 frcmd = PCMDLCK; 260 } else { 261 frcmd = 0; 262 bfp->l_pid = ttoproc(curthread)->p_pid; 263 bfp->l_sysid = 0; 264 } 265 break; 266 267 case F_SETLK_NBMAND: 268 /* 269 * Are NBMAND locks allowed on this file? 270 */ 271 if (!vp->v_vfsp || 272 !(vp->v_vfsp->vfs_flag & VFS_NBMAND)) { 273 error = EINVAL; 274 goto done; 275 } 276 if (vp->v_type != VREG) { 277 error = EINVAL; 278 goto done; 279 } 280 /*FALLTHROUGH*/ 281 282 case F_SETLK: 283 if (flag & F_REMOTELOCK) { 284 frcmd = SETFLCK|RCMDLCK; 285 } else if (flag & F_PXFSLOCK) { 286 frcmd = SETFLCK|PCMDLCK; 287 } else { 288 frcmd = SETFLCK; 289 bfp->l_pid = ttoproc(curthread)->p_pid; 290 bfp->l_sysid = 0; 291 } 292 if (cmd == F_SETLK_NBMAND && 293 (bfp->l_type == F_RDLCK || bfp->l_type == F_WRLCK)) { 294 frcmd |= NBMLCK; 295 } 296 297 if (nbl_need_check(vp)) { 298 nbl_start_crit(vp, RW_WRITER); 299 serialize = 1; 300 if (frcmd & NBMLCK) { 301 mode = (bfp->l_type == F_RDLCK) ? 302 V_READ : V_RDANDWR; 303 if (vn_is_mapped(vp, mode)) { 304 error = EAGAIN; 305 goto done; 306 } 307 } 308 } 309 break; 310 311 case F_SETLKW: 312 if (flag & F_REMOTELOCK) { 313 frcmd = SETFLCK|SLPFLCK|RCMDLCK; 314 } else if (flag & F_PXFSLOCK) { 315 frcmd = SETFLCK|SLPFLCK|PCMDLCK; 316 } else { 317 frcmd = SETFLCK|SLPFLCK; 318 bfp->l_pid = ttoproc(curthread)->p_pid; 319 bfp->l_sysid = 0; 320 } 321 322 if (nbl_need_check(vp)) { 323 nbl_start_crit(vp, RW_WRITER); 324 serialize = 1; 325 } 326 break; 327 328 case F_HASREMOTELOCKS: 329 nlmid = GETNLMID(bfp->l_sysid); 330 if (nlmid != 0) { /* booted as a cluster */ 331 l_has_rmt(bfp) = 332 cl_flk_has_remote_locks_for_nlmid(vp, nlmid); 333 } else { /* not booted as a cluster */ 334 l_has_rmt(bfp) = flk_has_remote_locks(vp); 335 } 336 337 goto done; 338 339 default: 340 error = EINVAL; 341 goto done; 342 } 343 344 /* 345 * If this is a blocking lock request and we're serializing lock 346 * requests, modify the callback list to leave the critical region 347 * while we're waiting for the lock. 348 */ 349 350 if (serialize && (frcmd & SLPFLCK) != 0) { 351 flk_add_callback(&serialize_callback, 352 frlock_serialize_blocked, vp, flk_cbp); 353 flk_cbp = &serialize_callback; 354 } 355 356 error = reclock(vp, bfp, frcmd, flag, offset, flk_cbp); 357 358 done: 359 if (serialize) 360 nbl_end_crit(vp); 361 362 return (error); 363 } 364 365 /* 366 * Callback when a lock request blocks and we are serializing requests. If 367 * before sleeping, leave the critical region. If after wakeup, reenter 368 * the critical region. 369 */ 370 371 static callb_cpr_t * 372 frlock_serialize_blocked(flk_cb_when_t when, void *infop) 373 { 374 vnode_t *vp = (vnode_t *)infop; 375 376 if (when == FLK_BEFORE_SLEEP) 377 nbl_end_crit(vp); 378 else { 379 nbl_start_crit(vp, RW_WRITER); 380 } 381 382 return (NULL); 383 } 384 385 /* 386 * Allow any flags. 387 */ 388 /* ARGSUSED */ 389 int 390 fs_setfl( 391 vnode_t *vp, 392 int oflags, 393 int nflags, 394 cred_t *cr, 395 caller_context_t *ct) 396 { 397 return (0); 398 } 399 400 /* 401 * Return the answer requested to poll() for non-device files. 402 * Only POLLIN, POLLRDNORM, and POLLOUT are recognized. 403 */ 404 struct pollhead fs_pollhd; 405 406 /* ARGSUSED */ 407 int 408 fs_poll(vnode_t *vp, 409 register short events, 410 int anyyet, 411 register short *reventsp, 412 struct pollhead **phpp, 413 caller_context_t *ct) 414 { 415 *reventsp = 0; 416 if (events & POLLIN) 417 *reventsp |= POLLIN; 418 if (events & POLLRDNORM) 419 *reventsp |= POLLRDNORM; 420 if (events & POLLRDBAND) 421 *reventsp |= POLLRDBAND; 422 if (events & POLLOUT) 423 *reventsp |= POLLOUT; 424 if (events & POLLWRBAND) 425 *reventsp |= POLLWRBAND; 426 *phpp = !anyyet && !*reventsp ? &fs_pollhd : (struct pollhead *)NULL; 427 return (0); 428 } 429 430 /* 431 * POSIX pathconf() support. 432 */ 433 /* ARGSUSED */ 434 int 435 fs_pathconf( 436 vnode_t *vp, 437 int cmd, 438 ulong_t *valp, 439 cred_t *cr, 440 caller_context_t *ct) 441 { 442 register ulong_t val; 443 register int error = 0; 444 struct statvfs64 vfsbuf; 445 446 switch (cmd) { 447 448 case _PC_LINK_MAX: 449 val = MAXLINK; 450 break; 451 452 case _PC_MAX_CANON: 453 val = MAX_CANON; 454 break; 455 456 case _PC_MAX_INPUT: 457 val = MAX_INPUT; 458 break; 459 460 case _PC_NAME_MAX: 461 bzero(&vfsbuf, sizeof (vfsbuf)); 462 if (error = VFS_STATVFS(vp->v_vfsp, &vfsbuf)) 463 break; 464 val = vfsbuf.f_namemax; 465 break; 466 467 case _PC_PATH_MAX: 468 case _PC_SYMLINK_MAX: 469 val = MAXPATHLEN; 470 break; 471 472 case _PC_PIPE_BUF: 473 val = PIPE_BUF; 474 break; 475 476 case _PC_NO_TRUNC: 477 if (vp->v_vfsp->vfs_flag & VFS_NOTRUNC) 478 val = 1; /* NOTRUNC is enabled for vp */ 479 else 480 val = (ulong_t)-1; 481 break; 482 483 case _PC_VDISABLE: 484 val = _POSIX_VDISABLE; 485 break; 486 487 case _PC_CHOWN_RESTRICTED: 488 if (rstchown) 489 val = rstchown; /* chown restricted enabled */ 490 else 491 val = (ulong_t)-1; 492 break; 493 494 case _PC_FILESIZEBITS: 495 496 /* 497 * If ever we come here it means that underlying file system 498 * does not recognise the command and therefore this 499 * configurable limit cannot be determined. We return -1 500 * and don't change errno. 501 */ 502 503 val = (ulong_t)-1; /* large file support */ 504 break; 505 506 case _PC_ACL_ENABLED: 507 val = 0; 508 break; 509 510 case _PC_CASE_BEHAVIOR: 511 val = _CASE_SENSITIVE; 512 if (vfs_has_feature(vp->v_vfsp, VFSFT_CASEINSENSITIVE) == 1) 513 val |= _CASE_INSENSITIVE; 514 if (vfs_has_feature(vp->v_vfsp, VFSFT_NOCASESENSITIVE) == 1) 515 val &= ~_CASE_SENSITIVE; 516 break; 517 518 case _PC_SATTR_ENABLED: 519 case _PC_SATTR_EXISTS: 520 val = 0; 521 break; 522 523 case _PC_ACCESS_FILTERING: 524 val = 0; 525 break; 526 527 default: 528 error = EINVAL; 529 break; 530 } 531 532 if (error == 0) 533 *valp = val; 534 return (error); 535 } 536 537 /* 538 * Dispose of a page. 539 */ 540 /* ARGSUSED */ 541 void 542 fs_dispose( 543 struct vnode *vp, 544 page_t *pp, 545 int fl, 546 int dn, 547 struct cred *cr, 548 caller_context_t *ct) 549 { 550 551 ASSERT(fl == B_FREE || fl == B_INVAL); 552 553 if (fl == B_FREE) 554 page_free(pp, dn); 555 else 556 page_destroy(pp, dn); 557 } 558 559 /* ARGSUSED */ 560 void 561 fs_nodispose( 562 struct vnode *vp, 563 page_t *pp, 564 int fl, 565 int dn, 566 struct cred *cr, 567 caller_context_t *ct) 568 { 569 cmn_err(CE_PANIC, "fs_nodispose invoked"); 570 } 571 572 /* 573 * fabricate acls for file systems that do not support acls. 574 */ 575 /* ARGSUSED */ 576 int 577 fs_fab_acl( 578 vnode_t *vp, 579 vsecattr_t *vsecattr, 580 int flag, 581 cred_t *cr, 582 caller_context_t *ct) 583 { 584 aclent_t *aclentp; 585 struct vattr vattr; 586 int error; 587 size_t aclsize; 588 589 vsecattr->vsa_aclcnt = 0; 590 vsecattr->vsa_aclentsz = 0; 591 vsecattr->vsa_aclentp = NULL; 592 vsecattr->vsa_dfaclcnt = 0; /* Default ACLs are not fabricated */ 593 vsecattr->vsa_dfaclentp = NULL; 594 595 vattr.va_mask = AT_MODE | AT_UID | AT_GID; 596 if (error = VOP_GETATTR(vp, &vattr, 0, cr, ct)) 597 return (error); 598 599 if (vsecattr->vsa_mask & (VSA_ACLCNT | VSA_ACL)) { 600 aclsize = 4 * sizeof (aclent_t); 601 vsecattr->vsa_aclcnt = 4; /* USER, GROUP, OTHER, and CLASS */ 602 vsecattr->vsa_aclentp = kmem_zalloc(aclsize, KM_SLEEP); 603 aclentp = vsecattr->vsa_aclentp; 604 605 aclentp->a_type = USER_OBJ; /* Owner */ 606 aclentp->a_perm = ((ushort_t)(vattr.va_mode & 0700)) >> 6; 607 aclentp->a_id = vattr.va_uid; /* Really undefined */ 608 aclentp++; 609 610 aclentp->a_type = GROUP_OBJ; /* Group */ 611 aclentp->a_perm = ((ushort_t)(vattr.va_mode & 0070)) >> 3; 612 aclentp->a_id = vattr.va_gid; /* Really undefined */ 613 aclentp++; 614 615 aclentp->a_type = OTHER_OBJ; /* Other */ 616 aclentp->a_perm = vattr.va_mode & 0007; 617 aclentp->a_id = (gid_t)-1; /* Really undefined */ 618 aclentp++; 619 620 aclentp->a_type = CLASS_OBJ; /* Class */ 621 aclentp->a_perm = (ushort_t)(0007); 622 aclentp->a_id = (gid_t)-1; /* Really undefined */ 623 } else if (vsecattr->vsa_mask & (VSA_ACECNT | VSA_ACE)) { 624 VERIFY(0 == acl_trivial_create(vattr.va_mode, 625 (ace_t **)&vsecattr->vsa_aclentp, &vsecattr->vsa_aclcnt)); 626 vsecattr->vsa_aclentsz = vsecattr->vsa_aclcnt * sizeof (ace_t); 627 } 628 629 return (error); 630 } 631 632 /* 633 * Common code for implementing DOS share reservations 634 */ 635 /* ARGSUSED4 */ 636 int 637 fs_shrlock( 638 struct vnode *vp, 639 int cmd, 640 struct shrlock *shr, 641 int flag, 642 cred_t *cr, 643 caller_context_t *ct) 644 { 645 int error; 646 647 /* 648 * Make sure that the file was opened with permissions appropriate 649 * for the request, and make sure the caller isn't trying to sneak 650 * in an NBMAND request. 651 */ 652 if (cmd == F_SHARE) { 653 if (((shr->s_access & F_RDACC) && (flag & FREAD) == 0) || 654 ((shr->s_access & F_WRACC) && (flag & FWRITE) == 0)) 655 return (EBADF); 656 if (shr->s_access & (F_RMACC | F_MDACC)) 657 return (EINVAL); 658 if (shr->s_deny & (F_MANDDNY | F_RMDNY)) 659 return (EINVAL); 660 } 661 if (cmd == F_SHARE_NBMAND) { 662 /* make sure nbmand is allowed on the file */ 663 if (!vp->v_vfsp || 664 !(vp->v_vfsp->vfs_flag & VFS_NBMAND)) { 665 return (EINVAL); 666 } 667 if (vp->v_type != VREG) { 668 return (EINVAL); 669 } 670 } 671 672 nbl_start_crit(vp, RW_WRITER); 673 674 switch (cmd) { 675 676 case F_SHARE_NBMAND: 677 shr->s_deny |= F_MANDDNY; 678 /*FALLTHROUGH*/ 679 case F_SHARE: 680 error = add_share(vp, shr); 681 break; 682 683 case F_UNSHARE: 684 error = del_share(vp, shr); 685 break; 686 687 case F_HASREMOTELOCKS: 688 /* 689 * We are overloading this command to refer to remote 690 * shares as well as remote locks, despite its name. 691 */ 692 shr->s_access = shr_has_remote_shares(vp, shr->s_sysid); 693 error = 0; 694 break; 695 696 default: 697 error = EINVAL; 698 break; 699 } 700 701 nbl_end_crit(vp); 702 return (error); 703 } 704 705 /*ARGSUSED1*/ 706 int 707 fs_vnevent_nosupport(vnode_t *vp, vnevent_t e, vnode_t *dvp, char *fnm, 708 caller_context_t *ct) 709 { 710 ASSERT(vp != NULL); 711 return (ENOTSUP); 712 } 713 714 /*ARGSUSED1*/ 715 int 716 fs_vnevent_support(vnode_t *vp, vnevent_t e, vnode_t *dvp, char *fnm, 717 caller_context_t *ct) 718 { 719 ASSERT(vp != NULL); 720 return (0); 721 } 722 723 /* 724 * return 1 for non-trivial ACL. 725 * 726 * NB: It is not necessary for the caller to VOP_RWLOCK since 727 * we only issue VOP_GETSECATTR. 728 * 729 * Returns 0 == trivial 730 * 1 == NOT Trivial 731 * <0 could not determine. 732 */ 733 int 734 fs_acl_nontrivial(vnode_t *vp, cred_t *cr) 735 { 736 ulong_t acl_styles; 737 ulong_t acl_flavor; 738 vsecattr_t vsecattr; 739 int error; 740 int isnontrivial; 741 742 /* determine the forms of ACLs maintained */ 743 error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &acl_styles, cr, NULL); 744 745 /* clear bits we don't understand and establish default acl_style */ 746 acl_styles &= (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED); 747 if (error || (acl_styles == 0)) 748 acl_styles = _ACL_ACLENT_ENABLED; 749 750 vsecattr.vsa_aclentp = NULL; 751 vsecattr.vsa_dfaclentp = NULL; 752 vsecattr.vsa_aclcnt = 0; 753 vsecattr.vsa_dfaclcnt = 0; 754 755 while (acl_styles) { 756 /* select one of the styles as current flavor */ 757 acl_flavor = 0; 758 if (acl_styles & _ACL_ACLENT_ENABLED) { 759 acl_flavor = _ACL_ACLENT_ENABLED; 760 vsecattr.vsa_mask = VSA_ACLCNT | VSA_DFACLCNT; 761 } else if (acl_styles & _ACL_ACE_ENABLED) { 762 acl_flavor = _ACL_ACE_ENABLED; 763 vsecattr.vsa_mask = VSA_ACECNT | VSA_ACE; 764 } 765 766 ASSERT(vsecattr.vsa_mask && acl_flavor); 767 error = VOP_GETSECATTR(vp, &vsecattr, 0, cr, NULL); 768 if (error == 0) 769 break; 770 771 /* that flavor failed */ 772 acl_styles &= ~acl_flavor; 773 } 774 775 /* if all styles fail then assume trivial */ 776 if (acl_styles == 0) 777 return (0); 778 779 /* process the flavor that worked */ 780 isnontrivial = 0; 781 if (acl_flavor & _ACL_ACLENT_ENABLED) { 782 if (vsecattr.vsa_aclcnt > MIN_ACL_ENTRIES) 783 isnontrivial = 1; 784 if (vsecattr.vsa_aclcnt && vsecattr.vsa_aclentp != NULL) 785 kmem_free(vsecattr.vsa_aclentp, 786 vsecattr.vsa_aclcnt * sizeof (aclent_t)); 787 if (vsecattr.vsa_dfaclcnt && vsecattr.vsa_dfaclentp != NULL) 788 kmem_free(vsecattr.vsa_dfaclentp, 789 vsecattr.vsa_dfaclcnt * sizeof (aclent_t)); 790 } 791 if (acl_flavor & _ACL_ACE_ENABLED) { 792 isnontrivial = ace_trivial(vsecattr.vsa_aclentp, 793 vsecattr.vsa_aclcnt); 794 795 if (vsecattr.vsa_aclcnt && vsecattr.vsa_aclentp != NULL) 796 kmem_free(vsecattr.vsa_aclentp, 797 vsecattr.vsa_aclcnt * sizeof (ace_t)); 798 /* ACE has no vsecattr.vsa_dfaclcnt */ 799 } 800 return (isnontrivial); 801 } 802 803 /* 804 * Check whether we need a retry to recover from STALE error. 805 */ 806 int 807 fs_need_estale_retry(int retry_count) 808 { 809 if (retry_count < fs_estale_retry) 810 return (1); 811 else 812 return (0); 813 } 814 815 816 static int (*fs_av_scan)(vnode_t *, cred_t *, int) = NULL; 817 818 /* 819 * Routine for anti-virus scanner to call to register its scanning routine. 820 */ 821 void 822 fs_vscan_register(int (*av_scan)(vnode_t *, cred_t *, int)) 823 { 824 fs_av_scan = av_scan; 825 } 826 827 /* 828 * Routine for file systems to call to initiate anti-virus scanning. 829 * Scanning will only be done on REGular files (currently). 830 */ 831 int 832 fs_vscan(vnode_t *vp, cred_t *cr, int async) 833 { 834 int ret = 0; 835 836 if (fs_av_scan && vp->v_type == VREG) 837 ret = (*fs_av_scan)(vp, cr, async); 838 839 return (ret); 840 } 841 842 /* 843 * support functions for reparse point 844 */ 845 /* 846 * reparse_vnode_parse 847 * 848 * Read the symlink data of a reparse point specified by the vnode 849 * and return the reparse data as name-value pair in the nvlist. 850 */ 851 int 852 reparse_vnode_parse(vnode_t *vp, nvlist_t *nvl) 853 { 854 int err; 855 char *lkdata; 856 struct uio uio; 857 struct iovec iov; 858 859 if (vp == NULL || nvl == NULL) 860 return (EINVAL); 861 862 lkdata = kmem_alloc(MAXREPARSELEN, KM_SLEEP); 863 864 /* 865 * Set up io vector to read sym link data 866 */ 867 iov.iov_base = lkdata; 868 iov.iov_len = MAXREPARSELEN; 869 uio.uio_iov = &iov; 870 uio.uio_iovcnt = 1; 871 uio.uio_segflg = UIO_SYSSPACE; 872 uio.uio_extflg = UIO_COPY_CACHED; 873 uio.uio_loffset = (offset_t)0; 874 uio.uio_resid = MAXREPARSELEN; 875 876 if ((err = VOP_READLINK(vp, &uio, kcred, NULL)) == 0) { 877 *(lkdata + MAXREPARSELEN - uio.uio_resid) = '\0'; 878 err = reparse_parse(lkdata, nvl); 879 } 880 kmem_free(lkdata, MAXREPARSELEN); /* done with lkdata */ 881 882 return (err); 883 } 884 885 void 886 reparse_point_init() 887 { 888 mutex_init(&reparsed_door_lock, NULL, MUTEX_DEFAULT, NULL); 889 } 890 891 static door_handle_t 892 reparse_door_get_handle() 893 { 894 door_handle_t dh; 895 896 mutex_enter(&reparsed_door_lock); 897 if ((dh = reparsed_door) == NULL) { 898 if (door_ki_open(REPARSED_DOOR, &reparsed_door) != 0) { 899 reparsed_door = NULL; 900 dh = NULL; 901 } else 902 dh = reparsed_door; 903 } 904 mutex_exit(&reparsed_door_lock); 905 return (dh); 906 } 907 908 static void 909 reparse_door_reset_handle() 910 { 911 mutex_enter(&reparsed_door_lock); 912 reparsed_door = NULL; 913 mutex_exit(&reparsed_door_lock); 914 } 915 916 /* 917 * reparse_kderef 918 * 919 * Accepts the service-specific item from the reparse point and returns 920 * the service-specific data requested. The caller specifies the size of 921 * the buffer provided via *bufsz; the routine will fail with EOVERFLOW 922 * if the results will not fit in the buffer, in which case, *bufsz will 923 * contain the number of bytes needed to hold the results. 924 * 925 * if ok return 0 and update *bufsize with length of actual result 926 * else return error code. 927 */ 928 int 929 reparse_kderef(const char *svc_type, const char *svc_data, char *buf, 930 size_t *bufsize) 931 { 932 int err, retries, need_free, retried_doorhd; 933 size_t dlen, res_len; 934 char *darg; 935 door_arg_t door_args; 936 reparsed_door_res_t *resp; 937 door_handle_t rp_door; 938 939 if (svc_type == NULL || svc_data == NULL || buf == NULL || 940 bufsize == NULL) 941 return (EINVAL); 942 943 /* get reparsed's door handle */ 944 if ((rp_door = reparse_door_get_handle()) == NULL) 945 return (EBADF); 946 947 /* setup buffer for door_call args and results */ 948 dlen = strlen(svc_type) + strlen(svc_data) + 2; 949 if (*bufsize < dlen) { 950 darg = kmem_alloc(dlen, KM_SLEEP); 951 need_free = 1; 952 } else { 953 darg = buf; /* use same buffer for door's args & results */ 954 need_free = 0; 955 } 956 957 /* build argument string of door call */ 958 (void) snprintf(darg, dlen, "%s:%s", svc_type, svc_data); 959 960 /* setup args for door call */ 961 door_args.data_ptr = darg; 962 door_args.data_size = dlen; 963 door_args.desc_ptr = NULL; 964 door_args.desc_num = 0; 965 door_args.rbuf = buf; 966 door_args.rsize = *bufsize; 967 968 /* do the door_call */ 969 retried_doorhd = 0; 970 retries = 0; 971 door_ki_hold(rp_door); 972 while ((err = door_ki_upcall_limited(rp_door, &door_args, 973 NULL, SIZE_MAX, 0)) != 0) { 974 if (err == EAGAIN || err == EINTR) { 975 if (++retries < REPARSED_DOORCALL_MAX_RETRY) { 976 delay(SEC_TO_TICK(1)); 977 continue; 978 } 979 } else if (err == EBADF) { 980 /* door server goes away... */ 981 reparse_door_reset_handle(); 982 983 if (retried_doorhd == 0) { 984 door_ki_rele(rp_door); 985 retried_doorhd++; 986 rp_door = reparse_door_get_handle(); 987 if (rp_door != NULL) { 988 door_ki_hold(rp_door); 989 continue; 990 } 991 } 992 } 993 break; 994 } 995 996 if (rp_door) 997 door_ki_rele(rp_door); 998 999 if (need_free) 1000 kmem_free(darg, dlen); /* done with args buffer */ 1001 1002 if (err != 0) 1003 return (err); 1004 1005 resp = (reparsed_door_res_t *)door_args.rbuf; 1006 if ((err = resp->res_status) == 0) { 1007 /* 1008 * have to save the length of the results before the 1009 * bcopy below since it's can be an overlap copy that 1010 * overwrites the reparsed_door_res_t structure at 1011 * the beginning of the buffer. 1012 */ 1013 res_len = (size_t)resp->res_len; 1014 1015 /* deref call is ok */ 1016 if (res_len > *bufsize) 1017 err = EOVERFLOW; 1018 else 1019 bcopy(resp->res_data, buf, res_len); 1020 *bufsize = res_len; 1021 } 1022 if (door_args.rbuf != buf) 1023 kmem_free(door_args.rbuf, door_args.rsize); 1024 1025 return (err); 1026 } 1027