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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/param.h> 30 #include <sys/types.h> 31 #include <sys/systm.h> 32 #include <sys/cred.h> 33 #include <sys/proc.h> 34 #include <sys/user.h> 35 #include <sys/time.h> 36 #include <sys/vnode.h> 37 #include <sys/vfs.h> 38 #include <sys/file.h> 39 #include <sys/uio.h> 40 #include <sys/buf.h> 41 #include <sys/mman.h> 42 #include <sys/tiuser.h> 43 #include <sys/pathname.h> 44 #include <sys/dirent.h> 45 #include <sys/conf.h> 46 #include <sys/debug.h> 47 #include <sys/unistd.h> 48 #include <sys/vmsystm.h> 49 #include <sys/fcntl.h> 50 #include <sys/flock.h> 51 #include <sys/swap.h> 52 #include <sys/errno.h> 53 #include <sys/sysmacros.h> 54 #include <sys/disp.h> 55 #include <sys/kmem.h> 56 #include <sys/cmn_err.h> 57 #include <sys/vtrace.h> 58 #include <sys/pathconf.h> 59 #include <sys/dnlc.h> 60 #include <sys/acl.h> 61 62 #include <rpc/types.h> 63 #include <rpc/auth.h> 64 #include <rpc/clnt.h> 65 #include <rpc/xdr.h> 66 #include <nfs/nfs.h> 67 #include <nfs/nfs_clnt.h> 68 #include <nfs/rnode.h> 69 #include <nfs/nfs_acl.h> 70 71 #include <vm/hat.h> 72 #include <vm/as.h> 73 #include <vm/page.h> 74 #include <vm/pvn.h> 75 #include <vm/seg.h> 76 #include <vm/seg_map.h> 77 #include <vm/seg_kmem.h> 78 #include <vm/seg_vn.h> 79 #include <vm/rm.h> 80 81 #include <fs/fs_subr.h> 82 83 /* 84 * The order and contents of this structure must be kept in sync with that of 85 * aclreqcnt_v2_tmpl in nfs_stats.c 86 */ 87 char *aclnames_v2[] = { 88 "null", "getacl", "setacl", "getattr", "access", "getxattrdir" 89 }; 90 91 /* 92 * This table maps from NFS protocol number into call type. 93 * Zero means a "Lookup" type call 94 * One means a "Read" type call 95 * Two means a "Write" type call 96 * This is used to select a default time-out. 97 */ 98 uchar_t acl_call_type_v2[] = { 99 0, 0, 1, 0, 0, 0 100 }; 101 102 /* 103 * Similar table, but to determine which timer to use 104 * (only real reads and writes!) 105 */ 106 uchar_t acl_timer_type_v2[] = { 107 0, 0, 0, 0, 0, 0 108 }; 109 110 /* 111 * This table maps from acl operation into a call type 112 * for the semisoft mount option. 113 * Zero means do not repeat operation. 114 * One means repeat. 115 */ 116 uchar_t acl_ss_call_type_v2[] = { 117 0, 0, 1, 0, 0, 0 118 }; 119 120 static int nfs_acl_dup_cache(vsecattr_t *, vsecattr_t *); 121 static void nfs_acl_dup_res(rnode_t *, vsecattr_t *); 122 123 /* ARGSUSED */ 124 int 125 acl_getacl2(vnode_t *vp, vsecattr_t *vsp, int flag, cred_t *cr) 126 { 127 int error; 128 GETACL2args args; 129 GETACL2res res; 130 int doqueue; 131 vattr_t va; 132 rnode_t *rp; 133 failinfo_t fi; 134 hrtime_t t; 135 136 rp = VTOR(vp); 137 if (rp->r_secattr != NULL) { 138 error = nfs_validate_caches(vp, cr); 139 if (error) 140 return (error); 141 mutex_enter(&rp->r_statelock); 142 if (rp->r_secattr != NULL) { 143 if (nfs_acl_dup_cache(vsp, rp->r_secattr)) { 144 mutex_exit(&rp->r_statelock); 145 return (0); 146 } 147 } 148 mutex_exit(&rp->r_statelock); 149 } 150 151 args.mask = vsp->vsa_mask; 152 args.fh = *VTOFH(vp); 153 fi.vp = vp; 154 fi.fhp = (caddr_t)&args.fh; 155 fi.copyproc = nfscopyfh; 156 fi.lookupproc = nfslookup; 157 fi.xattrdirproc = acl_getxattrdir2; 158 159 res.resok.acl.vsa_aclentp = NULL; 160 res.resok.acl.vsa_dfaclentp = NULL; 161 162 doqueue = 1; 163 164 t = gethrtime(); 165 166 error = acl2call(VTOMI(vp), ACLPROC2_GETACL, 167 xdr_GETACL2args, (caddr_t)&args, 168 xdr_GETACL2res, (caddr_t)&res, cr, 169 &doqueue, &res.status, 0, &fi); 170 171 if (error) 172 return (error); 173 174 error = geterrno(res.status); 175 if (!error) { 176 (void) nfs_cache_fattr(vp, &res.resok.attr, &va, t, cr); 177 nfs_acl_dup_res(rp, &res.resok.acl); 178 *vsp = res.resok.acl; 179 } else { 180 PURGE_STALE_FH(error, vp, cr); 181 } 182 183 return (error); 184 } 185 186 /* ARGSUSED */ 187 int 188 acl_setacl2(vnode_t *vp, vsecattr_t *vsp, int flag, cred_t *cr) 189 { 190 int error; 191 SETACL2args args; 192 SETACL2res res; 193 int doqueue; 194 vattr_t va; 195 rnode_t *rp; 196 hrtime_t t; 197 198 args.fh = *VTOFH(vp); 199 args.acl = *vsp; 200 201 doqueue = 1; 202 203 t = gethrtime(); 204 205 error = acl2call(VTOMI(vp), ACLPROC2_SETACL, 206 xdr_SETACL2args, (caddr_t)&args, 207 xdr_SETACL2res, (caddr_t)&res, cr, 208 &doqueue, &res.status, 0, NULL); 209 210 /* 211 * On success, adding the arguments to setsecattr into the cache have 212 * not proven adequate. On error, we cannot depend on cache. 213 * Simply flush the cache to force the next getsecattr 214 * to go over the wire. 215 */ 216 rp = VTOR(vp); 217 mutex_enter(&rp->r_statelock); 218 if (rp->r_secattr != NULL) { 219 nfs_acl_free(rp->r_secattr); 220 rp->r_secattr = NULL; 221 } 222 mutex_exit(&rp->r_statelock); 223 224 if (error) 225 return (error); 226 227 error = geterrno(res.status); 228 if (!error) { 229 (void) nfs_cache_fattr(vp, &res.resok.attr, &va, t, cr); 230 } else { 231 PURGE_STALE_FH(error, vp, cr); 232 } 233 234 return (error); 235 } 236 237 int 238 acl_getattr2_otw(vnode_t *vp, vattr_t *vap, cred_t *cr) 239 { 240 int error; 241 GETATTR2args args; 242 GETATTR2res res; 243 int doqueue; 244 failinfo_t fi; 245 hrtime_t t; 246 247 args.fh = *VTOFH(vp); 248 fi.vp = vp; 249 fi.fhp = (caddr_t)&args.fh; 250 fi.copyproc = nfscopyfh; 251 fi.lookupproc = nfslookup; 252 fi.xattrdirproc = acl_getxattrdir2; 253 254 doqueue = 1; 255 256 t = gethrtime(); 257 258 error = acl2call(VTOMI(vp), ACLPROC2_GETATTR, 259 xdr_GETATTR2args, (caddr_t)&args, 260 xdr_GETATTR2res, (caddr_t)&res, cr, 261 &doqueue, &res.status, 0, &fi); 262 263 if (error) 264 return (error); 265 error = geterrno(res.status); 266 267 if (!error) { 268 error = nfs_cache_fattr(vp, &res.resok.attr, vap, t, cr); 269 } else { 270 PURGE_STALE_FH(error, vp, cr); 271 } 272 273 return (error); 274 } 275 276 /* ARGSUSED */ 277 int 278 acl_access2(vnode_t *vp, int mode, int flags, cred_t *cr) 279 { 280 int error; 281 ACCESS2args args; 282 ACCESS2res res; 283 int doqueue; 284 uint32 acc; 285 rnode_t *rp; 286 cred_t *cred, *ncr; 287 vattr_t va; 288 failinfo_t fi; 289 nfs_access_type_t cacc; 290 hrtime_t t; 291 292 acc = 0; 293 if (mode & VREAD) 294 acc |= ACCESS2_READ; 295 if (mode & VWRITE) { 296 if (vn_is_readonly(vp) && !IS_DEVVP(vp)) 297 return (EROFS); 298 if (vp->v_type == VDIR) 299 acc |= ACCESS2_DELETE; 300 acc |= ACCESS2_MODIFY | ACCESS2_EXTEND; 301 } 302 if (mode & VEXEC) { 303 if (vp->v_type == VDIR) 304 acc |= ACCESS2_LOOKUP; 305 else 306 acc |= ACCESS2_EXECUTE; 307 } 308 309 rp = VTOR(vp); 310 if (vp->v_type == VDIR) { 311 args.access = ACCESS2_READ | ACCESS2_DELETE | ACCESS2_MODIFY | 312 ACCESS2_EXTEND | ACCESS2_LOOKUP; 313 } else { 314 args.access = ACCESS2_READ | ACCESS2_MODIFY | ACCESS2_EXTEND | 315 ACCESS2_EXECUTE; 316 } 317 args.fh = *VTOFH(vp); 318 fi.vp = vp; 319 fi.fhp = (caddr_t)&args.fh; 320 fi.copyproc = nfscopyfh; 321 fi.lookupproc = nfslookup; 322 fi.xattrdirproc = acl_getxattrdir2; 323 324 cred = cr; 325 ncr = crnetadjust(cred); 326 327 tryagain: 328 if (rp->r_acache != NULL) { 329 cacc = nfs_access_check(rp, acc, cr); 330 if (cacc == NFS_ACCESS_ALLOWED) 331 return (0); 332 if (cacc == NFS_ACCESS_DENIED) { 333 /* 334 * If the cred can be adjusted, try again 335 * with the new cred. 336 */ 337 if (ncr != NULL) { 338 cred = ncr; 339 ncr = NULL; 340 goto tryagain; 341 } 342 return (EACCES); 343 } 344 } 345 346 doqueue = 1; 347 348 t = gethrtime(); 349 350 error = acl2call(VTOMI(vp), ACLPROC2_ACCESS, 351 xdr_ACCESS2args, (caddr_t)&args, 352 xdr_ACCESS2res, (caddr_t)&res, cred, 353 &doqueue, &res.status, 0, &fi); 354 355 if (error) { 356 if (cred != cr) 357 crfree(cred); 358 return (error); 359 } 360 361 error = geterrno(res.status); 362 if (!error) { 363 (void) nfs_cache_fattr(vp, &res.resok.attr, &va, t, cr); 364 nfs_access_cache(rp, args.access, res.resok.access, cred); 365 if ((acc & res.resok.access) != acc) { 366 /* 367 * If the cred can be adjusted, try again 368 * with the new cred. 369 */ 370 if (ncr != NULL) { 371 cred = ncr; 372 ncr = NULL; 373 goto tryagain; 374 } 375 error = EACCES; 376 } 377 } else { 378 PURGE_STALE_FH(error, vp, cr); 379 } 380 381 if (cred != cr) 382 crfree(cred); 383 384 return (error); 385 } 386 387 static int xattr_lookup_neg_cache = 1; 388 389 /* 390 * Look up a hidden attribute directory over the wire; the vnode 391 * we start with could be a file or directory. We have to be 392 * tricky in recording the name in the rnode r_path - we use the 393 * magic name XATTR_RPATH and rely on code in failover_lookup() to 394 * detect this and use this routine to do the same lookup on 395 * remapping. DNLC is easier: slashes are legal, so we use 396 * XATTR_DIR_NAME as UFS does. 397 */ 398 int 399 acl_getxattrdir2(vnode_t *vp, vnode_t **vpp, bool_t create, cred_t *cr, 400 int rfscall_flags) 401 { 402 int error; 403 GETXATTRDIR2args args; 404 GETXATTRDIR2res res; 405 int doqueue; 406 failinfo_t fi; 407 hrtime_t t; 408 409 args.fh = *VTOFH(vp); 410 args.create = create; 411 412 fi.vp = vp; 413 fi.fhp = NULL; /* no need to update, filehandle not copied */ 414 fi.copyproc = nfscopyfh; 415 fi.lookupproc = nfslookup; 416 fi.xattrdirproc = acl_getxattrdir2; 417 418 doqueue = 1; 419 420 t = gethrtime(); 421 422 error = acl2call(VTOMI(vp), ACLPROC2_GETXATTRDIR, 423 xdr_GETXATTRDIR2args, (caddr_t)&args, 424 xdr_GETXATTRDIR2res, (caddr_t)&res, cr, 425 &doqueue, &res.status, rfscall_flags, &fi); 426 427 if (!error) { 428 error = geterrno(res.status); 429 if (!error) { 430 *vpp = makenfsnode(&res.resok.fh, &res.resok.attr, 431 vp->v_vfsp, t, cr, VTOR(vp)->r_path, XATTR_RPATH); 432 mutex_enter(&(*vpp)->v_lock); 433 (*vpp)->v_flag |= V_XATTRDIR; 434 mutex_exit(&(*vpp)->v_lock); 435 if (!(rfscall_flags & RFSCALL_SOFT)) 436 dnlc_update(vp, XATTR_DIR_NAME, *vpp); 437 } else { 438 PURGE_STALE_FH(error, vp, cr); 439 if (error == ENOENT && xattr_lookup_neg_cache) 440 dnlc_enter(vp, XATTR_DIR_NAME, DNLC_NO_VNODE); 441 } 442 } 443 return (error); 444 } 445 446 /* 447 * The order and contents of this structure must be kept in sync with that of 448 * aclreqcnt_v3_tmpl in nfs_stats.c 449 */ 450 char *aclnames_v3[] = { 451 "null", "getacl", "setacl", "getxattrdir" 452 }; 453 454 /* 455 * This table maps from NFS protocol number into call type. 456 * Zero means a "Lookup" type call 457 * One means a "Read" type call 458 * Two means a "Write" type call 459 * This is used to select a default time-out. 460 */ 461 uchar_t acl_call_type_v3[] = { 462 0, 0, 1, 0 463 }; 464 465 /* 466 * This table maps from acl operation into a call type 467 * for the semisoft mount option. 468 * Zero means do not repeat operation. 469 * One means repeat. 470 */ 471 uchar_t acl_ss_call_type_v3[] = { 472 0, 0, 1, 0 473 }; 474 475 /* 476 * Similar table, but to determine which timer to use 477 * (only real reads and writes!) 478 */ 479 uchar_t acl_timer_type_v3[] = { 480 0, 0, 0, 0 481 }; 482 483 /* ARGSUSED */ 484 int 485 acl_getacl3(vnode_t *vp, vsecattr_t *vsp, int flag, cred_t *cr) 486 { 487 int error; 488 GETACL3args args; 489 GETACL3res res; 490 int doqueue; 491 rnode_t *rp; 492 failinfo_t fi; 493 hrtime_t t; 494 495 rp = VTOR(vp); 496 if (rp->r_secattr != NULL) { 497 error = nfs3_validate_caches(vp, cr); 498 if (error) 499 return (error); 500 mutex_enter(&rp->r_statelock); 501 if (rp->r_secattr != NULL) { 502 if (nfs_acl_dup_cache(vsp, rp->r_secattr)) { 503 mutex_exit(&rp->r_statelock); 504 return (0); 505 } 506 } 507 mutex_exit(&rp->r_statelock); 508 } 509 510 args.mask = vsp->vsa_mask; 511 args.fh = *VTOFH3(vp); 512 fi.vp = vp; 513 fi.fhp = (caddr_t)&args.fh; 514 fi.copyproc = nfs3copyfh; 515 fi.lookupproc = nfs3lookup; 516 fi.xattrdirproc = acl_getxattrdir3; 517 518 res.resok.acl.vsa_aclentp = NULL; 519 res.resok.acl.vsa_dfaclentp = NULL; 520 521 doqueue = 1; 522 523 t = gethrtime(); 524 525 error = acl3call(VTOMI(vp), ACLPROC3_GETACL, 526 xdr_GETACL3args, (caddr_t)&args, 527 xdr_GETACL3res, (caddr_t)&res, cr, 528 &doqueue, &res.status, 0, &fi); 529 530 if (error) 531 return (error); 532 533 error = geterrno3(res.status); 534 535 if (!error) { 536 nfs3_cache_post_op_attr(vp, &res.resok.attr, t, cr); 537 nfs_acl_dup_res(rp, &res.resok.acl); 538 *vsp = res.resok.acl; 539 } else { 540 nfs3_cache_post_op_attr(vp, &res.resfail.attr, t, cr); 541 PURGE_STALE_FH(error, vp, cr); 542 } 543 544 return (error); 545 } 546 547 /* ARGSUSED */ 548 int 549 acl_setacl3(vnode_t *vp, vsecattr_t *vsp, int flag, cred_t *cr) 550 { 551 int error; 552 SETACL3args args; 553 SETACL3res res; 554 rnode_t *rp; 555 int doqueue; 556 hrtime_t t; 557 558 args.fh = *VTOFH3(vp); 559 args.acl = *vsp; 560 561 doqueue = 1; 562 563 t = gethrtime(); 564 565 error = acl3call(VTOMI(vp), ACLPROC3_SETACL, 566 xdr_SETACL3args, (caddr_t)&args, 567 xdr_SETACL3res, (caddr_t)&res, cr, 568 &doqueue, &res.status, 0, NULL); 569 570 /* 571 * On success, adding the arguments to setsecattr into the cache have 572 * not proven adequate. On error, we cannot depend on cache. 573 * Simply flush the cache to force the next getsecattr 574 * to go over the wire. 575 */ 576 rp = VTOR(vp); 577 mutex_enter(&rp->r_statelock); 578 if (rp->r_secattr != NULL) { 579 nfs_acl_free(rp->r_secattr); 580 rp->r_secattr = NULL; 581 } 582 mutex_exit(&rp->r_statelock); 583 584 if (error) 585 return (error); 586 587 error = geterrno3(res.status); 588 if (!error) { 589 nfs3_cache_post_op_attr(vp, &res.resok.attr, t, cr); 590 } else { 591 nfs3_cache_post_op_attr(vp, &res.resfail.attr, t, cr); 592 PURGE_STALE_FH(error, vp, cr); 593 } 594 595 return (error); 596 } 597 598 int 599 acl_getxattrdir3(vnode_t *vp, vnode_t **vpp, bool_t create, cred_t *cr, 600 int rfscall_flags) 601 { 602 int error; 603 GETXATTRDIR3args args; 604 GETXATTRDIR3res res; 605 int doqueue; 606 struct vattr vattr; 607 vnode_t *nvp; 608 failinfo_t fi; 609 hrtime_t t; 610 611 args.fh = *VTOFH3(vp); 612 args.create = create; 613 614 fi.vp = vp; 615 fi.fhp = (caddr_t)&args.fh; 616 fi.copyproc = nfs3copyfh; 617 fi.lookupproc = nfs3lookup; 618 fi.xattrdirproc = acl_getxattrdir3; 619 620 doqueue = 1; 621 622 t = gethrtime(); 623 624 error = acl3call(VTOMI(vp), ACLPROC3_GETXATTRDIR, 625 xdr_GETXATTRDIR3args, (caddr_t)&args, 626 xdr_GETXATTRDIR3res, (caddr_t)&res, cr, 627 &doqueue, &res.status, rfscall_flags, &fi); 628 629 if (error) 630 return (error); 631 632 error = geterrno3(res.status); 633 if (!error) { 634 if (res.resok.attr.attributes) { 635 nvp = makenfs3node(&res.resok.fh, 636 &res.resok.attr.attr, 637 vp->v_vfsp, t, cr, VTOR(vp)->r_path, XATTR_RPATH); 638 } else { 639 nvp = makenfs3node(&res.resok.fh, NULL, 640 vp->v_vfsp, t, cr, VTOR(vp)->r_path, XATTR_RPATH); 641 if (nvp->v_type == VNON) { 642 vattr.va_mask = AT_TYPE; 643 error = nfs3getattr(nvp, &vattr, cr); 644 if (error) { 645 VN_RELE(nvp); 646 return (error); 647 } 648 nvp->v_type = vattr.va_type; 649 } 650 } 651 mutex_enter(&nvp->v_lock); 652 nvp->v_flag |= V_XATTRDIR; 653 mutex_exit(&nvp->v_lock); 654 if (!(rfscall_flags & RFSCALL_SOFT)) 655 dnlc_update(vp, XATTR_DIR_NAME, nvp); 656 *vpp = nvp; 657 } else { 658 PURGE_STALE_FH(error, vp, cr); 659 if (error == ENOENT && xattr_lookup_neg_cache) 660 dnlc_enter(vp, XATTR_DIR_NAME, DNLC_NO_VNODE); 661 } 662 663 return (error); 664 } 665 666 void 667 nfs_acl_free(vsecattr_t *vsp) 668 { 669 670 if (vsp->vsa_aclentp != NULL) { 671 kmem_free(vsp->vsa_aclentp, vsp->vsa_aclcnt * 672 sizeof (aclent_t)); 673 } 674 if (vsp->vsa_dfaclentp != NULL) { 675 kmem_free(vsp->vsa_dfaclentp, vsp->vsa_dfaclcnt * 676 sizeof (aclent_t)); 677 } 678 kmem_free(vsp, sizeof (*vsp)); 679 } 680 681 static int 682 nfs_acl_dup_cache(vsecattr_t *vsp, vsecattr_t *rvsp) 683 { 684 size_t aclsize; 685 686 if ((rvsp->vsa_mask & vsp->vsa_mask) != vsp->vsa_mask) 687 return (0); 688 689 if (vsp->vsa_mask & VSA_ACL) { 690 ASSERT(rvsp->vsa_mask & VSA_ACLCNT); 691 aclsize = rvsp->vsa_aclcnt * sizeof (aclent_t); 692 vsp->vsa_aclentp = kmem_alloc(aclsize, KM_SLEEP); 693 bcopy(rvsp->vsa_aclentp, vsp->vsa_aclentp, aclsize); 694 } 695 if (vsp->vsa_mask & VSA_ACLCNT) 696 vsp->vsa_aclcnt = rvsp->vsa_aclcnt; 697 if (vsp->vsa_mask & VSA_DFACL) { 698 ASSERT(rvsp->vsa_mask & VSA_DFACLCNT); 699 aclsize = rvsp->vsa_dfaclcnt * sizeof (aclent_t); 700 vsp->vsa_dfaclentp = kmem_alloc(aclsize, KM_SLEEP); 701 bcopy(rvsp->vsa_dfaclentp, vsp->vsa_dfaclentp, aclsize); 702 } 703 if (vsp->vsa_mask & VSA_DFACLCNT) 704 vsp->vsa_dfaclcnt = rvsp->vsa_dfaclcnt; 705 706 return (1); 707 } 708 709 static void 710 nfs_acl_dup_res_impl(kmutex_t *statelock, vsecattr_t **rspp, vsecattr_t *vsp) 711 { 712 size_t aclsize; 713 vsecattr_t *rvsp; 714 715 mutex_enter(statelock); 716 if (*rspp != NULL) 717 rvsp = *rspp; 718 else { 719 rvsp = kmem_zalloc(sizeof (*rvsp), KM_NOSLEEP); 720 if (rvsp == NULL) { 721 mutex_exit(statelock); 722 return; 723 } 724 *rspp = rvsp; 725 } 726 727 if (vsp->vsa_mask & VSA_ACL) { 728 if (rvsp->vsa_aclentp != NULL && 729 rvsp->vsa_aclcnt != vsp->vsa_aclcnt) { 730 aclsize = rvsp->vsa_aclcnt * sizeof (aclent_t); 731 kmem_free(rvsp->vsa_aclentp, aclsize); 732 rvsp->vsa_aclentp = NULL; 733 } 734 if (vsp->vsa_aclcnt > 0) { 735 aclsize = vsp->vsa_aclcnt * sizeof (aclent_t); 736 if (rvsp->vsa_aclentp == NULL) { 737 rvsp->vsa_aclentp = kmem_alloc(aclsize, 738 KM_SLEEP); 739 } 740 bcopy(vsp->vsa_aclentp, rvsp->vsa_aclentp, aclsize); 741 } 742 rvsp->vsa_aclcnt = vsp->vsa_aclcnt; 743 rvsp->vsa_mask |= VSA_ACL | VSA_ACLCNT; 744 } 745 if (vsp->vsa_mask & VSA_ACLCNT) { 746 if (rvsp->vsa_aclentp != NULL && 747 rvsp->vsa_aclcnt != vsp->vsa_aclcnt) { 748 aclsize = rvsp->vsa_aclcnt * sizeof (aclent_t); 749 kmem_free(rvsp->vsa_aclentp, aclsize); 750 rvsp->vsa_aclentp = NULL; 751 rvsp->vsa_mask &= ~VSA_ACL; 752 } 753 rvsp->vsa_aclcnt = vsp->vsa_aclcnt; 754 rvsp->vsa_mask |= VSA_ACLCNT; 755 } 756 if (vsp->vsa_mask & VSA_DFACL) { 757 if (rvsp->vsa_dfaclentp != NULL && 758 rvsp->vsa_dfaclcnt != vsp->vsa_dfaclcnt) { 759 aclsize = rvsp->vsa_dfaclcnt * sizeof (aclent_t); 760 kmem_free(rvsp->vsa_dfaclentp, aclsize); 761 rvsp->vsa_dfaclentp = NULL; 762 } 763 if (vsp->vsa_dfaclcnt > 0) { 764 aclsize = vsp->vsa_dfaclcnt * sizeof (aclent_t); 765 if (rvsp->vsa_dfaclentp == NULL) { 766 rvsp->vsa_dfaclentp = kmem_alloc(aclsize, 767 KM_SLEEP); 768 } 769 bcopy(vsp->vsa_dfaclentp, rvsp->vsa_dfaclentp, aclsize); 770 } 771 rvsp->vsa_dfaclcnt = vsp->vsa_dfaclcnt; 772 rvsp->vsa_mask |= VSA_DFACL | VSA_DFACLCNT; 773 } 774 if (vsp->vsa_mask & VSA_DFACLCNT) { 775 if (rvsp->vsa_dfaclentp != NULL && 776 rvsp->vsa_dfaclcnt != vsp->vsa_dfaclcnt) { 777 aclsize = rvsp->vsa_dfaclcnt * sizeof (aclent_t); 778 kmem_free(rvsp->vsa_dfaclentp, aclsize); 779 rvsp->vsa_dfaclentp = NULL; 780 rvsp->vsa_mask &= ~VSA_DFACL; 781 } 782 rvsp->vsa_dfaclcnt = vsp->vsa_dfaclcnt; 783 rvsp->vsa_mask |= VSA_DFACLCNT; 784 } 785 mutex_exit(statelock); 786 } 787 788 static void 789 nfs_acl_dup_res(rnode_t *rp, vsecattr_t *vsp) 790 { 791 nfs_acl_dup_res_impl(&rp->r_statelock, &rp->r_secattr, vsp); 792 } 793