xref: /illumos-gate/usr/src/uts/common/fs/nfs/nfs4_attr.c (revision 03100a6332bd4edc7a53091fcf7c9a7131bcdaa7)
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