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