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