Home | History | Annotate | Download | only in nfs
      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