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.
     24  * All rights reserved.  Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 #include <sys/time.h>
     30 #include <sys/systm.h>
     31 
     32 #include <nfs/nfs.h>
     33 #include <nfs/nfs4.h>
     34 #include <nfs/rnode4.h>
     35 #include <nfs/nfs4_clnt.h>
     36 #include <sys/cmn_err.h>
     37 
     38 static int
     39 timestruc_to_settime4(timestruc_t *tt, settime4 *tt4, int flags)
     40 {
     41 	int	error = 0;
     42 
     43 	if (flags & ATTR_UTIME) {
     44 		tt4->set_it = SET_TO_CLIENT_TIME4;
     45 		error = nfs4_time_vton(tt, &tt4->time);
     46 	} else {
     47 		tt4->set_it = SET_TO_SERVER_TIME4;
     48 	}
     49 	return (error);
     50 }
     51 
     52 
     53 /*
     54  * nfs4_ver_fattr4_attr translates a vattr attribute into a fattr4 attribute
     55  * for use by nfsv4 verify.  For setting atime or mtime use the entry for
     56  * time_XX (XX == access or modify).
     57  * Return TRUE if arg was set (even if there was an error) and FALSE
     58  * otherwise. Also set error code. The caller should not continue
     59  * if error was set, whether or not the return is TRUE or FALSE. Returning
     60  * FALSE does not mean there was an error, only that the attr was not set.
     61  *
     62  * Note: For now we only have the options used by setattr. In the future
     63  * the switch statement below should cover all vattr attrs and possibly
     64  * sys attrs as well.
     65  */
     66 /* ARGSUSED */
     67 static bool_t
     68 nfs4_ver_fattr4_attr(vattr_t *vap, struct nfs4_ntov_map *ntovp,
     69 	union nfs4_attr_u *nap, int flags, int *errorp)
     70 {
     71 	bool_t	retval = TRUE;
     72 
     73 	/*
     74 	 * Special case for time set: if setting the
     75 	 * time, ignore entry for time access/modify set (setattr)
     76 	 * and instead use that of time access/modify.
     77 	 */
     78 	*errorp = 0;
     79 	/*
     80 	 * Bit matches the mask
     81 	 */
     82 	switch (ntovp->vbit & vap->va_mask) {
     83 	case AT_SIZE:
     84 		nap->size = vap->va_size;
     85 		break;
     86 	case AT_MODE:
     87 		nap->mode = vap->va_mode;
     88 		break;
     89 	case AT_UID:
     90 		/*
     91 		 * if no mapping, uid could be mapped to a numeric string,
     92 		 * e.g. 12345->"12345"
     93 		 */
     94 		if (*errorp = nfs_idmap_uid_str(vap->va_uid, &nap->owner,
     95 		    FALSE))
     96 			retval = FALSE;
     97 		break;
     98 	case AT_GID:
     99 		/*
    100 		 * if no mapping, gid will be mapped to a number string,
    101 		 * e.g. "12345"
    102 		 */
    103 		if (*errorp = nfs_idmap_gid_str(vap->va_gid, &nap->owner_group,
    104 		    FALSE))
    105 			retval = FALSE;
    106 		break;
    107 	case AT_ATIME:
    108 		if ((ntovp->nval != FATTR4_TIME_ACCESS) ||
    109 		    (*errorp = nfs4_time_vton(&vap->va_ctime,
    110 					&nap->time_access))) {
    111 			/*
    112 			 * either asked for FATTR4_TIME_ACCESS_SET -
    113 			 *	not used for setattr
    114 			 * or system time invalid for otw transfers
    115 			 */
    116 			retval = FALSE;
    117 		}
    118 		break;
    119 	case AT_MTIME:
    120 		if ((ntovp->nval != FATTR4_TIME_MODIFY) ||
    121 		    (*errorp = nfs4_time_vton(&vap->va_mtime,
    122 					&nap->time_modify))) {
    123 			/*
    124 			 * either asked for FATTR4_TIME_MODIFY_SET -
    125 			 *	not used for setattr
    126 			 * or system time invalid for otw transfers
    127 			 */
    128 			retval = FALSE;
    129 		}
    130 		break;
    131 	case AT_CTIME:
    132 		if (*errorp = nfs4_time_vton(&vap->va_ctime,
    133 					&nap->time_metadata)) {
    134 			/*
    135 			 * system time invalid for otw transfers
    136 			 */
    137 			retval = FALSE;
    138 		}
    139 		break;
    140 	default:
    141 		retval = FALSE;
    142 	}
    143 	return (retval);
    144 }
    145 
    146 /*
    147  * nfs4_set_fattr4_attr translates a vattr attribute into a fattr4 attribute
    148  * for use by nfs4_setattr.  For setting atime or mtime use the entry for
    149  * time_XX_set rather than time_XX (XX == access or modify).
    150  * Return TRUE if arg was set (even if there was an error) and FALSE
    151  * otherwise. Also set error code. The caller should not continue
    152  * if error was set, whether or not the return is TRUE or FALSE. Returning
    153  * FALSE does not mean there was an error, only that the attr was not set.
    154  */
    155 static bool_t
    156 nfs4_set_fattr4_attr(vattr_t *vap, vsecattr_t *vsap,
    157 	struct nfs4_ntov_map *ntovp, union nfs4_attr_u *nap, int flags,
    158 	int *errorp)
    159 {
    160 	bool_t	retval = TRUE;
    161 
    162 	/*
    163 	 * Special case for time set: if setting the
    164 	 * time, ignore entry for time access/modify
    165 	 * and instead use that of time access/modify set.
    166 	 */
    167 	*errorp = 0;
    168 	/*
    169 	 * Bit matches the mask
    170 	 */
    171 	switch (ntovp->vbit & vap->va_mask) {
    172 	case AT_SIZE:
    173 		nap->size = vap->va_size;
    174 		break;
    175 	case AT_MODE:
    176 		nap->mode = vap->va_mode;
    177 		break;
    178 	case AT_UID:
    179 		/*
    180 		 * if no mapping, uid will be mapped to a number string,
    181 		 * e.g. "12345"
    182 		 */
    183 		if (*errorp = nfs_idmap_uid_str(vap->va_uid, &nap->owner,
    184 		    FALSE))
    185 			retval = FALSE;
    186 		break;
    187 	case AT_GID:
    188 		/*
    189 		 * if no mapping, gid will be mapped to a number string,
    190 		 * e.g. "12345"
    191 		 */
    192 		if (*errorp = nfs_idmap_gid_str(vap->va_gid, &nap->owner_group,
    193 		    FALSE))
    194 			retval = FALSE;
    195 		break;
    196 	case AT_ATIME:
    197 		if ((ntovp->nval != FATTR4_TIME_ACCESS_SET) ||
    198 		    (*errorp = timestruc_to_settime4(&vap->va_atime,
    199 				&nap->time_access_set, flags))) {
    200 			/* FATTR4_TIME_ACCESS - not used for verify */
    201 			retval = FALSE;
    202 		}
    203 		break;
    204 	case AT_MTIME:
    205 		if ((ntovp->nval != FATTR4_TIME_MODIFY_SET) ||
    206 		    (*errorp = timestruc_to_settime4(&vap->va_mtime,
    207 				&nap->time_modify_set, flags))) {
    208 			/* FATTR4_TIME_MODIFY - not used for verify */
    209 			retval = FALSE;
    210 		}
    211 		break;
    212 	default:
    213 		/*
    214 		 * If the ntovp->vbit == 0 this is most likely the ACL.
    215 		 */
    216 		if (ntovp->vbit == 0 && ntovp->fbit == FATTR4_ACL_MASK) {
    217 			ASSERT(vsap->vsa_mask == (VSA_ACE | VSA_ACECNT));
    218 			nap->acl.fattr4_acl_len = vsap->vsa_aclcnt;
    219 			nap->acl.fattr4_acl_val = vsap->vsa_aclentp;
    220 		} else
    221 			retval = FALSE;
    222 	}
    223 
    224 	return (retval);
    225 }
    226 
    227 /*
    228  * XXX - This is a shorter version of vattr_to_fattr4 which only takes care
    229  * of setattr args - size, mode, uid/gid, times. Eventually we should generalize
    230  * by using nfs4_ntov_map and the same functions used by the server.
    231  * Here we just hardcoded the setattr attributes. Note that the order is
    232  * important - it should follow the order of the bits in the mask.
    233  */
    234 int
    235 vattr_to_fattr4(vattr_t *vap, vsecattr_t *vsap, fattr4 *fattrp, int flags,
    236 		enum nfs_opnum4 op, bitmap4 supp)
    237 {
    238 	int i, j;
    239 	union nfs4_attr_u *na = NULL;
    240 	int attrcnt;
    241 	int uid_attr = -1;
    242 	int gid_attr = -1;
    243 	int acl_attr = -1;
    244 	XDR xdr;
    245 	ulong_t xdr_size;
    246 	char *xdr_attrs;
    247 	int error = 0;
    248 	uint8_t amap[NFS4_MAXNUM_ATTRS];
    249 	uint_t va_mask = vap->va_mask;
    250 	bool_t (*attrfunc)();
    251 
    252 #ifndef lint
    253 	/*
    254 	 * Make sure that maximum attribute number can be expressed as an
    255 	 * 8 bit quantity.
    256 	 */
    257 	ASSERT(NFS4_MAXNUM_ATTRS <= (UINT8_MAX + 1));
    258 #endif
    259 	fattrp->attrmask = 0;
    260 	fattrp->attrlist4_len = 0;
    261 	fattrp->attrlist4 = NULL;
    262 	na = kmem_zalloc(sizeof (union nfs4_attr_u) * nfs4_ntov_map_size,
    263 			KM_SLEEP);
    264 
    265 	if (op == OP_SETATTR || op == OP_CREATE || op == OP_OPEN) {
    266 		/*
    267 		 * Note we need to set the attrmask for set operations.
    268 		 * In particular mtime and atime will be set to the
    269 		 * servers time.
    270 		 */
    271 		nfs4_vmask_to_nmask_set(va_mask, &fattrp->attrmask);
    272 		if (vsap != NULL)
    273 			fattrp->attrmask |= FATTR4_ACL_MASK;
    274 		attrfunc = nfs4_set_fattr4_attr;
    275 	} else {	/* verify/nverify */
    276 		/*
    277 		 * Verfy/nverify use the "normal vmask_to_nmask
    278 		 * this routine knows how to handle all vmask bits
    279 		 */
    280 		nfs4_vmask_to_nmask(va_mask, &fattrp->attrmask);
    281 		/*
    282 		 * XXX verify/nverify only works for a subset of attrs that
    283 		 * directly map to vattr_t attrs.  So, verify/nverify is
    284 		 * broken for servers that only support mandatory attrs.
    285 		 * Mask out change attr for now and fix verify op to
    286 		 * work with mandonly servers later.  nfs4_vmask_to_nmask
    287 		 * sets change whenever it sees request for ctime/mtime,
    288 		 * so we must turn off change because nfs4_ver_fattr4_attr
    289 		 * will not generate args for change.  This is a bug
    290 		 * that will be fixed later.
    291 		 * XXX
    292 		 */
    293 		fattrp->attrmask &= ~FATTR4_CHANGE_MASK;
    294 		attrfunc = nfs4_ver_fattr4_attr;
    295 	}
    296 
    297 	/* Mask out any rec attrs unsupported by server */
    298 	fattrp->attrmask &= supp;
    299 
    300 	attrcnt = 0;
    301 	xdr_size = 0;
    302 	for (i = 0; i < nfs4_ntov_map_size; i++) {
    303 		/*
    304 		 * In the case of FATTR4_ACL_MASK, the vbit will be 0 (zero)
    305 		 * so we must also check if the fbit is FATTR4_ACL_MASK before
    306 		 * skipping over this attribute.
    307 		 */
    308 		if (!(nfs4_ntov_map[i].vbit & vap->va_mask)) {
    309 			if (nfs4_ntov_map[i].fbit != FATTR4_ACL_MASK)
    310 				continue;
    311 			if (vsap == NULL)
    312 				continue;
    313 		}
    314 
    315 		if (attrfunc == nfs4_set_fattr4_attr) {
    316 			if (!(*attrfunc)(vap, vsap, &nfs4_ntov_map[i],
    317 			    &na[attrcnt], flags, &error))
    318 				continue;
    319 		} else if (attrfunc == nfs4_ver_fattr4_attr) {
    320 			if (!(*attrfunc)(vap, &nfs4_ntov_map[i], &na[attrcnt],
    321 			    flags, &error))
    322 				continue;
    323 		}
    324 
    325 		if (error)
    326 			goto done;	/* Exit! */
    327 
    328 		/*
    329 		 * Calculate XDR size
    330 		 */
    331 		if (nfs4_ntov_map[i].xdr_size != 0) {
    332 			/*
    333 			 * If we are setting attributes (attrfunc is
    334 			 * nfs4_set_fattr4_attr) and are setting the
    335 			 * mtime or atime, adjust the xdr size down by
    336 			 * 3 words, since we are using the server's
    337 			 * time as the current time.  Exception: if
    338 			 * ATTR_UTIME is set, the client sends the
    339 			 * time, so leave the xdr size alone.
    340 			 */
    341 			xdr_size += nfs4_ntov_map[i].xdr_size;
    342 			if ((nfs4_ntov_map[i].nval == FATTR4_TIME_ACCESS_SET ||
    343 			    nfs4_ntov_map[i].nval == FATTR4_TIME_MODIFY_SET) &&
    344 				attrfunc == nfs4_set_fattr4_attr &&
    345 				!(flags & ATTR_UTIME)) {
    346 				xdr_size -= 3 * BYTES_PER_XDR_UNIT;
    347 			}
    348 		} else {
    349 			/*
    350 			 * The only zero xdr_sizes we should see
    351 			 * are AT_UID, AT_GID and FATTR4_ACL_MASK
    352 			 */
    353 			ASSERT(nfs4_ntov_map[i].vbit == AT_UID ||
    354 				nfs4_ntov_map[i].vbit == AT_GID ||
    355 				nfs4_ntov_map[i].fbit == FATTR4_ACL_MASK);
    356 			if (nfs4_ntov_map[i].vbit == AT_UID) {
    357 				uid_attr = attrcnt;
    358 				xdr_size += BYTES_PER_XDR_UNIT;	/* length */
    359 				xdr_size +=
    360 					RNDUP(na[attrcnt].owner.utf8string_len);
    361 			} else if (nfs4_ntov_map[i].vbit == AT_GID) {
    362 				gid_attr = attrcnt;
    363 				xdr_size += BYTES_PER_XDR_UNIT;	/* length */
    364 				xdr_size +=
    365 				    RNDUP(
    366 					na[attrcnt].owner_group.utf8string_len);
    367 			} else if (nfs4_ntov_map[i].fbit == FATTR4_ACL_MASK) {
    368 				nfsace4 *tmpacl = (nfsace4 *)vsap->vsa_aclentp;
    369 
    370 				acl_attr = attrcnt;
    371 				/* fattr4_acl_len */
    372 				xdr_size += BYTES_PER_XDR_UNIT;
    373 				/* fattr4_acl_val */
    374 				xdr_size += RNDUP((vsap->vsa_aclcnt *
    375 				    (sizeof (acetype4) + sizeof (aceflag4)
    376 				    + sizeof (acemask4))));
    377 
    378 				for (j = 0; j < vsap->vsa_aclcnt; j++) {
    379 					/* who - utf8string_len */
    380 					xdr_size += BYTES_PER_XDR_UNIT;
    381 					/* who - utf8string_val */
    382 					xdr_size +=
    383 					    RNDUP(tmpacl[j].who.utf8string_len);
    384 				}
    385 			}
    386 		}
    387 
    388 		/*
    389 		 * This attr is going otw
    390 		 */
    391 		amap[attrcnt] = (uint8_t)nfs4_ntov_map[i].nval;
    392 		attrcnt++;
    393 
    394 		/*
    395 		 * Clear this bit from test mask so we stop
    396 		 * as soon as all requested attrs are done.
    397 		 */
    398 		va_mask &= ~nfs4_ntov_map[i].vbit;
    399 		if (va_mask == 0 &&
    400 		    (vsap == NULL || (vsap != NULL && acl_attr != -1)))
    401 			break;
    402 	}
    403 
    404 	if (attrcnt == 0) {
    405 		goto done;
    406 	}
    407 
    408 	fattrp->attrlist4 = xdr_attrs = kmem_alloc(xdr_size, KM_SLEEP);
    409 	fattrp->attrlist4_len = xdr_size;
    410 	xdrmem_create(&xdr, xdr_attrs, xdr_size, XDR_ENCODE);
    411 	for (i = 0; i < attrcnt; i++) {
    412 		if ((*nfs4_ntov_map[amap[i]].xfunc)(&xdr, &na[i]) == FALSE) {
    413 			cmn_err(CE_WARN, "vattr_to_fattr4: xdr encode of "
    414 				"attribute failed\n");
    415 			error = EINVAL;
    416 			break;
    417 		}
    418 	}
    419 done:
    420 	/*
    421 	 * Free any malloc'd attrs, can only be uid or gid
    422 	 */
    423 	if (uid_attr != -1 && na[uid_attr].owner.utf8string_val != NULL) {
    424 		kmem_free(na[uid_attr].owner.utf8string_val,
    425 				na[uid_attr].owner.utf8string_len);
    426 	}
    427 	if (gid_attr != -1 && na[gid_attr].owner_group.utf8string_val != NULL) {
    428 		kmem_free(na[gid_attr].owner_group.utf8string_val,
    429 				na[gid_attr].owner_group.utf8string_len);
    430 	}
    431 
    432 	/* xdrmem_destroy(&xdrs); */	/* NO-OP */
    433 	kmem_free(na, sizeof (union nfs4_attr_u) * nfs4_ntov_map_size);
    434 	if (error)
    435 		nfs4_fattr4_free(fattrp);
    436 	return (error);
    437 }
    438 
    439 void
    440 nfs4_fattr4_free(fattr4 *attrp)
    441 {
    442 	/*
    443 	 * set attrlist4val/len to 0 because...
    444 	 *
    445 	 * op_readdir resfree function could call us again
    446 	 * for last entry4 if it was able to encode the name
    447 	 * and cookie but couldn't encode the attrs because
    448 	 * of maxcount violation (from rddir args).  In that
    449 	 * case, the last/partial entry4's fattr4 has already
    450 	 * been free'd, but the entry4 remains on the end of
    451 	 * the list.
    452 	 */
    453 	attrp->attrmask = 0;
    454 
    455 	if (attrp->attrlist4) {
    456 		kmem_free(attrp->attrlist4, attrp->attrlist4_len);
    457 		attrp->attrlist4 = NULL;
    458 		attrp->attrlist4_len = 0;
    459 	}
    460 }
    461 
    462 /*
    463  * Translate a vattr_t mask to a fattr4 type bitmap, caller is
    464  * responsible for zeroing bitsval if needed.
    465  */
    466 void
    467 nfs4_vmask_to_nmask(uint_t vmask, bitmap4 *bitsval)
    468 {
    469 	if (vmask == AT_ALL || vmask == NFS4_VTON_ATTR_MASK) {
    470 		*bitsval |= NFS4_NTOV_ATTR_MASK;
    471 		return;
    472 	}
    473 
    474 	vmask &= NFS4_VTON_ATTR_MASK;
    475 	if (vmask == 0) {
    476 		return;
    477 	}
    478 
    479 	if (vmask & AT_TYPE)
    480 		*bitsval |= FATTR4_TYPE_MASK;
    481 	if (vmask & AT_MODE)
    482 		*bitsval |= FATTR4_MODE_MASK;
    483 	if (vmask & AT_UID)
    484 		*bitsval |= FATTR4_OWNER_MASK;
    485 	if (vmask & AT_GID)
    486 		*bitsval |= FATTR4_OWNER_GROUP_MASK;
    487 	if (vmask & AT_FSID)
    488 		*bitsval |= FATTR4_FSID_MASK;
    489 	/* set mounted_on_fileid when AT_NODEID requested */
    490 	if (vmask & AT_NODEID)
    491 		*bitsval |= FATTR4_FILEID_MASK | FATTR4_MOUNTED_ON_FILEID_MASK;
    492 	if (vmask & AT_NLINK)
    493 		*bitsval |= FATTR4_NUMLINKS_MASK;
    494 	if (vmask & AT_SIZE)
    495 		*bitsval |= FATTR4_SIZE_MASK;
    496 	if (vmask & AT_ATIME)
    497 		*bitsval |= FATTR4_TIME_ACCESS_MASK;
    498 	if (vmask & AT_MTIME)
    499 		*bitsval |= FATTR4_TIME_MODIFY_MASK;
    500 	/* also set CHANGE whenever AT_CTIME requested */
    501 	if (vmask & AT_CTIME)
    502 		*bitsval |= FATTR4_TIME_METADATA_MASK | FATTR4_CHANGE_MASK;
    503 	if (vmask & AT_NBLOCKS)
    504 		*bitsval |= FATTR4_SPACE_USED_MASK;
    505 	if (vmask & AT_RDEV)
    506 		*bitsval |= FATTR4_RAWDEV_MASK;
    507 }
    508 
    509 /*
    510  * nfs4_vmask_to_nmask_set is used for setattr. A separate function needed
    511  * because of special treatment to timeset.
    512  */
    513 void
    514 nfs4_vmask_to_nmask_set(uint_t vmask, bitmap4 *bitsval)
    515 {
    516 	vmask &= NFS4_VTON_ATTR_MASK_SET;
    517 
    518 	if (vmask == 0) {
    519 		return;
    520 	}
    521 
    522 	if (vmask & AT_MODE)
    523 		*bitsval |= FATTR4_MODE_MASK;
    524 	if (vmask & AT_UID)
    525 		*bitsval |= FATTR4_OWNER_MASK;
    526 	if (vmask & AT_GID)
    527 		*bitsval |= FATTR4_OWNER_GROUP_MASK;
    528 	if (vmask & AT_SIZE)
    529 		*bitsval |= FATTR4_SIZE_MASK;
    530 	if (vmask & AT_ATIME)
    531 		*bitsval |= FATTR4_TIME_ACCESS_SET_MASK;
    532 	if (vmask & AT_MTIME)
    533 		*bitsval |= FATTR4_TIME_MODIFY_SET_MASK;
    534 }
    535 
    536 /*
    537  * Convert NFS Version 4 over the network attributes to the local
    538  * virtual attributes.
    539  */
    540 vtype_t nf4_to_vt[] = {
    541 	VBAD, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO, VDIR, VREG
    542 };
    543 
    544 
    545 /*
    546  *	{ fbit, vbit, vfsstat, mandatory,
    547  *		nval, xdr_size, xfunc,
    548  *		sv_getit, prtstr },
    549  */
    550 struct nfs4_ntov_map nfs4_ntov_map[] = {
    551 	{ FATTR4_SUPPORTED_ATTRS_MASK, 0, FALSE, TRUE,
    552 		FATTR4_SUPPORTED_ATTRS, 2 * BYTES_PER_XDR_UNIT, xdr_bitmap4,
    553 		NULL, "fattr4_supported_attrs" },
    554 
    555 	{ FATTR4_TYPE_MASK, AT_TYPE, FALSE, TRUE,
    556 		FATTR4_TYPE, BYTES_PER_XDR_UNIT, xdr_int,
    557 		NULL, "fattr4_type" },
    558 
    559 	{ FATTR4_FH_EXPIRE_TYPE_MASK, 0, FALSE, TRUE,
    560 		FATTR4_FH_EXPIRE_TYPE, BYTES_PER_XDR_UNIT, xdr_u_int,
    561 		NULL, "fattr4_fh_expire_type" },
    562 
    563 	{ FATTR4_CHANGE_MASK, 0, FALSE, TRUE,
    564 		FATTR4_CHANGE, 2 * BYTES_PER_XDR_UNIT, xdr_u_longlong_t,
    565 		NULL, "fattr4_change" },
    566 
    567 	{ FATTR4_SIZE_MASK, AT_SIZE, FALSE, TRUE,
    568 		FATTR4_SIZE,  2 * BYTES_PER_XDR_UNIT, xdr_u_longlong_t,
    569 		NULL, "fattr4_size" },
    570 
    571 	{ FATTR4_LINK_SUPPORT_MASK, 0, FALSE, TRUE,
    572 		FATTR4_LINK_SUPPORT, BYTES_PER_XDR_UNIT, xdr_bool,
    573 		NULL, "fattr4_link_support" },
    574 
    575 	{ FATTR4_SYMLINK_SUPPORT_MASK, 0, FALSE, TRUE,
    576 		FATTR4_SYMLINK_SUPPORT, BYTES_PER_XDR_UNIT, xdr_bool,
    577 		NULL, "fattr4_symlink_support" },
    578 
    579 	{ FATTR4_NAMED_ATTR_MASK, 0, FALSE, TRUE,
    580 		FATTR4_NAMED_ATTR, BYTES_PER_XDR_UNIT, xdr_bool,
    581 		NULL, "fattr4_named_attr" },
    582 
    583 	{ FATTR4_FSID_MASK, AT_FSID, FALSE, TRUE,
    584 		FATTR4_FSID, 4 * BYTES_PER_XDR_UNIT, xdr_fattr4_fsid,
    585 		NULL, "fattr4_fsid" },
    586 
    587 	{ FATTR4_UNIQUE_HANDLES_MASK, 0, FALSE, TRUE,
    588 		FATTR4_UNIQUE_HANDLES, BYTES_PER_XDR_UNIT, xdr_bool,
    589 		NULL, "fattr4_unique_handles" },
    590 
    591 	{ FATTR4_LEASE_TIME_MASK, 0, FALSE, TRUE,
    592 		FATTR4_LEASE_TIME, BYTES_PER_XDR_UNIT, xdr_u_int,
    593 		NULL, "fattr4_lease_time" },
    594 
    595 	{ FATTR4_RDATTR_ERROR_MASK, 0, FALSE, TRUE,
    596 		FATTR4_RDATTR_ERROR, BYTES_PER_XDR_UNIT, xdr_int,
    597 		NULL, "fattr4_rdattr_error" },
    598 
    599 	{ FATTR4_ACL_MASK, 0, FALSE, FALSE,
    600 		FATTR4_ACL, 0, xdr_fattr4_acl,
    601 		NULL, "fattr4_acl" },
    602 
    603 	{ FATTR4_ACLSUPPORT_MASK, 0, FALSE, FALSE,
    604 		FATTR4_ACLSUPPORT, BYTES_PER_XDR_UNIT, xdr_u_int,
    605 		NULL, "fattr4_aclsupport" },
    606 
    607 	{ FATTR4_ARCHIVE_MASK, 0, FALSE, FALSE,
    608 		FATTR4_ARCHIVE, BYTES_PER_XDR_UNIT, xdr_bool,
    609 		NULL, "fattr4_archive" },
    610 
    611 	{ FATTR4_CANSETTIME_MASK, 0, FALSE, FALSE,
    612 		FATTR4_CANSETTIME, BYTES_PER_XDR_UNIT, xdr_bool,
    613 		NULL, "fattr4_cansettime" },
    614 
    615 	{ FATTR4_CASE_INSENSITIVE_MASK, 0, FALSE, FALSE,
    616 		FATTR4_CASE_INSENSITIVE, BYTES_PER_XDR_UNIT, xdr_bool,
    617 		NULL, "fattr4_case_insensitive" },
    618 
    619 	{ FATTR4_CASE_PRESERVING_MASK, 0, FALSE, FALSE,
    620 		FATTR4_CASE_PRESERVING, BYTES_PER_XDR_UNIT, xdr_bool,
    621 		NULL, "fattr4_case_preserving" },
    622 
    623 	{ FATTR4_CHOWN_RESTRICTED_MASK, 0, FALSE, FALSE,
    624 		FATTR4_CHOWN_RESTRICTED, BYTES_PER_XDR_UNIT, xdr_bool,
    625 		NULL, "fattr4_chown_restricted" },
    626 
    627 	{ FATTR4_FILEHANDLE_MASK, 0, FALSE, TRUE,
    628 		FATTR4_FILEHANDLE, 0, xdr_nfs_fh4,
    629 		NULL, "fattr4_filehandle" },
    630 
    631 	{ FATTR4_FILEID_MASK, AT_NODEID, FALSE, FALSE,
    632 		FATTR4_FILEID, 2 * BYTES_PER_XDR_UNIT, xdr_u_longlong_t,
    633 		NULL, "fattr4_fileid" },
    634 
    635 	{ FATTR4_FILES_AVAIL_MASK, 0, TRUE, FALSE,
    636 		FATTR4_FILES_AVAIL, 2 * BYTES_PER_XDR_UNIT, xdr_u_longlong_t,
    637 		NULL, "fattr4_files_avail" },
    638 
    639 	{ FATTR4_FILES_FREE_MASK, 0, TRUE, FALSE,
    640 		FATTR4_FILES_FREE, 2 * BYTES_PER_XDR_UNIT, xdr_u_longlong_t,
    641 		NULL, "fattr4_files_free" },
    642 
    643 	{ FATTR4_FILES_TOTAL_MASK, 0, TRUE, FALSE,
    644 		FATTR4_FILES_TOTAL, 2 * BYTES_PER_XDR_UNIT, xdr_u_longlong_t,
    645 		NULL, "fattr4_files_total" },
    646 
    647 	{ FATTR4_FS_LOCATIONS_MASK, 0, FALSE, FALSE,
    648 		FATTR4_FS_LOCATIONS, 0, xdr_fattr4_fs_locations,
    649 		NULL, "fattr4_fs_locations" },
    650 
    651 	{ FATTR4_HIDDEN_MASK, 0, FALSE, FALSE,
    652 		FATTR4_HIDDEN, BYTES_PER_XDR_UNIT, xdr_bool,
    653 		NULL, "fattr4_hidden" },
    654 
    655 	{ FATTR4_HOMOGENEOUS_MASK, 0, FALSE, FALSE,
    656 		FATTR4_HOMOGENEOUS, BYTES_PER_XDR_UNIT, xdr_bool,
    657 		NULL, "fattr4_homogeneous" },
    658 
    659 	{ FATTR4_MAXFILESIZE_MASK, 0, FALSE, FALSE,
    660 		FATTR4_MAXFILESIZE, 2 * BYTES_PER_XDR_UNIT, xdr_u_longlong_t,
    661 		NULL, "fattr4_maxfilesize" },
    662 
    663 	{ FATTR4_MAXLINK_MASK, 0, FALSE, FALSE,
    664 		FATTR4_MAXLINK, BYTES_PER_XDR_UNIT, xdr_u_int,
    665 		NULL, "fattr4_maxlink" },
    666 
    667 	{ FATTR4_MAXNAME_MASK, 0, FALSE, FALSE,
    668 		FATTR4_MAXNAME, BYTES_PER_XDR_UNIT, xdr_u_int,
    669 		NULL, "fattr4_maxname" },
    670 
    671 	{ FATTR4_MAXREAD_MASK, 0, FALSE, FALSE,
    672 		FATTR4_MAXREAD, 2 * BYTES_PER_XDR_UNIT, xdr_u_longlong_t,
    673 		NULL, "fattr4_maxread" },
    674 
    675 	{ FATTR4_MAXWRITE_MASK, 0, FALSE, FALSE,
    676 		FATTR4_MAXWRITE, 2 * BYTES_PER_XDR_UNIT, xdr_u_longlong_t,
    677 		NULL, "fattr4_maxwrite" },
    678 
    679 	{ FATTR4_MIMETYPE_MASK, 0, FALSE, FALSE,
    680 		FATTR4_MIMETYPE, 0, xdr_utf8string,
    681 		NULL, "fattr4_mimetype" },
    682 
    683 	{ FATTR4_MODE_MASK, AT_MODE, FALSE, FALSE,
    684 		FATTR4_MODE, BYTES_PER_XDR_UNIT, xdr_u_int,
    685 		NULL, "fattr4_mode" },
    686 
    687 	{ FATTR4_NO_TRUNC_MASK, 0, FALSE, FALSE,
    688 		FATTR4_NO_TRUNC, BYTES_PER_XDR_UNIT, xdr_bool,
    689 		NULL, "fattr4_no_trunc" },
    690 
    691 	{ FATTR4_NUMLINKS_MASK, AT_NLINK, FALSE, FALSE,
    692 		FATTR4_NUMLINKS, BYTES_PER_XDR_UNIT, xdr_u_int,
    693 		NULL, "fattr4_numlinks" },
    694 
    695 	{ FATTR4_OWNER_MASK, AT_UID, FALSE, FALSE,
    696 		FATTR4_OWNER, 0, xdr_utf8string,
    697 		NULL, "fattr4_owner" },
    698 
    699 	{ FATTR4_OWNER_GROUP_MASK, AT_GID, FALSE, FALSE,
    700 		FATTR4_OWNER_GROUP, 0, xdr_utf8string,
    701 		NULL, "fattr4_owner_group" },
    702 
    703 	{ FATTR4_QUOTA_AVAIL_HARD_MASK, 0, FALSE, FALSE,
    704 		FATTR4_QUOTA_AVAIL_HARD, 2 * BYTES_PER_XDR_UNIT,
    705 		xdr_u_longlong_t,
    706 		NULL, "fattr4_quota_avail_hard" },
    707 
    708 	{ FATTR4_QUOTA_AVAIL_SOFT_MASK, 0, FALSE, FALSE,
    709 		FATTR4_QUOTA_AVAIL_SOFT, 2 * BYTES_PER_XDR_UNIT,
    710 		xdr_u_longlong_t,
    711 		NULL, "fattr4_quota_avail_soft" },
    712 
    713 	{ FATTR4_QUOTA_USED_MASK, 0, FALSE, FALSE,
    714 		FATTR4_QUOTA_USED, 2 * BYTES_PER_XDR_UNIT, xdr_u_longlong_t,
    715 		NULL, "fattr4_quota_used" },
    716 
    717 	{ FATTR4_RAWDEV_MASK, AT_RDEV, FALSE, FALSE,
    718 		FATTR4_RAWDEV, 2 * BYTES_PER_XDR_UNIT, xdr_fattr4_rawdev,
    719 		NULL, "fattr4_rawdev" },
    720 
    721 	{ FATTR4_SPACE_AVAIL_MASK, 0, TRUE, FALSE,
    722 		FATTR4_SPACE_AVAIL, 2 * BYTES_PER_XDR_UNIT, xdr_u_longlong_t,
    723 		NULL, "fattr4_space_avail" },
    724 
    725 	{ FATTR4_SPACE_FREE_MASK, 0, TRUE, FALSE,
    726 		FATTR4_SPACE_FREE, 2 * BYTES_PER_XDR_UNIT, xdr_u_longlong_t,
    727 		NULL, "fattr4_space_free" },
    728 
    729 	{ FATTR4_SPACE_TOTAL_MASK, 0, TRUE, FALSE,
    730 		FATTR4_SPACE_TOTAL, 2 * BYTES_PER_XDR_UNIT, xdr_u_longlong_t,
    731 		NULL, "fattr4_space_total" },
    732 
    733 	{ FATTR4_SPACE_USED_MASK, AT_NBLOCKS, FALSE, FALSE,
    734 		FATTR4_SPACE_USED, 2 * BYTES_PER_XDR_UNIT, xdr_u_longlong_t,
    735 		NULL, "fattr4_space_used" },
    736 
    737 	{ FATTR4_SYSTEM_MASK, 0, FALSE, FALSE,
    738 		FATTR4_SYSTEM, BYTES_PER_XDR_UNIT, xdr_bool,
    739 		NULL, "fattr4_system" },
    740 
    741 	{ FATTR4_TIME_ACCESS_MASK, AT_ATIME, FALSE, FALSE,
    742 		FATTR4_TIME_ACCESS, 3 * BYTES_PER_XDR_UNIT, xdr_nfstime4,
    743 		NULL, "fattr4_time_access" },
    744 
    745 	{ FATTR4_TIME_ACCESS_SET_MASK, AT_ATIME, FALSE, FALSE,
    746 		FATTR4_TIME_ACCESS_SET, 4 * BYTES_PER_XDR_UNIT, xdr_settime4,
    747 		NULL, "fattr4_time_access_set" },
    748 
    749 	{ FATTR4_TIME_BACKUP_MASK, 0, FALSE, FALSE,
    750 		FATTR4_TIME_BACKUP, 3 * BYTES_PER_XDR_UNIT, xdr_nfstime4,
    751 		NULL, "fattr4_time_backup" },
    752 
    753 	{ FATTR4_TIME_CREATE_MASK, 0, FALSE, FALSE,
    754 		FATTR4_TIME_CREATE, 3 * BYTES_PER_XDR_UNIT, xdr_nfstime4,
    755 		NULL, "fattr4_time_create" },
    756 
    757 	{ FATTR4_TIME_DELTA_MASK, 0, FALSE, FALSE,
    758 		FATTR4_TIME_DELTA, 3 * BYTES_PER_XDR_UNIT, xdr_nfstime4,
    759 		NULL, "fattr4_time_delta" },
    760 
    761 	{ FATTR4_TIME_METADATA_MASK, AT_CTIME, FALSE, FALSE,
    762 		FATTR4_TIME_METADATA, 3 * BYTES_PER_XDR_UNIT, xdr_nfstime4,
    763 		NULL, "fattr4_time_metadata" },
    764 
    765 	{ FATTR4_TIME_MODIFY_MASK, AT_MTIME, FALSE, FALSE,
    766 		FATTR4_TIME_MODIFY, 3 * BYTES_PER_XDR_UNIT, xdr_nfstime4,
    767 		NULL, "fattr4_time_modify" },
    768 
    769 	{ FATTR4_TIME_MODIFY_SET_MASK, AT_MTIME, FALSE, FALSE,
    770 		FATTR4_TIME_MODIFY_SET, 4 * BYTES_PER_XDR_UNIT, xdr_settime4,
    771 		NULL, "fattr4_time_modify_set" },
    772 
    773 	{ FATTR4_MOUNTED_ON_FILEID_MASK, 0, FALSE, FALSE,
    774 		FATTR4_MOUNTED_ON_FILEID, 2 * BYTES_PER_XDR_UNIT,
    775 		xdr_u_longlong_t,
    776 		NULL, "fattr4_mounted_on_fileid" },
    777 
    778 };
    779 
    780 uint_t nfs4_ntov_map_size = sizeof (nfs4_ntov_map) /
    781 	sizeof (struct nfs4_ntov_map);
    782