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
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.
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]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include <sys/param.h>
30 #include <sys/types.h>
31 #include <sys/systm.h>
36 #include <sys/vnode.h>
42 #include <sys/tiuser.h>
43 #include <sys/pathname.h>
44 #include <sys/dirent.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>
52 #include <sys/errno.h>
53 #include <sys/sysmacros.h>
56 #include <sys/cmn_err.h>
57 #include <sys/vtrace.h>
58 #include <sys/pathconf.h>
62 #include <rpc/types.h>
67 #include <nfs/nfs_clnt.h>
68 #include <nfs/rnode.h>
69 #include <nfs/nfs_acl.h>
76 #include <vm/seg_map.h>
77 #include <vm/seg_kmem.h>
78 #include <vm/seg_vn.h>
81 #include <sys/fs_subr.h>
84 * The order and contents of this structure must be kept in sync with that of
85 * aclreqcnt_v2_tmpl in nfs_stats.c
87 char *aclnames_v2
[] = {
88 "null", "getacl", "setacl", "getattr", "access", "getxattrdir"
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.
98 uchar_t acl_call_type_v2
[] = {
103 * Similar table, but to determine which timer to use
104 * (only real reads and writes!)
106 uchar_t acl_timer_type_v2
[] = {
111 * This table maps from acl operation into a call type
112 * for the semisoft mount option.
113 * Zero means do not repeat operation.
116 uchar_t acl_ss_call_type_v2
[] = {
120 static int nfs_acl_dup_cache(vsecattr_t
*, vsecattr_t
*);
121 static void nfs_acl_dup_res(rnode_t
*, vsecattr_t
*);
125 acl_getacl2(vnode_t
*vp
, vsecattr_t
*vsp
, int flag
, cred_t
*cr
)
137 if (rp
->r_secattr
!= NULL
) {
138 error
= nfs_validate_caches(vp
, cr
);
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
);
148 mutex_exit(&rp
->r_statelock
);
151 args
.mask
= vsp
->vsa_mask
;
152 args
.fh
= *VTOFH(vp
);
154 fi
.fhp
= (caddr_t
)&args
.fh
;
155 fi
.copyproc
= nfscopyfh
;
156 fi
.lookupproc
= nfslookup
;
157 fi
.xattrdirproc
= acl_getxattrdir2
;
159 res
.resok
.acl
.vsa_aclentp
= NULL
;
160 res
.resok
.acl
.vsa_dfaclentp
= NULL
;
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
);
174 error
= geterrno(res
.status
);
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
;
180 PURGE_STALE_FH(error
, vp
, cr
);
188 acl_setacl2(vnode_t
*vp
, vsecattr_t
*vsp
, int flag
, cred_t
*cr
)
198 args
.fh
= *VTOFH(vp
);
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
);
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.
217 mutex_enter(&rp
->r_statelock
);
218 if (rp
->r_secattr
!= NULL
) {
219 nfs_acl_free(rp
->r_secattr
);
220 rp
->r_secattr
= NULL
;
222 mutex_exit(&rp
->r_statelock
);
227 error
= geterrno(res
.status
);
229 (void) nfs_cache_fattr(vp
, &res
.resok
.attr
, &va
, t
, cr
);
231 PURGE_STALE_FH(error
, vp
, cr
);
238 acl_getattr2_otw(vnode_t
*vp
, vattr_t
*vap
, cred_t
*cr
)
247 args
.fh
= *VTOFH(vp
);
249 fi
.fhp
= (caddr_t
)&args
.fh
;
250 fi
.copyproc
= nfscopyfh
;
251 fi
.lookupproc
= nfslookup
;
252 fi
.xattrdirproc
= acl_getxattrdir2
;
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
);
265 error
= geterrno(res
.status
);
268 error
= nfs_cache_fattr(vp
, &res
.resok
.attr
, vap
, t
, cr
);
270 PURGE_STALE_FH(error
, vp
, cr
);
278 acl_access2(vnode_t
*vp
, int mode
, int flags
, cred_t
*cr
)
286 cred_t
*cred
, *ncr
, *ncrfree
= NULL
;
289 nfs_access_type_t cacc
;
296 if (vn_is_readonly(vp
) && !IS_DEVVP(vp
))
298 if (vp
->v_type
== VDIR
)
299 acc
|= ACCESS2_DELETE
;
300 acc
|= ACCESS2_MODIFY
| ACCESS2_EXTEND
;
303 if (vp
->v_type
== VDIR
)
304 acc
|= ACCESS2_LOOKUP
;
306 acc
|= ACCESS2_EXECUTE
;
310 if (vp
->v_type
== VDIR
) {
311 args
.access
= ACCESS2_READ
| ACCESS2_DELETE
| ACCESS2_MODIFY
|
312 ACCESS2_EXTEND
| ACCESS2_LOOKUP
;
314 args
.access
= ACCESS2_READ
| ACCESS2_MODIFY
| ACCESS2_EXTEND
|
317 args
.fh
= *VTOFH(vp
);
319 fi
.fhp
= (caddr_t
)&args
.fh
;
320 fi
.copyproc
= nfscopyfh
;
321 fi
.lookupproc
= nfslookup
;
322 fi
.xattrdirproc
= acl_getxattrdir2
;
326 * ncr and ncrfree both initially
327 * point to the memory area returned
329 * ncrfree not NULL when exiting means
330 * that we need to release it
332 ncr
= crnetadjust(cred
);
336 if (rp
->r_acache
!= NULL
) {
337 cacc
= nfs_access_check(rp
, acc
, cr
);
338 if (cacc
== NFS_ACCESS_ALLOWED
) {
343 if (cacc
== NFS_ACCESS_DENIED
) {
345 * If the cred can be adjusted, try again
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
);
374 error
= geterrno(res
.status
);
376 (void) nfs_cache_fattr(vp
, &res
.resok
.attr
, &va
, t
, cr
);
377 nfs_access_cache(rp
, args
.access
, res
.resok
.access
, cred
);
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
386 if ((acc
& res
.resok
.access
) != acc
) {
388 * If the cred can be adjusted, try again
399 PURGE_STALE_FH(error
, vp
, cr
);
408 static int xattr_lookup_neg_cache
= 1;
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.
420 acl_getxattrdir2(vnode_t
*vp
, vnode_t
**vpp
, bool_t create
, cred_t
*cr
,
424 GETXATTRDIR2args args
;
430 args
.fh
= *VTOFH(vp
);
431 args
.create
= create
;
434 fi
.fhp
= NULL
; /* no need to update, filehandle not copied */
435 fi
.copyproc
= nfscopyfh
;
436 fi
.lookupproc
= nfslookup
;
437 fi
.xattrdirproc
= acl_getxattrdir2
;
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
);
449 error
= geterrno(res
.status
);
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
);
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
);
468 * The order and contents of this structure must be kept in sync with that of
469 * aclreqcnt_v3_tmpl in nfs_stats.c
471 char *aclnames_v3
[] = {
472 "null", "getacl", "setacl", "getxattrdir"
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.
482 uchar_t acl_call_type_v3
[] = {
487 * This table maps from acl operation into a call type
488 * for the semisoft mount option.
489 * Zero means do not repeat operation.
492 uchar_t acl_ss_call_type_v3
[] = {
497 * Similar table, but to determine which timer to use
498 * (only real reads and writes!)
500 uchar_t acl_timer_type_v3
[] = {
506 acl_getacl3(vnode_t
*vp
, vsecattr_t
*vsp
, int flag
, cred_t
*cr
)
517 if (rp
->r_secattr
!= NULL
) {
518 error
= nfs3_validate_caches(vp
, cr
);
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
);
528 mutex_exit(&rp
->r_statelock
);
531 args
.mask
= vsp
->vsa_mask
;
532 args
.fh
= *VTOFH3(vp
);
534 fi
.fhp
= (caddr_t
)&args
.fh
;
535 fi
.copyproc
= nfs3copyfh
;
536 fi
.lookupproc
= nfs3lookup
;
537 fi
.xattrdirproc
= acl_getxattrdir3
;
539 res
.resok
.acl
.vsa_aclentp
= NULL
;
540 res
.resok
.acl
.vsa_dfaclentp
= NULL
;
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
);
554 error
= geterrno3(res
.status
);
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
;
561 nfs3_cache_post_op_attr(vp
, &res
.resfail
.attr
, t
, cr
);
562 PURGE_STALE_FH(error
, vp
, cr
);
570 acl_setacl3(vnode_t
*vp
, vsecattr_t
*vsp
, int flag
, cred_t
*cr
)
579 args
.fh
= *VTOFH3(vp
);
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
);
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.
598 mutex_enter(&rp
->r_statelock
);
599 if (rp
->r_secattr
!= NULL
) {
600 nfs_acl_free(rp
->r_secattr
);
601 rp
->r_secattr
= NULL
;
603 mutex_exit(&rp
->r_statelock
);
608 error
= geterrno3(res
.status
);
610 nfs3_cache_post_op_attr(vp
, &res
.resok
.attr
, t
, cr
);
612 nfs3_cache_post_op_attr(vp
, &res
.resfail
.attr
, t
, cr
);
613 PURGE_STALE_FH(error
, vp
, cr
);
620 acl_getxattrdir3(vnode_t
*vp
, vnode_t
**vpp
, bool_t create
, cred_t
*cr
,
624 GETXATTRDIR3args args
;
632 args
.fh
= *VTOFH3(vp
);
633 args
.create
= create
;
636 fi
.fhp
= (caddr_t
)&args
.fh
;
637 fi
.copyproc
= nfs3copyfh
;
638 fi
.lookupproc
= nfs3lookup
;
639 fi
.xattrdirproc
= acl_getxattrdir3
;
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
);
653 error
= geterrno3(res
.status
);
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
);
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
);
669 nvp
->v_type
= vattr
.va_type
;
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
);
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
);
688 nfs_acl_free(vsecattr_t
*vsp
)
691 if (vsp
->vsa_aclentp
!= NULL
) {
692 kmem_free(vsp
->vsa_aclentp
, vsp
->vsa_aclcnt
*
695 if (vsp
->vsa_dfaclentp
!= NULL
) {
696 kmem_free(vsp
->vsa_dfaclentp
, vsp
->vsa_dfaclcnt
*
699 kmem_free(vsp
, sizeof (*vsp
));
703 nfs_acl_dup_cache(vsecattr_t
*vsp
, vsecattr_t
*rvsp
)
707 if ((rvsp
->vsa_mask
& vsp
->vsa_mask
) != vsp
->vsa_mask
)
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
);
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
);
724 if (vsp
->vsa_mask
& VSA_DFACLCNT
)
725 vsp
->vsa_dfaclcnt
= rvsp
->vsa_dfaclcnt
;
731 nfs_acl_dup_res_impl(kmutex_t
*statelock
, vsecattr_t
**rspp
, vsecattr_t
*vsp
)
736 mutex_enter(statelock
);
740 rvsp
= kmem_zalloc(sizeof (*rvsp
), KM_NOSLEEP
);
742 mutex_exit(statelock
);
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
;
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
,
761 bcopy(vsp
->vsa_aclentp
, rvsp
->vsa_aclentp
, aclsize
);
763 rvsp
->vsa_aclcnt
= vsp
->vsa_aclcnt
;
764 rvsp
->vsa_mask
|= VSA_ACL
| VSA_ACLCNT
;
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
;
774 rvsp
->vsa_aclcnt
= vsp
->vsa_aclcnt
;
775 rvsp
->vsa_mask
|= VSA_ACLCNT
;
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
;
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
,
790 bcopy(vsp
->vsa_dfaclentp
, rvsp
->vsa_dfaclentp
, aclsize
);
792 rvsp
->vsa_dfaclcnt
= vsp
->vsa_dfaclcnt
;
793 rvsp
->vsa_mask
|= VSA_DFACL
| VSA_DFACLCNT
;
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
;
803 rvsp
->vsa_dfaclcnt
= vsp
->vsa_dfaclcnt
;
804 rvsp
->vsa_mask
|= VSA_DFACLCNT
;
806 mutex_exit(statelock
);
810 nfs_acl_dup_res(rnode_t
*rp
, vsecattr_t
*vsp
)
812 nfs_acl_dup_res_impl(&rp
->r_statelock
, &rp
->r_secattr
, vsp
);