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
acl_getacl2(vnode_t * vp,vsecattr_t * vsp,int flag,cred_t * cr)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
acl_setacl2(vnode_t * vp,vsecattr_t * vsp,int flag,cred_t * cr)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
acl_getattr2_otw(vnode_t * vp,vattr_t * vap,cred_t * cr)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
acl_access2(vnode_t * vp,int mode,int flags,cred_t * cr)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
acl_getxattrdir2(vnode_t * vp,vnode_t ** vpp,bool_t create,cred_t * cr,int rfscall_flags)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
acl_getacl3(vnode_t * vp,vsecattr_t * vsp,int flag,cred_t * cr)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
acl_setacl3(vnode_t * vp,vsecattr_t * vsp,int flag,cred_t * cr)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
acl_getxattrdir3(vnode_t * vp,vnode_t ** vpp,bool_t create,cred_t * cr,int rfscall_flags)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
nfs_acl_free(vsecattr_t * vsp)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
nfs_acl_dup_cache(vsecattr_t * vsp,vsecattr_t * rvsp)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
nfs_acl_dup_res_impl(kmutex_t * statelock,vsecattr_t ** rspp,vsecattr_t * vsp)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
nfs_acl_dup_res(rnode_t * rp,vsecattr_t * vsp)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