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