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, *ncrfree = NULL; 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 /* 326 * ncr and ncrfree both initially 327 * point to the memory area returned 328 * by crnetadjust(); 329 * ncrfree not NULL when exiting means 330 * that we need to release it 331 */ 332 ncr = crnetadjust(cred); 333 ncrfree = ncr; 334 335 tryagain: 336 if (rp->r_acache != NULL) { 337 cacc = nfs_access_check(rp, acc, cr); 338 if (cacc == NFS_ACCESS_ALLOWED) { 339 if (ncrfree != NULL) 340 crfree(ncrfree); 341 return (0); 342 } 343 if (cacc == NFS_ACCESS_DENIED) { 344 /* 345 * If the cred can be adjusted, try again 346 * with the new cred. 347 */ 348 if (ncr != NULL) { 349 cred = ncr; 350 ncr = NULL; 351 goto tryagain; 352 } 353 if (ncrfree != NULL) 354 crfree(ncrfree); 355 return (EACCES); 356 } 357 } 358 359 doqueue = 1; 360 361 t = gethrtime(); 362 363 error = acl2call(VTOMI(vp), ACLPROC2_ACCESS, 364 xdr_ACCESS2args, (caddr_t)&args, 365 xdr_ACCESS2res, (caddr_t)&res, cred, 366 &doqueue, &res.status, 0, &fi); 367 368 if (error) { 369 if (ncrfree != NULL) 370 crfree(ncrfree); 371 return (error); 372 } 373 374 error = geterrno(res.status); 375 if (!error) { 376 (void) nfs_cache_fattr(vp, &res.resok.attr, &va, t, cr); 377 nfs_access_cache(rp, args.access, res.resok.access, cred); 378 /* 379 * we just cached results with cred; if cred is the 380 * adjusted credentials from crnetadjust, we do not want 381 * to release them before exiting: hence setting ncrfree 382 * to NULL 383 */ 384 if (cred != cr) 385 ncrfree = NULL; 386 if ((acc & res.resok.access) != acc) { 387 /* 388 * If the cred can be adjusted, try again 389 * with the new cred. 390 */ 391 if (ncr != NULL) { 392 cred = ncr; 393 ncr = NULL; 394 goto tryagain; 395 } 396 error = EACCES; 397 } 398 } else { 399 PURGE_STALE_FH(error, vp, cr); 400 } 401 402 if (ncrfree != NULL) 403 crfree(ncrfree); 404 405 return (error); 406 } 407 408 static int xattr_lookup_neg_cache = 1; 409 410 /* 411 * Look up a hidden attribute directory over the wire; the vnode 412 * we start with could be a file or directory. We have to be 413 * tricky in recording the name in the rnode r_path - we use the 414 * magic name XATTR_RPATH and rely on code in failover_lookup() to 415 * detect this and use this routine to do the same lookup on 416 * remapping. DNLC is easier: slashes are legal, so we use 417 * XATTR_DIR_NAME as UFS does. 418 */ 419 int 420 acl_getxattrdir2(vnode_t *vp, vnode_t **vpp, bool_t create, cred_t *cr, 421 int rfscall_flags) 422 { 423 int error; 424 GETXATTRDIR2args args; 425 GETXATTRDIR2res res; 426 int doqueue; 427 failinfo_t fi; 428 hrtime_t t; 429 430 args.fh = *VTOFH(vp); 431 args.create = create; 432 433 fi.vp = vp; 434 fi.fhp = NULL; /* no need to update, filehandle not copied */ 435 fi.copyproc = nfscopyfh; 436 fi.lookupproc = nfslookup; 437 fi.xattrdirproc = acl_getxattrdir2; 438 439 doqueue = 1; 440 441 t = gethrtime(); 442 443 error = acl2call(VTOMI(vp), ACLPROC2_GETXATTRDIR, 444 xdr_GETXATTRDIR2args, (caddr_t)&args, 445 xdr_GETXATTRDIR2res, (caddr_t)&res, cr, 446 &doqueue, &res.status, rfscall_flags, &fi); 447 448 if (!error) { 449 error = geterrno(res.status); 450 if (!error) { 451 *vpp = makenfsnode(&res.resok.fh, &res.resok.attr, 452 vp->v_vfsp, t, cr, VTOR(vp)->r_path, XATTR_RPATH); 453 mutex_enter(&(*vpp)->v_lock); 454 (*vpp)->v_flag |= V_XATTRDIR; 455 mutex_exit(&(*vpp)->v_lock); 456 if (!(rfscall_flags & RFSCALL_SOFT)) 457 dnlc_update(vp, XATTR_DIR_NAME, *vpp); 458 } else { 459 PURGE_STALE_FH(error, vp, cr); 460 if (error == ENOENT && xattr_lookup_neg_cache) 461 dnlc_enter(vp, XATTR_DIR_NAME, DNLC_NO_VNODE); 462 } 463 } 464 return (error); 465 } 466 467 /* 468 * The order and contents of this structure must be kept in sync with that of 469 * aclreqcnt_v3_tmpl in nfs_stats.c 470 */ 471 char *aclnames_v3[] = { 472 "null", "getacl", "setacl", "getxattrdir" 473 }; 474 475 /* 476 * This table maps from NFS protocol number into call type. 477 * Zero means a "Lookup" type call 478 * One means a "Read" type call 479 * Two means a "Write" type call 480 * This is used to select a default time-out. 481 */ 482 uchar_t acl_call_type_v3[] = { 483 0, 0, 1, 0 484 }; 485 486 /* 487 * This table maps from acl operation into a call type 488 * for the semisoft mount option. 489 * Zero means do not repeat operation. 490 * One means repeat. 491 */ 492 uchar_t acl_ss_call_type_v3[] = { 493 0, 0, 1, 0 494 }; 495 496 /* 497 * Similar table, but to determine which timer to use 498 * (only real reads and writes!) 499 */ 500 uchar_t acl_timer_type_v3[] = { 501 0, 0, 0, 0 502 }; 503 504 /* ARGSUSED */ 505 int 506 acl_getacl3(vnode_t *vp, vsecattr_t *vsp, int flag, cred_t *cr) 507 { 508 int error; 509 GETACL3args args; 510 GETACL3res res; 511 int doqueue; 512 rnode_t *rp; 513 failinfo_t fi; 514 hrtime_t t; 515 516 rp = VTOR(vp); 517 if (rp->r_secattr != NULL) { 518 error = nfs3_validate_caches(vp, cr); 519 if (error) 520 return (error); 521 mutex_enter(&rp->r_statelock); 522 if (rp->r_secattr != NULL) { 523 if (nfs_acl_dup_cache(vsp, rp->r_secattr)) { 524 mutex_exit(&rp->r_statelock); 525 return (0); 526 } 527 } 528 mutex_exit(&rp->r_statelock); 529 } 530 531 args.mask = vsp->vsa_mask; 532 args.fh = *VTOFH3(vp); 533 fi.vp = vp; 534 fi.fhp = (caddr_t)&args.fh; 535 fi.copyproc = nfs3copyfh; 536 fi.lookupproc = nfs3lookup; 537 fi.xattrdirproc = acl_getxattrdir3; 538 539 res.resok.acl.vsa_aclentp = NULL; 540 res.resok.acl.vsa_dfaclentp = NULL; 541 542 doqueue = 1; 543 544 t = gethrtime(); 545 546 error = acl3call(VTOMI(vp), ACLPROC3_GETACL, 547 xdr_GETACL3args, (caddr_t)&args, 548 xdr_GETACL3res, (caddr_t)&res, cr, 549 &doqueue, &res.status, 0, &fi); 550 551 if (error) 552 return (error); 553 554 error = geterrno3(res.status); 555 556 if (!error) { 557 nfs3_cache_post_op_attr(vp, &res.resok.attr, t, cr); 558 nfs_acl_dup_res(rp, &res.resok.acl); 559 *vsp = res.resok.acl; 560 } else { 561 nfs3_cache_post_op_attr(vp, &res.resfail.attr, t, cr); 562 PURGE_STALE_FH(error, vp, cr); 563 } 564 565 return (error); 566 } 567 568 /* ARGSUSED */ 569 int 570 acl_setacl3(vnode_t *vp, vsecattr_t *vsp, int flag, cred_t *cr) 571 { 572 int error; 573 SETACL3args args; 574 SETACL3res res; 575 rnode_t *rp; 576 int doqueue; 577 hrtime_t t; 578 579 args.fh = *VTOFH3(vp); 580 args.acl = *vsp; 581 582 doqueue = 1; 583 584 t = gethrtime(); 585 586 error = acl3call(VTOMI(vp), ACLPROC3_SETACL, 587 xdr_SETACL3args, (caddr_t)&args, 588 xdr_SETACL3res, (caddr_t)&res, cr, 589 &doqueue, &res.status, 0, NULL); 590 591 /* 592 * On success, adding the arguments to setsecattr into the cache have 593 * not proven adequate. On error, we cannot depend on cache. 594 * Simply flush the cache to force the next getsecattr 595 * to go over the wire. 596 */ 597 rp = VTOR(vp); 598 mutex_enter(&rp->r_statelock); 599 if (rp->r_secattr != NULL) { 600 nfs_acl_free(rp->r_secattr); 601 rp->r_secattr = NULL; 602 } 603 mutex_exit(&rp->r_statelock); 604 605 if (error) 606 return (error); 607 608 error = geterrno3(res.status); 609 if (!error) { 610 nfs3_cache_post_op_attr(vp, &res.resok.attr, t, cr); 611 } else { 612 nfs3_cache_post_op_attr(vp, &res.resfail.attr, t, cr); 613 PURGE_STALE_FH(error, vp, cr); 614 } 615 616 return (error); 617 } 618 619 int 620 acl_getxattrdir3(vnode_t *vp, vnode_t **vpp, bool_t create, cred_t *cr, 621 int rfscall_flags) 622 { 623 int error; 624 GETXATTRDIR3args args; 625 GETXATTRDIR3res res; 626 int doqueue; 627 struct vattr vattr; 628 vnode_t *nvp; 629 failinfo_t fi; 630 hrtime_t t; 631 632 args.fh = *VTOFH3(vp); 633 args.create = create; 634 635 fi.vp = vp; 636 fi.fhp = (caddr_t)&args.fh; 637 fi.copyproc = nfs3copyfh; 638 fi.lookupproc = nfs3lookup; 639 fi.xattrdirproc = acl_getxattrdir3; 640 641 doqueue = 1; 642 643 t = gethrtime(); 644 645 error = acl3call(VTOMI(vp), ACLPROC3_GETXATTRDIR, 646 xdr_GETXATTRDIR3args, (caddr_t)&args, 647 xdr_GETXATTRDIR3res, (caddr_t)&res, cr, 648 &doqueue, &res.status, rfscall_flags, &fi); 649 650 if (error) 651 return (error); 652 653 error = geterrno3(res.status); 654 if (!error) { 655 if (res.resok.attr.attributes) { 656 nvp = makenfs3node(&res.resok.fh, 657 &res.resok.attr.attr, 658 vp->v_vfsp, t, cr, VTOR(vp)->r_path, XATTR_RPATH); 659 } else { 660 nvp = makenfs3node(&res.resok.fh, NULL, 661 vp->v_vfsp, t, cr, VTOR(vp)->r_path, XATTR_RPATH); 662 if (nvp->v_type == VNON) { 663 vattr.va_mask = AT_TYPE; 664 error = nfs3getattr(nvp, &vattr, cr); 665 if (error) { 666 VN_RELE(nvp); 667 return (error); 668 } 669 nvp->v_type = vattr.va_type; 670 } 671 } 672 mutex_enter(&nvp->v_lock); 673 nvp->v_flag |= V_XATTRDIR; 674 mutex_exit(&nvp->v_lock); 675 if (!(rfscall_flags & RFSCALL_SOFT)) 676 dnlc_update(vp, XATTR_DIR_NAME, nvp); 677 *vpp = nvp; 678 } else { 679 PURGE_STALE_FH(error, vp, cr); 680 if (error == ENOENT && xattr_lookup_neg_cache) 681 dnlc_enter(vp, XATTR_DIR_NAME, DNLC_NO_VNODE); 682 } 683 684 return (error); 685 } 686 687 void 688 nfs_acl_free(vsecattr_t *vsp) 689 { 690 691 if (vsp->vsa_aclentp != NULL) { 692 kmem_free(vsp->vsa_aclentp, vsp->vsa_aclcnt * 693 sizeof (aclent_t)); 694 } 695 if (vsp->vsa_dfaclentp != NULL) { 696 kmem_free(vsp->vsa_dfaclentp, vsp->vsa_dfaclcnt * 697 sizeof (aclent_t)); 698 } 699 kmem_free(vsp, sizeof (*vsp)); 700 } 701 702 static int 703 nfs_acl_dup_cache(vsecattr_t *vsp, vsecattr_t *rvsp) 704 { 705 size_t aclsize; 706 707 if ((rvsp->vsa_mask & vsp->vsa_mask) != vsp->vsa_mask) 708 return (0); 709 710 if (vsp->vsa_mask & VSA_ACL) { 711 ASSERT(rvsp->vsa_mask & VSA_ACLCNT); 712 aclsize = rvsp->vsa_aclcnt * sizeof (aclent_t); 713 vsp->vsa_aclentp = kmem_alloc(aclsize, KM_SLEEP); 714 bcopy(rvsp->vsa_aclentp, vsp->vsa_aclentp, aclsize); 715 } 716 if (vsp->vsa_mask & VSA_ACLCNT) 717 vsp->vsa_aclcnt = rvsp->vsa_aclcnt; 718 if (vsp->vsa_mask & VSA_DFACL) { 719 ASSERT(rvsp->vsa_mask & VSA_DFACLCNT); 720 aclsize = rvsp->vsa_dfaclcnt * sizeof (aclent_t); 721 vsp->vsa_dfaclentp = kmem_alloc(aclsize, KM_SLEEP); 722 bcopy(rvsp->vsa_dfaclentp, vsp->vsa_dfaclentp, aclsize); 723 } 724 if (vsp->vsa_mask & VSA_DFACLCNT) 725 vsp->vsa_dfaclcnt = rvsp->vsa_dfaclcnt; 726 727 return (1); 728 } 729 730 static void 731 nfs_acl_dup_res_impl(kmutex_t *statelock, vsecattr_t **rspp, vsecattr_t *vsp) 732 { 733 size_t aclsize; 734 vsecattr_t *rvsp; 735 736 mutex_enter(statelock); 737 if (*rspp != NULL) 738 rvsp = *rspp; 739 else { 740 rvsp = kmem_zalloc(sizeof (*rvsp), KM_NOSLEEP); 741 if (rvsp == NULL) { 742 mutex_exit(statelock); 743 return; 744 } 745 *rspp = rvsp; 746 } 747 748 if (vsp->vsa_mask & VSA_ACL) { 749 if (rvsp->vsa_aclentp != NULL && 750 rvsp->vsa_aclcnt != vsp->vsa_aclcnt) { 751 aclsize = rvsp->vsa_aclcnt * sizeof (aclent_t); 752 kmem_free(rvsp->vsa_aclentp, aclsize); 753 rvsp->vsa_aclentp = NULL; 754 } 755 if (vsp->vsa_aclcnt > 0) { 756 aclsize = vsp->vsa_aclcnt * sizeof (aclent_t); 757 if (rvsp->vsa_aclentp == NULL) { 758 rvsp->vsa_aclentp = kmem_alloc(aclsize, 759 KM_SLEEP); 760 } 761 bcopy(vsp->vsa_aclentp, rvsp->vsa_aclentp, aclsize); 762 } 763 rvsp->vsa_aclcnt = vsp->vsa_aclcnt; 764 rvsp->vsa_mask |= VSA_ACL | VSA_ACLCNT; 765 } 766 if (vsp->vsa_mask & VSA_ACLCNT) { 767 if (rvsp->vsa_aclentp != NULL && 768 rvsp->vsa_aclcnt != vsp->vsa_aclcnt) { 769 aclsize = rvsp->vsa_aclcnt * sizeof (aclent_t); 770 kmem_free(rvsp->vsa_aclentp, aclsize); 771 rvsp->vsa_aclentp = NULL; 772 rvsp->vsa_mask &= ~VSA_ACL; 773 } 774 rvsp->vsa_aclcnt = vsp->vsa_aclcnt; 775 rvsp->vsa_mask |= VSA_ACLCNT; 776 } 777 if (vsp->vsa_mask & VSA_DFACL) { 778 if (rvsp->vsa_dfaclentp != NULL && 779 rvsp->vsa_dfaclcnt != vsp->vsa_dfaclcnt) { 780 aclsize = rvsp->vsa_dfaclcnt * sizeof (aclent_t); 781 kmem_free(rvsp->vsa_dfaclentp, aclsize); 782 rvsp->vsa_dfaclentp = NULL; 783 } 784 if (vsp->vsa_dfaclcnt > 0) { 785 aclsize = vsp->vsa_dfaclcnt * sizeof (aclent_t); 786 if (rvsp->vsa_dfaclentp == NULL) { 787 rvsp->vsa_dfaclentp = kmem_alloc(aclsize, 788 KM_SLEEP); 789 } 790 bcopy(vsp->vsa_dfaclentp, rvsp->vsa_dfaclentp, aclsize); 791 } 792 rvsp->vsa_dfaclcnt = vsp->vsa_dfaclcnt; 793 rvsp->vsa_mask |= VSA_DFACL | VSA_DFACLCNT; 794 } 795 if (vsp->vsa_mask & VSA_DFACLCNT) { 796 if (rvsp->vsa_dfaclentp != NULL && 797 rvsp->vsa_dfaclcnt != vsp->vsa_dfaclcnt) { 798 aclsize = rvsp->vsa_dfaclcnt * sizeof (aclent_t); 799 kmem_free(rvsp->vsa_dfaclentp, aclsize); 800 rvsp->vsa_dfaclentp = NULL; 801 rvsp->vsa_mask &= ~VSA_DFACL; 802 } 803 rvsp->vsa_dfaclcnt = vsp->vsa_dfaclcnt; 804 rvsp->vsa_mask |= VSA_DFACLCNT; 805 } 806 mutex_exit(statelock); 807 } 808 809 static void 810 nfs_acl_dup_res(rnode_t *rp, vsecattr_t *vsp) 811 { 812 nfs_acl_dup_res_impl(&rp->r_statelock, &rp->r_secattr, vsp); 813 } 814