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 2007 Sun Microsystems, Inc. All rights reserved. 27 * Use is subject to license terms. 28 */ 29 30 #pragma ident "%Z%%M% %I% %E% SMI" 31 32 /* 33 * Generic vnode operations. 34 */ 35 #include <sys/types.h> 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/errno.h> 39 #include <sys/fcntl.h> 40 #include <sys/flock.h> 41 #include <sys/statvfs.h> 42 #include <sys/vfs.h> 43 #include <sys/vnode.h> 44 #include <sys/proc.h> 45 #include <sys/user.h> 46 #include <sys/unistd.h> 47 #include <sys/cred.h> 48 #include <sys/poll.h> 49 #include <sys/debug.h> 50 #include <sys/cmn_err.h> 51 #include <sys/stream.h> 52 #include <fs/fs_subr.h> 53 #include <sys/acl.h> 54 #include <sys/share.h> 55 #include <sys/file.h> 56 #include <sys/kmem.h> 57 #include <sys/file.h> 58 #include <sys/nbmlock.h> 59 #include <acl/acl_common.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 * The associated operation is not supported by the file system. 70 */ 71 int 72 fs_nosys() 73 { 74 return (ENOSYS); 75 } 76 77 /* 78 * The associated operation is invalid (on this vnode). 79 */ 80 int 81 fs_inval() 82 { 83 return (EINVAL); 84 } 85 86 /* 87 * The associated operation is valid only for directories. 88 */ 89 int 90 fs_notdir() 91 { 92 return (ENOTDIR); 93 } 94 95 /* 96 * Free the file system specific resources. For the file systems that 97 * do not support the forced unmount, it will be a nop function. 98 */ 99 100 /*ARGSUSED*/ 101 void 102 fs_freevfs(vfs_t *vfsp) 103 { 104 } 105 106 /* ARGSUSED */ 107 int 108 fs_nosys_map(struct vnode *vp, 109 offset_t off, 110 struct as *as, 111 caddr_t *addrp, 112 size_t len, 113 uchar_t prot, 114 uchar_t maxprot, 115 uint_t flags, 116 struct cred *cr, 117 caller_context_t *ct) 118 { 119 return (ENOSYS); 120 } 121 122 /* ARGSUSED */ 123 int 124 fs_nosys_addmap(struct vnode *vp, 125 offset_t off, 126 struct as *as, 127 caddr_t addr, 128 size_t len, 129 uchar_t prot, 130 uchar_t maxprot, 131 uint_t flags, 132 struct cred *cr, 133 caller_context_t *ct) 134 { 135 return (ENOSYS); 136 } 137 138 /* ARGSUSED */ 139 int 140 fs_nosys_poll(vnode_t *vp, 141 register short events, 142 int anyyet, 143 register short *reventsp, 144 struct pollhead **phpp, 145 caller_context_t *ct) 146 { 147 return (ENOSYS); 148 } 149 150 151 /* 152 * The file system has nothing to sync to disk. However, the 153 * VFS_SYNC operation must not fail. 154 */ 155 /* ARGSUSED */ 156 int 157 fs_sync(struct vfs *vfspp, short flag, cred_t *cr) 158 { 159 return (0); 160 } 161 162 /* 163 * Does nothing but VOP_FSYNC must not fail. 164 */ 165 /* ARGSUSED */ 166 int 167 fs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct) 168 { 169 return (0); 170 } 171 172 /* 173 * Does nothing but VOP_PUTPAGE must not fail. 174 */ 175 /* ARGSUSED */ 176 int 177 fs_putpage(vnode_t *vp, offset_t off, size_t len, int flags, cred_t *cr, 178 caller_context_t *ctp) 179 { 180 return (0); 181 } 182 183 /* 184 * Does nothing but VOP_IOCTL must not fail. 185 */ 186 /* ARGSUSED */ 187 int 188 fs_ioctl(vnode_t *vp, int com, intptr_t data, int flag, cred_t *cred, 189 int *rvalp) 190 { 191 return (0); 192 } 193 194 /* 195 * Read/write lock/unlock. Does nothing. 196 */ 197 /* ARGSUSED */ 198 int 199 fs_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp) 200 { 201 return (-1); 202 } 203 204 /* ARGSUSED */ 205 void 206 fs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp) 207 { 208 } 209 210 /* 211 * Compare two vnodes. 212 */ 213 /*ARGSUSED2*/ 214 int 215 fs_cmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct) 216 { 217 return (vp1 == vp2); 218 } 219 220 /* 221 * No-op seek operation. 222 */ 223 /* ARGSUSED */ 224 int 225 fs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct) 226 { 227 return ((*noffp < 0 || *noffp > MAXOFFSET_T) ? EINVAL : 0); 228 } 229 230 /* 231 * File and record locking. 232 */ 233 /* ARGSUSED */ 234 int 235 fs_frlock(register vnode_t *vp, int cmd, struct flock64 *bfp, int flag, 236 offset_t offset, flk_callback_t *flk_cbp, cred_t *cr, 237 caller_context_t *ct) 238 { 239 int frcmd; 240 int nlmid; 241 int error = 0; 242 flk_callback_t serialize_callback; 243 int serialize = 0; 244 v_mode_t mode; 245 246 switch (cmd) { 247 248 case F_GETLK: 249 case F_O_GETLK: 250 if (flag & F_REMOTELOCK) { 251 frcmd = RCMDLCK; 252 } else if (flag & F_PXFSLOCK) { 253 frcmd = PCMDLCK; 254 } else { 255 frcmd = 0; 256 bfp->l_pid = ttoproc(curthread)->p_pid; 257 bfp->l_sysid = 0; 258 } 259 break; 260 261 case F_SETLK_NBMAND: 262 /* 263 * Are NBMAND locks allowed on this file? 264 */ 265 if (!vp->v_vfsp || 266 !(vp->v_vfsp->vfs_flag & VFS_NBMAND)) { 267 error = EINVAL; 268 goto done; 269 } 270 if (vp->v_type != VREG) { 271 error = EINVAL; 272 goto done; 273 } 274 /*FALLTHROUGH*/ 275 276 case F_SETLK: 277 if (flag & F_REMOTELOCK) { 278 frcmd = SETFLCK|RCMDLCK; 279 } else if (flag & F_PXFSLOCK) { 280 frcmd = SETFLCK|PCMDLCK; 281 } else { 282 frcmd = SETFLCK; 283 bfp->l_pid = ttoproc(curthread)->p_pid; 284 bfp->l_sysid = 0; 285 } 286 if (cmd == F_SETLK_NBMAND && 287 (bfp->l_type == F_RDLCK || bfp->l_type == F_WRLCK)) { 288 frcmd |= NBMLCK; 289 } 290 /* 291 * Check whether there is an NBMAND share reservation that 292 * conflicts with the lock request. 293 */ 294 if (nbl_need_check(vp)) { 295 nbl_start_crit(vp, RW_WRITER); 296 serialize = 1; 297 if (frcmd & NBMLCK) { 298 mode = (bfp->l_type == F_RDLCK) ? 299 V_READ : V_RDANDWR; 300 if (vn_is_mapped(vp, mode)) { 301 error = EAGAIN; 302 goto done; 303 } 304 } 305 if (share_blocks_lock(vp, bfp)) { 306 error = EAGAIN; 307 goto done; 308 } 309 } 310 break; 311 312 case F_SETLKW: 313 if (flag & F_REMOTELOCK) { 314 frcmd = SETFLCK|SLPFLCK|RCMDLCK; 315 } else if (flag & F_PXFSLOCK) { 316 frcmd = SETFLCK|SLPFLCK|PCMDLCK; 317 } else { 318 frcmd = SETFLCK|SLPFLCK; 319 bfp->l_pid = ttoproc(curthread)->p_pid; 320 bfp->l_sysid = 0; 321 } 322 /* 323 * If there is an NBMAND share reservation that conflicts 324 * with the lock request, block until the conflicting share 325 * reservation goes away. 326 */ 327 if (nbl_need_check(vp)) { 328 nbl_start_crit(vp, RW_WRITER); 329 serialize = 1; 330 if (share_blocks_lock(vp, bfp)) { 331 error = wait_for_share(vp, bfp); 332 if (error != 0) 333 goto done; 334 } 335 } 336 break; 337 338 case F_HASREMOTELOCKS: 339 nlmid = GETNLMID(bfp->l_sysid); 340 if (nlmid != 0) { /* booted as a cluster */ 341 l_has_rmt(bfp) = 342 cl_flk_has_remote_locks_for_nlmid(vp, nlmid); 343 } else { /* not booted as a cluster */ 344 l_has_rmt(bfp) = flk_has_remote_locks(vp); 345 } 346 347 goto done; 348 349 default: 350 error = EINVAL; 351 goto done; 352 } 353 354 /* 355 * If this is a blocking lock request and we're serializing lock 356 * requests, modify the callback list to leave the critical region 357 * while we're waiting for the lock. 358 */ 359 360 if (serialize && (frcmd & SLPFLCK) != 0) { 361 flk_add_callback(&serialize_callback, 362 frlock_serialize_blocked, vp, flk_cbp); 363 flk_cbp = &serialize_callback; 364 } 365 366 error = reclock(vp, bfp, frcmd, flag, offset, flk_cbp); 367 368 done: 369 if (serialize) 370 nbl_end_crit(vp); 371 372 return (error); 373 } 374 375 /* 376 * Callback when a lock request blocks and we are serializing requests. If 377 * before sleeping, leave the critical region. If after wakeup, reenter 378 * the critical region. 379 */ 380 381 static callb_cpr_t * 382 frlock_serialize_blocked(flk_cb_when_t when, void *infop) 383 { 384 vnode_t *vp = (vnode_t *)infop; 385 386 if (when == FLK_BEFORE_SLEEP) 387 nbl_end_crit(vp); 388 else { 389 nbl_start_crit(vp, RW_WRITER); 390 } 391 392 return (NULL); 393 } 394 395 /* 396 * Allow any flags. 397 */ 398 /* ARGSUSED */ 399 int 400 fs_setfl( 401 vnode_t *vp, 402 int oflags, 403 int nflags, 404 cred_t *cr, 405 caller_context_t *ct) 406 { 407 return (0); 408 } 409 410 /* 411 * Return the answer requested to poll() for non-device files. 412 * Only POLLIN, POLLRDNORM, and POLLOUT are recognized. 413 */ 414 struct pollhead fs_pollhd; 415 416 /* ARGSUSED */ 417 int 418 fs_poll(vnode_t *vp, 419 register short events, 420 int anyyet, 421 register short *reventsp, 422 struct pollhead **phpp, 423 caller_context_t *ct) 424 { 425 *reventsp = 0; 426 if (events & POLLIN) 427 *reventsp |= POLLIN; 428 if (events & POLLRDNORM) 429 *reventsp |= POLLRDNORM; 430 if (events & POLLRDBAND) 431 *reventsp |= POLLRDBAND; 432 if (events & POLLOUT) 433 *reventsp |= POLLOUT; 434 if (events & POLLWRBAND) 435 *reventsp |= POLLWRBAND; 436 *phpp = !anyyet && !*reventsp ? &fs_pollhd : (struct pollhead *)NULL; 437 return (0); 438 } 439 440 /* 441 * POSIX pathconf() support. 442 */ 443 /* ARGSUSED */ 444 int 445 fs_pathconf( 446 vnode_t *vp, 447 int cmd, 448 ulong_t *valp, 449 cred_t *cr, 450 caller_context_t *ct) 451 { 452 register ulong_t val; 453 register int error = 0; 454 struct statvfs64 vfsbuf; 455 456 switch (cmd) { 457 458 case _PC_LINK_MAX: 459 val = MAXLINK; 460 break; 461 462 case _PC_MAX_CANON: 463 val = MAX_CANON; 464 break; 465 466 case _PC_MAX_INPUT: 467 val = MAX_INPUT; 468 break; 469 470 case _PC_NAME_MAX: 471 bzero(&vfsbuf, sizeof (vfsbuf)); 472 if (error = VFS_STATVFS(vp->v_vfsp, &vfsbuf)) 473 break; 474 val = vfsbuf.f_namemax; 475 break; 476 477 case _PC_PATH_MAX: 478 case _PC_SYMLINK_MAX: 479 val = MAXPATHLEN; 480 break; 481 482 case _PC_PIPE_BUF: 483 val = PIPE_BUF; 484 break; 485 486 case _PC_NO_TRUNC: 487 if (vp->v_vfsp->vfs_flag & VFS_NOTRUNC) 488 val = 1; /* NOTRUNC is enabled for vp */ 489 else 490 val = (ulong_t)-1; 491 break; 492 493 case _PC_VDISABLE: 494 val = _POSIX_VDISABLE; 495 break; 496 497 case _PC_CHOWN_RESTRICTED: 498 if (rstchown) 499 val = rstchown; /* chown restricted enabled */ 500 else 501 val = (ulong_t)-1; 502 break; 503 504 case _PC_FILESIZEBITS: 505 506 /* 507 * If ever we come here it means that underlying file system 508 * does not recognise the command and therefore this 509 * configurable limit cannot be determined. We return -1 510 * and don't change errno. 511 */ 512 513 val = (ulong_t)-1; /* large file support */ 514 break; 515 516 case _PC_ACL_ENABLED: 517 val = 0; 518 break; 519 520 case _PC_CASE_BEHAVIOR: 521 val = _CASE_SENSITIVE; 522 if (vfs_has_feature(vp->v_vfsp, VFSFT_CASEINSENSITIVE) == 1) 523 val |= _CASE_INSENSITIVE; 524 if (vfs_has_feature(vp->v_vfsp, VFSFT_NOCASESENSITIVE) == 1) 525 val &= ~_CASE_SENSITIVE; 526 break; 527 528 case _PC_SATTR_ENABLED: 529 case _PC_SATTR_EXISTS: 530 val = 0; 531 break; 532 533 default: 534 error = EINVAL; 535 break; 536 } 537 538 if (error == 0) 539 *valp = val; 540 return (error); 541 } 542 543 /* 544 * Dispose of a page. 545 */ 546 /* ARGSUSED */ 547 void 548 fs_dispose( 549 struct vnode *vp, 550 page_t *pp, 551 int fl, 552 int dn, 553 struct cred *cr, 554 caller_context_t *ct) 555 { 556 557 ASSERT(fl == B_FREE || fl == B_INVAL); 558 559 if (fl == B_FREE) 560 page_free(pp, dn); 561 else 562 page_destroy(pp, dn); 563 } 564 565 /* ARGSUSED */ 566 void 567 fs_nodispose( 568 struct vnode *vp, 569 page_t *pp, 570 int fl, 571 int dn, 572 struct cred *cr, 573 caller_context_t *ct) 574 { 575 cmn_err(CE_PANIC, "fs_nodispose invoked"); 576 } 577 578 /* 579 * fabricate acls for file systems that do not support acls. 580 */ 581 /* ARGSUSED */ 582 int 583 fs_fab_acl( 584 vnode_t *vp, 585 vsecattr_t *vsecattr, 586 int flag, 587 cred_t *cr, 588 caller_context_t *ct) 589 { 590 aclent_t *aclentp; 591 ace_t *acep; 592 struct vattr vattr; 593 int error; 594 size_t aclsize; 595 596 vsecattr->vsa_aclcnt = 0; 597 vsecattr->vsa_aclentsz = 0; 598 vsecattr->vsa_aclentp = NULL; 599 vsecattr->vsa_dfaclcnt = 0; /* Default ACLs are not fabricated */ 600 vsecattr->vsa_dfaclentp = NULL; 601 602 vattr.va_mask = AT_MODE | AT_UID | AT_GID; 603 if (error = VOP_GETATTR(vp, &vattr, 0, cr, ct)) 604 return (error); 605 606 if (vsecattr->vsa_mask & (VSA_ACLCNT | VSA_ACL)) { 607 aclsize = 4 * sizeof (aclent_t); 608 vsecattr->vsa_aclcnt = 4; /* USER, GROUP, OTHER, and CLASS */ 609 vsecattr->vsa_aclentp = kmem_zalloc(aclsize, KM_SLEEP); 610 aclentp = vsecattr->vsa_aclentp; 611 612 aclentp->a_type = USER_OBJ; /* Owner */ 613 aclentp->a_perm = ((ushort_t)(vattr.va_mode & 0700)) >> 6; 614 aclentp->a_id = vattr.va_uid; /* Really undefined */ 615 aclentp++; 616 617 aclentp->a_type = GROUP_OBJ; /* Group */ 618 aclentp->a_perm = ((ushort_t)(vattr.va_mode & 0070)) >> 3; 619 aclentp->a_id = vattr.va_gid; /* Really undefined */ 620 aclentp++; 621 622 aclentp->a_type = OTHER_OBJ; /* Other */ 623 aclentp->a_perm = vattr.va_mode & 0007; 624 aclentp->a_id = (gid_t)-1; /* Really undefined */ 625 aclentp++; 626 627 aclentp->a_type = CLASS_OBJ; /* Class */ 628 aclentp->a_perm = (ushort_t)(0007); 629 aclentp->a_id = (gid_t)-1; /* Really undefined */ 630 } else if (vsecattr->vsa_mask & (VSA_ACECNT | VSA_ACE)) { 631 aclsize = 6 * sizeof (ace_t); 632 vsecattr->vsa_aclcnt = 6; 633 vsecattr->vsa_aclentp = kmem_zalloc(aclsize, KM_SLEEP); 634 vsecattr->vsa_aclentsz = aclsize; 635 acep = vsecattr->vsa_aclentp; 636 (void) memcpy(acep, trivial_acl, sizeof (ace_t) * 6); 637 adjust_ace_pair(acep, (vattr.va_mode & 0700) >> 6); 638 adjust_ace_pair(acep + 2, (vattr.va_mode & 0070) >> 3); 639 adjust_ace_pair(acep + 4, vattr.va_mode & 0007); 640 } 641 642 return (0); 643 } 644 645 /* 646 * Common code for implementing DOS share reservations 647 */ 648 /* ARGSUSED4 */ 649 int 650 fs_shrlock( 651 struct vnode *vp, 652 int cmd, 653 struct shrlock *shr, 654 int flag, 655 cred_t *cr, 656 caller_context_t *ct) 657 { 658 int error; 659 660 /* 661 * Make sure that the file was opened with permissions appropriate 662 * for the request, and make sure the caller isn't trying to sneak 663 * in an NBMAND request. 664 */ 665 if (cmd == F_SHARE) { 666 if (((shr->s_access & F_RDACC) && (flag & FREAD) == 0) || 667 ((shr->s_access & F_WRACC) && (flag & FWRITE) == 0)) 668 return (EBADF); 669 if (shr->s_access & (F_RMACC | F_MDACC)) 670 return (EINVAL); 671 if (shr->s_deny & (F_MANDDNY | F_RMDNY)) 672 return (EINVAL); 673 } 674 if (cmd == F_SHARE_NBMAND) { 675 /* make sure nbmand is allowed on the file */ 676 if (!vp->v_vfsp || 677 !(vp->v_vfsp->vfs_flag & VFS_NBMAND)) { 678 return (EINVAL); 679 } 680 if (vp->v_type != VREG) { 681 return (EINVAL); 682 } 683 } 684 685 nbl_start_crit(vp, RW_WRITER); 686 687 switch (cmd) { 688 689 case F_SHARE_NBMAND: 690 shr->s_deny |= F_MANDDNY; 691 /*FALLTHROUGH*/ 692 case F_SHARE: 693 error = add_share(vp, shr); 694 break; 695 696 case F_UNSHARE: 697 error = del_share(vp, shr); 698 break; 699 700 case F_HASREMOTELOCKS: 701 /* 702 * We are overloading this command to refer to remote 703 * shares as well as remote locks, despite its name. 704 */ 705 shr->s_access = shr_has_remote_shares(vp, shr->s_sysid); 706 error = 0; 707 break; 708 709 default: 710 error = EINVAL; 711 break; 712 } 713 714 nbl_end_crit(vp); 715 return (error); 716 } 717 718 /*ARGSUSED1*/ 719 int 720 fs_vnevent_nosupport(vnode_t *vp, vnevent_t e, vnode_t *dvp, char *fnm, 721 caller_context_t *ct) 722 { 723 ASSERT(vp != NULL); 724 return (ENOTSUP); 725 } 726 727 /*ARGSUSED1*/ 728 int 729 fs_vnevent_support(vnode_t *vp, vnevent_t e, vnode_t *dvp, char *fnm, 730 caller_context_t *ct) 731 { 732 ASSERT(vp != NULL); 733 return (0); 734 } 735 736 /* 737 * return 1 for non-trivial ACL. 738 * 739 * NB: It is not necessary for the caller to VOP_RWLOCK since 740 * we only issue VOP_GETSECATTR. 741 * 742 * Returns 0 == trivial 743 * 1 == NOT Trivial 744 * <0 could not determine. 745 */ 746 int 747 fs_acl_nontrivial(vnode_t *vp, cred_t *cr) 748 { 749 ulong_t acl_styles; 750 ulong_t acl_flavor; 751 vsecattr_t vsecattr; 752 int error; 753 int isnontrivial; 754 755 /* determine the forms of ACLs maintained */ 756 error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &acl_styles, cr, NULL); 757 758 /* clear bits we don't understand and establish default acl_style */ 759 acl_styles &= (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED); 760 if (error || (acl_styles == 0)) 761 acl_styles = _ACL_ACLENT_ENABLED; 762 763 vsecattr.vsa_aclentp = NULL; 764 vsecattr.vsa_dfaclentp = NULL; 765 vsecattr.vsa_aclcnt = 0; 766 vsecattr.vsa_dfaclcnt = 0; 767 768 while (acl_styles) { 769 /* select one of the styles as current flavor */ 770 acl_flavor = 0; 771 if (acl_styles & _ACL_ACLENT_ENABLED) { 772 acl_flavor = _ACL_ACLENT_ENABLED; 773 vsecattr.vsa_mask = VSA_ACLCNT | VSA_DFACLCNT; 774 } else if (acl_styles & _ACL_ACE_ENABLED) { 775 acl_flavor = _ACL_ACE_ENABLED; 776 vsecattr.vsa_mask = VSA_ACECNT | VSA_ACE; 777 } 778 779 ASSERT(vsecattr.vsa_mask && acl_flavor); 780 error = VOP_GETSECATTR(vp, &vsecattr, 0, cr, NULL); 781 if (error == 0) 782 break; 783 784 /* that flavor failed */ 785 acl_styles &= ~acl_flavor; 786 } 787 788 /* if all styles fail then assume trivial */ 789 if (acl_styles == 0) 790 return (0); 791 792 /* process the flavor that worked */ 793 isnontrivial = 0; 794 if (acl_flavor & _ACL_ACLENT_ENABLED) { 795 if (vsecattr.vsa_aclcnt > MIN_ACL_ENTRIES) 796 isnontrivial = 1; 797 if (vsecattr.vsa_aclcnt && vsecattr.vsa_aclentp != NULL) 798 kmem_free(vsecattr.vsa_aclentp, 799 vsecattr.vsa_aclcnt * sizeof (aclent_t)); 800 if (vsecattr.vsa_dfaclcnt && vsecattr.vsa_dfaclentp != NULL) 801 kmem_free(vsecattr.vsa_dfaclentp, 802 vsecattr.vsa_dfaclcnt * sizeof (aclent_t)); 803 } 804 if (acl_flavor & _ACL_ACE_ENABLED) { 805 806 isnontrivial = ace_trivial(vsecattr.vsa_aclentp, 807 vsecattr.vsa_aclcnt); 808 809 if (vsecattr.vsa_aclcnt && vsecattr.vsa_aclentp != NULL) 810 kmem_free(vsecattr.vsa_aclentp, 811 vsecattr.vsa_aclcnt * sizeof (ace_t)); 812 /* ACE has no vsecattr.vsa_dfaclcnt */ 813 } 814 return (isnontrivial); 815 } 816 817 /* 818 * Check whether we need a retry to recover from STALE error. 819 */ 820 int 821 fs_need_estale_retry(int retry_count) 822 { 823 if (retry_count < fs_estale_retry) 824 return (1); 825 else 826 return (0); 827 } 828 829 830 static int (*fs_av_scan)(vnode_t *, cred_t *, int) = NULL; 831 832 /* 833 * Routine for anti-virus scanner to call to register its scanning routine. 834 */ 835 void 836 fs_vscan_register(int (*av_scan)(vnode_t *, cred_t *, int)) 837 { 838 fs_av_scan = av_scan; 839 } 840 841 /* 842 * Routine for file systems to call to initiate anti-virus scanning. 843 * Scanning will only be done on REGular files (currently). 844 */ 845 int 846 fs_vscan(vnode_t *vp, cred_t *cr, int async) 847 { 848 int ret = 0; 849 850 if (fs_av_scan && vp->v_type == VREG) 851 ret = (*fs_av_scan)(vp, cr, async); 852 853 return (ret); 854 } 855