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