xref: /illumos-gate/usr/src/uts/common/fs/nfs/nfs4_srv_attr.c (revision 4de2612967d06c4fdbf524a62556a1e8118a006f)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/systm.h>
30 #include <sys/cmn_err.h>
31 #include <nfs/nfs.h>
32 #include <nfs/export.h>
33 #include <nfs/nfs4.h>
34 #include <sys/ddi.h>
35 
36 void	rfs4_init_compound_state(struct compound_state *);
37 
38 bitmap4 rfs4_supported_attrs;
39 int MSG_PRT_DEBUG = FALSE;
40 
41 /* If building with DEBUG enabled, enable mandattr tuneable by default */
42 #ifdef DEBUG
43 #ifndef RFS4_SUPPORT_MANDATTR_ONLY
44 #define	RFS4_SUPPORT_MANDATTR_ONLY
45 #endif
46 #endif
47 
48 /*
49  * If building with mandattr only code, disable it by default.
50  * To enable, set rfs4_mandattr_only in /etc/system and reboot.
51  * When building without mandattr ifdef, the compiler should
52  * optimize away the the comparisons because RFS4_MANDATTR_ONLY
53  * is defined to be 0.
54  */
55 #ifdef RFS4_SUPPORT_MANDATTR_ONLY
56 #define	NFS4_LAST_MANDATTR FATTR4_RDATTR_ERROR
57 #define	RFS4_MANDATTR_ONLY rfs4_mandattr_only
58 int rfs4_mandattr_only = 0;
59 #else
60 #define	RFS4_MANDATTR_ONLY 0
61 #endif
62 
63 
64 static void rfs4_ntov_init(void);
65 static int rfs4_fattr4_supported_attrs();
66 static int rfs4_fattr4_type();
67 static int rfs4_fattr4_fh_expire_type();
68 static int rfs4_fattr4_change();
69 static int rfs4_fattr4_size();
70 static int rfs4_fattr4_link_support();
71 static int rfs4_fattr4_symlink_support();
72 static int rfs4_fattr4_named_attr();
73 static int rfs4_fattr4_fsid();
74 static int rfs4_fattr4_unique_handles();
75 static int rfs4_fattr4_lease_time();
76 static int rfs4_fattr4_rdattr_error();
77 static int rfs4_fattr4_acl();
78 static int rfs4_fattr4_aclsupport();
79 static int rfs4_fattr4_archive();
80 static int rfs4_fattr4_cansettime();
81 static int rfs4_fattr4_case_insensitive();
82 static int rfs4_fattr4_case_preserving();
83 static int rfs4_fattr4_chown_restricted();
84 static int rfs4_fattr4_filehandle();
85 static int rfs4_fattr4_fileid();
86 static int rfs4_fattr4_files_avail();
87 static int rfs4_fattr4_files_free();
88 static int rfs4_fattr4_files_total();
89 static int rfs4_fattr4_fs_locations();
90 static int rfs4_fattr4_hidden();
91 static int rfs4_fattr4_homogeneous();
92 static int rfs4_fattr4_maxfilesize();
93 static int rfs4_fattr4_maxlink();
94 static int rfs4_fattr4_maxname();
95 static int rfs4_fattr4_maxread();
96 static int rfs4_fattr4_maxwrite();
97 static int rfs4_fattr4_mimetype();
98 static int rfs4_fattr4_mode();
99 static int rfs4_fattr4_no_trunc();
100 static int rfs4_fattr4_numlinks();
101 static int rfs4_fattr4_owner();
102 static int rfs4_fattr4_owner_group();
103 static int rfs4_fattr4_quota_avail_hard();
104 static int rfs4_fattr4_quota_avail_soft();
105 static int rfs4_fattr4_quota_used();
106 static int rfs4_fattr4_rawdev();
107 static int rfs4_fattr4_space_avail();
108 static int rfs4_fattr4_space_free();
109 static int rfs4_fattr4_space_total();
110 static int rfs4_fattr4_space_used();
111 static int rfs4_fattr4_system();
112 static int rfs4_fattr4_time_access();
113 static int rfs4_fattr4_time_access_set();
114 static int rfs4_fattr4_time_backup();
115 static int rfs4_fattr4_time_create();
116 static int rfs4_fattr4_time_delta();
117 static int rfs4_fattr4_time_metadata();
118 static int rfs4_fattr4_time_modify();
119 static int rfs4_fattr4_time_modify_set();
120 
121 /*
122  * Initialize the supported attributes
123  */
124 void
125 rfs4_attr_init()
126 {
127 	int i;
128 	struct nfs4_svgetit_arg sarg;
129 	struct compound_state cs;
130 	struct statvfs64 sb;
131 
132 	rfs4_init_compound_state(&cs);
133 	cs.vp = rootvp;
134 	cs.fh.nfs_fh4_val = NULL;
135 	cs.cr = kcred;
136 
137 	/*
138 	 * Get all the supported attributes
139 	 */
140 	sarg.op = NFS4ATTR_SUPPORTED;
141 	sarg.cs = &cs;
142 	sarg.vap->va_mask = AT_ALL;
143 	sarg.sbp = &sb;
144 	sarg.flag = 0;
145 	sarg.rdattr_error = NFS4_OK;
146 	sarg.rdattr_error_req = FALSE;
147 
148 	rfs4_ntov_init();
149 
150 	rfs4_supported_attrs = 0;
151 	for (i = 0; i < NFS4_MAXNUM_ATTRS; i++) {
152 #ifdef RFS4_SUPPORT_MANDATTR_ONLY
153 		if (rfs4_mandattr_only == TRUE && i > NFS4_LAST_MANDATTR)
154 			continue;
155 #endif
156 		if ((*nfs4_ntov_map[i].sv_getit)(NFS4ATTR_SUPPORTED,
157 		    &sarg, NULL) == 0) {
158 			rfs4_supported_attrs |= nfs4_ntov_map[i].fbit;
159 		}
160 	}
161 }
162 
163 /*
164  * The following rfs4_fattr4_* functions convert between the fattr4
165  * arguments/attributes and the system (e.g. vattr) values. The following
166  * commands are currently in use:
167  *
168  * NFS4ATTR_SUPPORTED: checks if the attribute in question is supported:
169  *	sarg.op = SUPPORTED - all supported attrs
170  *	sarg.op = GETIT - only supported readable attrs
171  *	sarg.op = SETIT - only supported writable attrs
172  *
173  * NFS4ATTR_GETIT: getattr type conversion - convert system values
174  * (e.g. vattr struct) to fattr4 type values to be returned to the
175  * user - usually in response to nfsv4 getattr request.
176  *
177  * NFS4ATTR_SETIT: convert fattr4 type values to system values to use by
178  * setattr. Allows only read/write and write attributes,
179  * even if not supported by the filesystem. Note that ufs only allows setattr
180  * of owner/group, mode, size, atime/mtime.
181  *
182  * NFS4ATTR_VERIT: convert fattr4 type values to system values to use by
183  * verify/nverify. Implemented to allow
184  * almost everything that can be returned by getattr into known structs
185  * (like vfsstat64 or vattr_t), that is, both read only and read/write attrs.
186  * The function will return -1 if it found that the arguments don't match.
187  * This applies to system-wide values that don't require a VOP_GETATTR
188  * or other further checks to verify. It will return no error if they
189  * either match or were retrieved successfully for later checking.
190  *
191  * NFS4ATTR_FREEIT: free up any space allocated by either of the above.
192  * The sargp->op should be either NFS4ATTR_GETIT or NFS4ATTR_SETIT
193  * to indicate which op was used to allocate the space.
194  *
195  * XXX Note: these functions are currently used by the server only. A
196  * XXX different method of conversion is used on the client side.
197  * XXX Eventually combining the two (possibly by adding NFS4ATTR_CLNT_GETIT
198  * XXX and SETIT) may be a cleaner approach.
199  */
200 
201 /*
202  * Mandatory attributes
203  */
204 
205 /* ARGSUSED */
206 static int
207 rfs4_fattr4_supported_attrs(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
208 	union nfs4_attr_u *na)
209 {
210 	int	error = 0;
211 
212 	switch (cmd) {
213 	case NFS4ATTR_SUPPORTED:
214 		if (sarg->op == NFS4ATTR_SETIT)
215 			error = EINVAL;
216 		break;		/* this attr is supported */
217 	case NFS4ATTR_GETIT:
218 		na->supported_attrs = rfs4_supported_attrs;
219 		break;
220 	case NFS4ATTR_SETIT:
221 		/*
222 		 * read-only attr
223 		 */
224 		error = EINVAL;
225 		break;
226 	case NFS4ATTR_VERIT:
227 		/*
228 		 * Compare the input bitmap to the server's bitmap
229 		 */
230 		if (na->supported_attrs != rfs4_supported_attrs) {
231 			error = -1;	/* no match */
232 		}
233 		break;
234 	case NFS4ATTR_FREEIT:
235 		break;
236 	}
237 	return (error);
238 }
239 
240 /*
241  * Translate vnode vtype to nfsv4_ftype.
242  */
243 static nfs_ftype4 vt_to_nf4[] = {
244 	0, NF4REG, NF4DIR, NF4BLK, NF4CHR, NF4LNK, NF4FIFO, 0, 0, NF4SOCK, 0
245 };
246 
247 /* ARGSUSED */
248 static int
249 rfs4_fattr4_type(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
250 	union nfs4_attr_u *na)
251 {
252 	int		error = 0;
253 
254 	switch (cmd) {
255 	case NFS4ATTR_SUPPORTED:
256 		if (sarg->op == NFS4ATTR_SETIT)
257 			error = EINVAL;
258 		break;		/* this attr is supported */
259 	case NFS4ATTR_GETIT:
260 		if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_TYPE)) {
261 			error = -1;	/* may be okay if rdattr_error */
262 			break;
263 		}
264 		ASSERT(sarg->vap->va_mask & AT_TYPE);
265 
266 		/*
267 		 * if xattr flag not set, use v4_to_nf4 mapping;
268 		 * otherwise verify xattr flag is in sync with va_type
269 		 * and set xattr types.
270 		 */
271 		if (! (sarg->xattr & (FH4_NAMEDATTR | FH4_ATTRDIR)))
272 			na->type = vt_to_nf4[sarg->vap->va_type];
273 		else {
274 			/*
275 			 * FH4 flag was set.  Dir type maps to attrdir,
276 			 * and all other types map to namedattr.
277 			 */
278 			if (sarg->vap->va_type == VDIR)
279 				na->type = NF4ATTRDIR;
280 			else
281 				na->type = NF4NAMEDATTR;
282 		}
283 		break;
284 	case NFS4ATTR_SETIT:
285 		/*
286 		 * read-only attr
287 		 */
288 		error = EINVAL;
289 		break;
290 	case NFS4ATTR_VERIT:
291 		/*
292 		 * Compare the input type to the object type on server
293 		 */
294 		ASSERT(sarg->vap->va_mask & AT_TYPE);
295 		if (sarg->vap->va_type != nf4_to_vt[na->type])
296 			error = -1;	/* no match */
297 		break;
298 	case NFS4ATTR_FREEIT:
299 		break;
300 	}
301 	return (error);
302 }
303 
304 /* ARGSUSED */
305 static int
306 fattr4_get_fh_expire_type(struct exportinfo *exi, uint32_t *fh_expire_typep)
307 {
308 #ifdef	VOLATILE_FH_TEST
309 	int	ex_flags;
310 
311 	if (exi == NULL)
312 		return (ESTALE);
313 	ex_flags = exi->exi_export.ex_flags;
314 	if ((ex_flags & (EX_VOLFH | EX_VOLRNM | EX_VOLMIG | EX_NOEXPOPEN))
315 		== 0) {
316 		*fh_expire_typep = FH4_PERSISTENT;
317 		return (0);
318 	}
319 	*fh_expire_typep = 0;
320 
321 	if (ex_flags & EX_NOEXPOPEN) {
322 		/* file handles should not expire with open - not used */
323 		*fh_expire_typep = FH4_NOEXPIRE_WITH_OPEN;
324 	}
325 	if (ex_flags & EX_VOLFH) {
326 		/*
327 		 * file handles may expire any time - on share here.
328 		 * If volatile any, no need to check other flags.
329 		 */
330 		*fh_expire_typep |= FH4_VOLATILE_ANY;
331 		return (0);
332 	}
333 	if (ex_flags & EX_VOLRNM) {
334 		/* file handles may expire on rename */
335 		*fh_expire_typep |= FH4_VOL_RENAME;
336 	}
337 	if (ex_flags & EX_VOLMIG) {
338 		/* file handles may expire on migration - not used */
339 		*fh_expire_typep |= FH4_VOL_MIGRATION;
340 	}
341 #else	/* not VOLATILE_FH_TEST */
342 	*fh_expire_typep = FH4_PERSISTENT;
343 #endif	/* VOLATILE_FH_TEST */
344 
345 	return (0);
346 }
347 
348 /*
349  * At this point the only volatile filehandles we allow (for test purposes
350  * only) are either fh's that expire when the filesystem is shared (reshared),
351  * fh's that expire on a rename and persistent ones.
352  */
353 /* ARGSUSED */
354 static int
355 rfs4_fattr4_fh_expire_type(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
356 	union nfs4_attr_u *na)
357 {
358 	uint32_t fh_expire_type;
359 	int error = 0;
360 
361 	switch (cmd) {
362 	case NFS4ATTR_SUPPORTED:
363 		if (sarg->op == NFS4ATTR_SETIT)
364 			error = EINVAL;
365 		break;		/* this attr is supported */
366 	case NFS4ATTR_GETIT:
367 		error = fattr4_get_fh_expire_type(sarg->cs->exi,
368 				&na->fh_expire_type);
369 		break;
370 	case NFS4ATTR_SETIT:
371 		/*
372 		 * read-only attr
373 		 */
374 		error = EINVAL;
375 		break;
376 	case NFS4ATTR_VERIT:
377 		error = fattr4_get_fh_expire_type(sarg->cs->exi,
378 				&fh_expire_type);
379 		if (!error && (na->fh_expire_type != fh_expire_type))
380 			error = -1;	/* no match */
381 		break;
382 	case NFS4ATTR_FREEIT:
383 		break;
384 	}
385 	return (error);
386 }
387 
388 static int
389 fattr4_get_change(struct nfs4_svgetit_arg *sarg, fattr4_change *changep)
390 {
391 	vattr_t vap2[1], *vap = sarg->vap;
392 	struct compound_state *cs = sarg->cs;
393 	vnode_t *vp = cs->vp;
394 	nfsstat4 status;
395 
396 	if ((vap->va_mask & AT_CTIME) == 0) {
397 		if (sarg->rdattr_error && (vp == NULL)) {
398 			return (-1);	/* may be okay if rdattr_error */
399 		}
400 		ASSERT(vp != NULL);
401 		vap = vap2;
402 		vap->va_mask = AT_CTIME;
403 		status = rfs4_vop_getattr(vp, vap, 0, cs->cr);
404 		if (status != NFS4_OK)
405 			return (geterrno4(status));
406 	}
407 	NFS4_SET_FATTR4_CHANGE(*changep, vap->va_ctime)
408 	return (0);
409 }
410 
411 /* ARGSUSED */
412 static int
413 rfs4_fattr4_change(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
414 	union nfs4_attr_u *na)
415 {
416 	int error = 0;
417 	fattr4_change change;
418 	uint_t mask;
419 	vattr_t *vap = sarg->vap;
420 
421 	switch (cmd) {
422 	case NFS4ATTR_SUPPORTED:
423 		if (sarg->op == NFS4ATTR_SETIT)
424 			error = EINVAL;
425 		break;		/* this attr is supported */
426 	case NFS4ATTR_GETIT:
427 		error = fattr4_get_change(sarg, &na->change);
428 		break;
429 	case NFS4ATTR_SETIT:
430 		/*
431 		 * read-only attr
432 		 */
433 		error = EINVAL;
434 		break;
435 	case NFS4ATTR_VERIT:
436 		mask = vap->va_mask;
437 		vap->va_mask &= ~AT_CTIME;	/* force a VOP_GETATTR */
438 		error = fattr4_get_change(sarg, &change);
439 		vap->va_mask = mask;
440 		if (!error && (na->change != change))
441 			error = -1;
442 		break;
443 	case NFS4ATTR_FREEIT:
444 		break;
445 	}
446 	return (error);
447 }
448 
449 /* ARGSUSED */
450 static int
451 rfs4_fattr4_size(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
452 	union nfs4_attr_u *na)
453 {
454 	int	error = 0;
455 
456 	switch (cmd) {
457 	case NFS4ATTR_SUPPORTED:
458 		break;		/* this attr is supported */
459 	case NFS4ATTR_GETIT:
460 		if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_SIZE)) {
461 			error = -1;	/* may be okay if rdattr_error */
462 			break;
463 		}
464 		ASSERT(sarg->vap->va_mask & AT_SIZE);
465 		na->size = sarg->vap->va_size;
466 		break;
467 	case NFS4ATTR_SETIT:
468 		ASSERT(sarg->vap->va_mask & AT_SIZE);
469 		sarg->vap->va_size = na->size;
470 		break;
471 	case NFS4ATTR_VERIT:
472 		ASSERT(sarg->vap->va_mask & AT_SIZE);
473 		if (sarg->vap->va_size != na->size)
474 			error = -1;	/* no match */
475 		break;
476 	case NFS4ATTR_FREEIT:
477 		break;
478 	}
479 	return (error);
480 }
481 
482 /*
483  * XXX - need VOP extension to ask file system (e.g. pcfs) if it supports
484  * hard links.
485  */
486 /* ARGSUSED */
487 static int
488 rfs4_fattr4_link_support(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
489 	union nfs4_attr_u *na)
490 {
491 	int error = 0;
492 
493 	switch (cmd) {
494 	case NFS4ATTR_SUPPORTED:
495 		if (sarg->op == NFS4ATTR_SETIT)
496 			error = EINVAL;
497 		break;		/* this attr is supported */
498 	case NFS4ATTR_GETIT:
499 		na->link_support = TRUE;
500 		break;
501 	case NFS4ATTR_SETIT:
502 		/*
503 		 * read-only attr
504 		 */
505 		error = EINVAL;
506 		break;
507 	case NFS4ATTR_VERIT:
508 		if (!na->link_support)
509 			error = -1;	/* no match */
510 		break;
511 	case NFS4ATTR_FREEIT:
512 		break;
513 	}
514 	return (error);
515 }
516 
517 /*
518  * XXX - need VOP extension to ask file system (e.g. pcfs) if it supports
519  * sym links.
520  */
521 /* ARGSUSED */
522 static int
523 rfs4_fattr4_symlink_support(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
524 	union nfs4_attr_u *na)
525 {
526 	int error = 0;
527 
528 	switch (cmd) {
529 	case NFS4ATTR_SUPPORTED:
530 		if (sarg->op == NFS4ATTR_SETIT)
531 			error = EINVAL;
532 		break;		/* this attr is supported */
533 	case NFS4ATTR_GETIT:
534 		na->symlink_support = TRUE;
535 		break;
536 	case NFS4ATTR_SETIT:
537 		/*
538 		 * read-only attr
539 		 */
540 		error = EINVAL;
541 		break;
542 	case NFS4ATTR_VERIT:
543 		if (!na->symlink_support)
544 			error = -1;	/* no match */
545 		break;
546 	case NFS4ATTR_FREEIT:
547 		break;
548 	}
549 	return (error);
550 }
551 
552 /* ARGSUSED */
553 static int
554 rfs4_fattr4_named_attr(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
555 	union nfs4_attr_u *na)
556 {
557 	int error = 0;
558 	ulong_t val;
559 
560 	switch (cmd) {
561 	case NFS4ATTR_SUPPORTED:
562 		if (sarg->op == NFS4ATTR_SETIT)
563 			error = EINVAL;
564 		break;		/* this attr is supported */
565 	case NFS4ATTR_GETIT:
566 		if (sarg->rdattr_error && (sarg->cs->vp == NULL)) {
567 			error = -1;	/* may be okay if rdattr_error */
568 			break;
569 		}
570 		ASSERT(sarg->cs->vp != NULL);
571 
572 		/*
573 		 * Solaris xattr model requires that VFS_XATTR is set
574 		 * in file systems enabled for xattr.  If VFS_XATTR
575 		 * not set, no need to call pathconf.
576 		 */
577 		if (sarg->cs->vp->v_vfsp->vfs_flag & VFS_XATTR) {
578 			error = VOP_PATHCONF(sarg->cs->vp, _PC_XATTR_EXISTS,
579 					&val, sarg->cs->cr);
580 			if (error)
581 				break;
582 		} else
583 			val = 0;
584 		na->named_attr = (val ? TRUE : FALSE);
585 		break;
586 	case NFS4ATTR_SETIT:
587 		/*
588 		 * read-only attr
589 		 */
590 		error = EINVAL;
591 		break;
592 	case NFS4ATTR_VERIT:
593 		ASSERT(sarg->cs->vp != NULL);
594 		if (sarg->cs->vp->v_vfsp->vfs_flag & VFS_XATTR) {
595 			error = VOP_PATHCONF(sarg->cs->vp, _PC_XATTR_EXISTS,
596 					&val, sarg->cs->cr);
597 			if (error)
598 				break;
599 		} else
600 			val = 0;
601 		if (na->named_attr != (val ? TRUE : FALSE))
602 			error = -1;	/* no match */
603 		break;
604 	case NFS4ATTR_FREEIT:
605 		break;
606 	}
607 	return (error);
608 }
609 
610 /* ARGSUSED */
611 static int
612 rfs4_fattr4_fsid(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
613 	union nfs4_attr_u *na)
614 {
615 	int error = 0;
616 	int *pmaj = (int *)&na->fsid.major;
617 
618 	/*
619 	 * fsid_t is 64bits so it fits completely in fattr4_fsid.major.
620 	 * fattr4_fsid.minor is always set to 0 since it isn't needed (yet).
621 	 */
622 	switch (cmd) {
623 	case NFS4ATTR_SUPPORTED:
624 		if (sarg->op == NFS4ATTR_SETIT)
625 			error = EINVAL;
626 		break;		/* this attr is supported */
627 	case NFS4ATTR_GETIT:
628 		if (sarg->cs->exi->exi_volatile_dev) {
629 			pmaj[0] = sarg->cs->exi->exi_fsid.val[0];
630 			pmaj[1] = sarg->cs->exi->exi_fsid.val[1];
631 			na->fsid.minor = 0;
632 		} else {
633 			na->fsid.major = getmajor(sarg->vap->va_fsid);
634 			na->fsid.minor = getminor(sarg->vap->va_fsid);
635 		}
636 		break;
637 	case NFS4ATTR_SETIT:
638 		error = EINVAL;
639 		break;
640 	case NFS4ATTR_VERIT:
641 		if (sarg->cs->exi->exi_volatile_dev) {
642 			if (pmaj[0] != sarg->cs->exi->exi_fsid.val[0] ||
643 			    pmaj[1] != sarg->cs->exi->exi_fsid.val[1] ||
644 			    na->fsid.minor != 0)
645 				error = -1;
646 		} else {
647 			if (na->fsid.major != getmajor(sarg->vap->va_fsid) ||
648 			    na->fsid.minor != getminor(sarg->vap->va_fsid))
649 				error = -1;
650 		}
651 		break;
652 	case NFS4ATTR_FREEIT:
653 		break;
654 	}
655 	return (error);
656 }
657 
658 /* ARGSUSED */
659 static int
660 rfs4_fattr4_unique_handles(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
661 	union nfs4_attr_u *na)
662 {
663 	/*
664 	 * XXX
665 	 * For now, we can't support this. Problem of /export, beinging
666 	 * a file system, /export/a and /export/b shared separately,
667 	 * and /export/a/l and /export/b/l are ahrd links of each other.
668 	 */
669 	int error = 0;
670 
671 	switch (cmd) {
672 	case NFS4ATTR_SUPPORTED:
673 		if (sarg->op == NFS4ATTR_SETIT)
674 			error = EINVAL;
675 		break;		/* this attr is supported */
676 	case NFS4ATTR_GETIT:
677 		na->unique_handles = FALSE;
678 		break;
679 	case NFS4ATTR_SETIT:
680 		/*
681 		 * read-only attr
682 		 */
683 		error = EINVAL;
684 		break;
685 	case NFS4ATTR_VERIT:
686 		if (na->unique_handles)
687 			error = -1;	/* no match */
688 		break;
689 	case NFS4ATTR_FREEIT:
690 		break;
691 	}
692 	return (error);
693 }
694 
695 /* ARGSUSED */
696 static int
697 rfs4_fattr4_lease_time(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
698 	union nfs4_attr_u *na)
699 {
700 	int error = 0;
701 
702 	switch (cmd) {
703 	case NFS4ATTR_SUPPORTED:
704 		if (sarg->op == NFS4ATTR_SETIT)
705 			error = EINVAL;
706 		break;		/* this attr is supported */
707 	case NFS4ATTR_GETIT:
708 		na->lease_time = rfs4_lease_time;
709 		break;
710 	case NFS4ATTR_SETIT:
711 		/*
712 		 * read-only attr
713 		 */
714 		error = EINVAL;
715 		break;
716 	case NFS4ATTR_VERIT:
717 		if (na->lease_time != rfs4_lease_time)
718 			error = -1;	/* no match */
719 		break;
720 	case NFS4ATTR_FREEIT:
721 		break;
722 	}
723 	return (error);
724 }
725 
726 /* ARGSUSED */
727 static int
728 rfs4_fattr4_rdattr_error(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
729 	union nfs4_attr_u *na)
730 {
731 	int error = 0;
732 
733 	switch (cmd) {
734 	case NFS4ATTR_SUPPORTED:
735 		if ((sarg->op == NFS4ATTR_SETIT) ||
736 			(sarg->op == NFS4ATTR_VERIT))
737 			error = EINVAL;
738 		break;		/* this attr is supported */
739 	case NFS4ATTR_GETIT:
740 		ASSERT(sarg->rdattr_error_req);
741 		na->rdattr_error = sarg->rdattr_error;
742 		break;
743 	case NFS4ATTR_SETIT:
744 	case NFS4ATTR_VERIT:
745 		/*
746 		 * read-only attr
747 		 */
748 		error = EINVAL;
749 		break;
750 	case NFS4ATTR_FREEIT:
751 		break;
752 	}
753 	return (error);
754 }
755 
756 /* ARGSUSED */
757 static int
758 rfs4_fattr4_filehandle(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
759 	union nfs4_attr_u *na)
760 {
761 	int error = 0;
762 	nfs_fh4 *fh;
763 
764 	switch (cmd) {
765 	case NFS4ATTR_SUPPORTED:
766 		if (sarg->op == NFS4ATTR_SETIT)
767 			error = EINVAL;
768 		break;		/* this attr is supported */
769 	case NFS4ATTR_GETIT:
770 		/*
771 		 * If sarg->cs->fh is all zeros then should makefh a new
772 		 * one, otherwise, copy that one over.
773 		 */
774 		fh = &sarg->cs->fh;
775 		if (sarg->cs->fh.nfs_fh4_len == 0) {
776 			if (sarg->rdattr_error && (sarg->cs->vp == NULL)) {
777 				error = -1;	/* okay if rdattr_error */
778 				break;
779 			}
780 			ASSERT(sarg->cs->vp != NULL);
781 			na->filehandle.nfs_fh4_val =
782 				kmem_alloc(NFS_FH4_LEN, KM_SLEEP);
783 			error = makefh4(&na->filehandle, sarg->cs->vp,
784 					sarg->cs->exi);
785 		} else {
786 			na->filehandle.nfs_fh4_val =
787 				kmem_alloc(fh->nfs_fh4_len, KM_SLEEP);
788 			nfs_fh4_copy(fh, &na->filehandle);
789 		}
790 		break;
791 	case NFS4ATTR_SETIT:
792 		/*
793 		 * read-only attr
794 		 */
795 		error = EINVAL;
796 		break;
797 	case NFS4ATTR_VERIT:
798 		if (nfs4cmpfh(&na->filehandle, &sarg->cs->fh))
799 			error = -1;	/* no match */
800 		break;
801 	case NFS4ATTR_FREEIT:
802 		if (sarg->op == NFS4ATTR_GETIT) {
803 			if (na->filehandle.nfs_fh4_val) {
804 				kmem_free(na->filehandle.nfs_fh4_val,
805 					na->filehandle.nfs_fh4_len);
806 				bzero(&na->filehandle, sizeof (na->filehandle));
807 			}
808 		}
809 		break;
810 	}
811 	return (error);
812 }
813 
814 /*
815  * Recommended attributes
816  */
817 
818 /* ARGSUSED */
819 static int
820 rfs4_fattr4_acl(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
821 	union nfs4_attr_u *na)
822 {
823 	int error = 0;
824 	vsecattr_t vs_native, vs_ace4;
825 	ulong_t whichacl;
826 	nfsstat4 status;
827 	vattr_t va, *vap = sarg->vap;
828 	vnode_t *vp = sarg->cs->vp;
829 
830 	if (RFS4_MANDATTR_ONLY)
831 		return (ENOTSUP);
832 
833 	switch (cmd) {
834 	case NFS4ATTR_SUPPORTED:
835 		break;
836 
837 	case NFS4ATTR_VERIT:
838 	case NFS4ATTR_GETIT:
839 		if (sarg->rdattr_error && (vp == NULL)) {
840 			return (-1);
841 		}
842 		ASSERT(vp != NULL);
843 		bzero(&vs_native, sizeof (vs_native));
844 
845 		/* see which ACLs fs supports */
846 		error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &whichacl,
847 		    sarg->cs->cr);
848 		if (error != 0) {
849 			/*
850 			 * If we got an error, then the filesystem
851 			 * likely does not understand the _PC_ACL_ENABLED
852 			 * pathconf.  In this case, we fall back to trying
853 			 * POSIX-draft (aka UFS-style) ACLs, since that's
854 			 * the behavior used by earlier version of NFS.
855 			 */
856 			error = 0;
857 			whichacl = _ACL_ACLENT_ENABLED;
858 		}
859 
860 		if (!(whichacl & (_ACL_ACE_ENABLED | _ACL_ACLENT_ENABLED))) {
861 			/*
862 			 * If the file system supports neither ACE nor
863 			 * ACLENT ACLs we will fall back to UFS-style ACLs
864 			 * like we did above if there was an error upon
865 			 * calling VOP_PATHCONF.
866 			 *
867 			 * ACE and ACLENT type ACLs are the only interfaces
868 			 * supported thus far.  If any other bits are set on
869 			 * 'whichacl' upon return from VOP_PATHCONF, we will
870 			 * ignore them.
871 			 */
872 			whichacl = _ACL_ACLENT_ENABLED;
873 		}
874 
875 		if (whichacl & _ACL_ACE_ENABLED)
876 			vs_native.vsa_mask = VSA_ACE | VSA_ACECNT;
877 		else if (whichacl & _ACL_ACLENT_ENABLED)
878 			vs_native.vsa_mask = VSA_ACL | VSA_ACLCNT |
879 			    VSA_DFACL | VSA_DFACLCNT;
880 
881 		if (error != 0)
882 			break;
883 
884 		/* get the ACL, and translate it into nfsace4 style */
885 		error = VOP_GETSECATTR(vp, &vs_native,
886 		    0, sarg->cs->cr);
887 		if (error != 0)
888 			break;
889 		if (whichacl & _ACL_ACE_ENABLED) {
890 			error = vs_acet_to_ace4(&vs_native, &vs_ace4, TRUE);
891 			vs_acet_destroy(&vs_native);
892 		} else {
893 			error = vs_aent_to_ace4(&vs_native, &vs_ace4,
894 			    vp->v_type == VDIR, TRUE);
895 			vs_aent_destroy(&vs_native);
896 		}
897 		if (error != 0)
898 			break;
899 
900 		if (cmd == NFS4ATTR_GETIT) {
901 			na->acl.fattr4_acl_len = vs_ace4.vsa_aclcnt;
902 			/* see case NFS4ATTR_FREEIT for this being freed */
903 			na->acl.fattr4_acl_val = vs_ace4.vsa_aclentp;
904 		} else {
905 			if (na->acl.fattr4_acl_len != vs_ace4.vsa_aclcnt)
906 				error = -1; /* no match */
907 			else if (ln_ace4_cmp(na->acl.fattr4_acl_val,
908 			    vs_ace4.vsa_aclentp,
909 			    vs_ace4.vsa_aclcnt) != 0)
910 				error = -1; /* no match */
911 		}
912 
913 		break;
914 
915 	case NFS4ATTR_SETIT:
916 		if (sarg->rdattr_error && (vp == NULL)) {
917 			return (-1);
918 		}
919 		ASSERT(vp != NULL);
920 
921 		/* prepare vs_ace4 from fattr4 data */
922 		bzero(&vs_ace4, sizeof (vs_ace4));
923 		vs_ace4.vsa_mask = VSA_ACE | VSA_ACECNT;
924 		vs_ace4.vsa_aclcnt = na->acl.fattr4_acl_len;
925 		vs_ace4.vsa_aclentp = na->acl.fattr4_acl_val;
926 
927 		/* make sure we have correct owner/group */
928 		if ((vap->va_mask & (AT_UID | AT_GID)) !=
929 		    (AT_UID | AT_GID)) {
930 			vap = &va;
931 			vap->va_mask = AT_UID | AT_GID;
932 			status = rfs4_vop_getattr(vp,
933 			    vap, 0, sarg->cs->cr);
934 			if (status != NFS4_OK)
935 				return (geterrno4(status));
936 		}
937 
938 		/* see which ACLs the fs supports */
939 		error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &whichacl,
940 		    sarg->cs->cr);
941 		if (error != 0) {
942 			/*
943 			 * If we got an error, then the filesystem
944 			 * likely does not understand the _PC_ACL_ENABLED
945 			 * pathconf.  In this case, we fall back to trying
946 			 * POSIX-draft (aka UFS-style) ACLs, since that's
947 			 * the behavior used by earlier version of NFS.
948 			 */
949 			error = 0;
950 			whichacl = _ACL_ACLENT_ENABLED;
951 		}
952 
953 		if (!(whichacl & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED))) {
954 			/*
955 			 * If the file system supports neither ACE nor
956 			 * ACLENT ACLs we will fall back to UFS-style ACLs
957 			 * like we did above if there was an error upon
958 			 * calling VOP_PATHCONF.
959 			 *
960 			 * ACE and ACLENT type ACLs are the only interfaces
961 			 * supported thus far.  If any other bits are set on
962 			 * 'whichacl' upon return from VOP_PATHCONF, we will
963 			 * ignore them.
964 			 */
965 			whichacl = _ACL_ACLENT_ENABLED;
966 		}
967 
968 		if (whichacl & _ACL_ACE_ENABLED) {
969 			error = vs_ace4_to_acet(&vs_ace4, &vs_native,
970 			    vap->va_uid, vap->va_gid, TRUE, FALSE);
971 			if (error != 0)
972 				break;
973 			(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
974 			error = VOP_SETSECATTR(vp, &vs_native,
975 			    0, sarg->cs->cr);
976 			VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
977 			vs_acet_destroy(&vs_native);
978 		} else if (whichacl & _ACL_ACLENT_ENABLED) {
979 			error = vs_ace4_to_aent(&vs_ace4, &vs_native,
980 			    vap->va_uid, vap->va_gid, vp->v_type == VDIR, TRUE,
981 			    FALSE);
982 			if (error != 0)
983 				break;
984 			(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
985 			error = VOP_SETSECATTR(vp, &vs_native,
986 			    0, sarg->cs->cr);
987 			VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
988 			vs_aent_destroy(&vs_native);
989 		}
990 		break;
991 
992 	case NFS4ATTR_FREEIT:
993 		if (sarg->op == NFS4ATTR_GETIT) {
994 			vs_ace4.vsa_mask = VSA_ACE | VSA_ACECNT;
995 			vs_ace4.vsa_aclcnt = na->acl.fattr4_acl_len;
996 			vs_ace4.vsa_aclentp = na->acl.fattr4_acl_val;
997 			vs_ace4_destroy(&vs_ace4);
998 		}
999 		break;
1000 	}
1001 
1002 	return (error);
1003 }
1004 
1005 /* ARGSUSED */
1006 static int
1007 rfs4_fattr4_aclsupport(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1008 	union nfs4_attr_u *na)
1009 {
1010 	int error = 0;
1011 
1012 	if (RFS4_MANDATTR_ONLY)
1013 		return (ENOTSUP);
1014 
1015 	switch (cmd) {
1016 	case NFS4ATTR_SUPPORTED:
1017 		if (sarg->op == NFS4ATTR_SETIT)
1018 			error = EINVAL;
1019 		break;	/* supported */
1020 	case NFS4ATTR_GETIT:
1021 		na->aclsupport = ACL4_SUPPORT_ALLOW_ACL |
1022 		    ACL4_SUPPORT_DENY_ACL;
1023 		break;
1024 	case NFS4ATTR_SETIT:
1025 		error = EINVAL;
1026 		break;
1027 	case NFS4ATTR_VERIT:
1028 		if (na->aclsupport != (ACL4_SUPPORT_ALLOW_ACL |
1029 		    ACL4_SUPPORT_DENY_ACL))
1030 			error = -1;	/* no match */
1031 		break;
1032 	}
1033 
1034 	return (error);
1035 }
1036 
1037 /* ARGSUSED */
1038 static int
1039 rfs4_fattr4_archive(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1040 	union nfs4_attr_u *na)
1041 {
1042 	return (ENOTSUP);
1043 }
1044 
1045 /* ARGSUSED */
1046 static int
1047 rfs4_fattr4_cansettime(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1048 	union nfs4_attr_u *na)
1049 {
1050 	int error = 0;
1051 
1052 	if (RFS4_MANDATTR_ONLY)
1053 		return (ENOTSUP);
1054 
1055 	switch (cmd) {
1056 	case NFS4ATTR_SUPPORTED:
1057 		if (sarg->op == NFS4ATTR_SETIT)
1058 			error = EINVAL;
1059 		break;		/* this attr is supported */
1060 	case NFS4ATTR_GETIT:
1061 		na->cansettime = TRUE;
1062 		break;
1063 	case NFS4ATTR_SETIT:
1064 		/*
1065 		 * read-only attr
1066 		 */
1067 		error = EINVAL;
1068 		break;
1069 	case NFS4ATTR_VERIT:
1070 		if (!na->cansettime)
1071 			error = -1;	/* no match */
1072 		break;
1073 	case NFS4ATTR_FREEIT:
1074 		break;
1075 	}
1076 	return (error);
1077 }
1078 
1079 /*
1080  * XXX - need VOP extension to ask file system (e.g. pcfs) if it supports
1081  * case insenstive.
1082  */
1083 /* ARGSUSED */
1084 static int
1085 rfs4_fattr4_case_insensitive(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1086 	union nfs4_attr_u *na)
1087 {
1088 	int error = 0;
1089 
1090 	if (RFS4_MANDATTR_ONLY)
1091 		return (ENOTSUP);
1092 
1093 	switch (cmd) {
1094 	case NFS4ATTR_SUPPORTED:
1095 		if (sarg->op == NFS4ATTR_SETIT)
1096 			error = EINVAL;
1097 		break;		/* this attr is supported */
1098 	case NFS4ATTR_GETIT:
1099 		na->case_insensitive = FALSE;
1100 		break;
1101 	case NFS4ATTR_SETIT:
1102 		/*
1103 		 * read-only attr
1104 		 */
1105 		error = EINVAL;
1106 		break;
1107 	case NFS4ATTR_VERIT:
1108 		if (!na->case_insensitive)
1109 			error = -1;	/* no match */
1110 		break;
1111 	case NFS4ATTR_FREEIT:
1112 		break;
1113 	}
1114 	return (error);
1115 }
1116 
1117 /* ARGSUSED */
1118 static int
1119 rfs4_fattr4_case_preserving(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1120 	union nfs4_attr_u *na)
1121 {
1122 	int error = 0;
1123 
1124 	if (RFS4_MANDATTR_ONLY)
1125 		return (ENOTSUP);
1126 
1127 	switch (cmd) {
1128 	case NFS4ATTR_SUPPORTED:
1129 		if (sarg->op == NFS4ATTR_SETIT)
1130 			error = EINVAL;
1131 		break;		/* this attr is supported */
1132 	case NFS4ATTR_GETIT:
1133 		na->case_preserving = TRUE;
1134 		break;
1135 	case NFS4ATTR_SETIT:
1136 		/*
1137 		 * read-only attr
1138 		 */
1139 		error = EINVAL;
1140 		break;
1141 	case NFS4ATTR_VERIT:
1142 		if (!na->case_preserving)
1143 			error = -1;	/* no match */
1144 		break;
1145 	case NFS4ATTR_FREEIT:
1146 		break;
1147 	}
1148 	return (error);
1149 }
1150 
1151 /* fattr4_chown_restricted should reall be fattr4_chown_allowed */
1152 /* ARGSUSED */
1153 static int
1154 rfs4_fattr4_chown_restricted(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1155 	union nfs4_attr_u *na)
1156 {
1157 	int error = 0;
1158 	ulong_t val;
1159 
1160 	if (RFS4_MANDATTR_ONLY)
1161 		return (ENOTSUP);
1162 
1163 	switch (cmd) {
1164 	case NFS4ATTR_SUPPORTED:
1165 		if (sarg->op == NFS4ATTR_SETIT)
1166 			error = EINVAL;
1167 		break;		/* this attr is supported */
1168 	case NFS4ATTR_GETIT:
1169 		if (sarg->rdattr_error && (sarg->cs->vp == NULL)) {
1170 			error = -1;	/* may be okay if rdattr_error */
1171 			break;
1172 		}
1173 		ASSERT(sarg->cs->vp != NULL);
1174 		error = VOP_PATHCONF(sarg->cs->vp,
1175 				_PC_CHOWN_RESTRICTED, &val, sarg->cs->cr);
1176 		if (error)
1177 			break;
1178 
1179 		na->chown_restricted = (val == 1);
1180 		break;
1181 	case NFS4ATTR_SETIT:
1182 		/*
1183 		 * read-only attr
1184 		 */
1185 		error = EINVAL;
1186 		break;
1187 	case NFS4ATTR_VERIT:
1188 		ASSERT(sarg->cs->vp != NULL);
1189 		error = VOP_PATHCONF(sarg->cs->vp,
1190 				_PC_CHOWN_RESTRICTED, &val, sarg->cs->cr);
1191 		if (error)
1192 			break;
1193 		if (na->chown_restricted != (val == 1))
1194 			error = -1;	/* no match */
1195 		break;
1196 	case NFS4ATTR_FREEIT:
1197 		break;
1198 	}
1199 	return (error);
1200 }
1201 
1202 /* ARGSUSED */
1203 static int
1204 rfs4_fattr4_fileid(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1205 	union nfs4_attr_u *na)
1206 {
1207 	int	error = 0;
1208 
1209 	if (RFS4_MANDATTR_ONLY)
1210 		return (ENOTSUP);
1211 
1212 	switch (cmd) {
1213 	case NFS4ATTR_SUPPORTED:
1214 		if (sarg->op == NFS4ATTR_SETIT)
1215 			error = EINVAL;
1216 		break;		/* this attr is supported */
1217 	case NFS4ATTR_GETIT:
1218 		if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_NODEID)) {
1219 			error = -1;	/* may be okay if rdattr_error */
1220 			break;
1221 		}
1222 		ASSERT(sarg->vap->va_mask & AT_NODEID);
1223 		na->fileid = sarg->vap->va_nodeid;
1224 		break;
1225 	case NFS4ATTR_SETIT:
1226 		/*
1227 		 * read-only attr
1228 		 */
1229 		error = EINVAL;
1230 		break;
1231 	case NFS4ATTR_VERIT:
1232 		ASSERT(sarg->vap->va_mask & AT_NODEID);
1233 		if (sarg->vap->va_nodeid != na->fileid)
1234 			error = -1;	/* no match */
1235 		break;
1236 	case NFS4ATTR_FREEIT:
1237 		break;
1238 	}
1239 	return (error);
1240 }
1241 
1242 /* ARGSUSED */
1243 static int
1244 rfs4_get_mntdfileid(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg)
1245 {
1246 	int error = 0;
1247 	vattr_t	*vap, va;
1248 	vnode_t *stubvp = NULL, *vp;
1249 
1250 	vp = sarg->cs->vp;
1251 	sarg->mntdfid_set = FALSE;
1252 
1253 	/* VROOT object, must untraverse */
1254 	if (vp->v_flag & VROOT) {
1255 
1256 		/* extra hold for vp since untraverse might rele */
1257 		VN_HOLD(vp);
1258 		stubvp = untraverse(vp);
1259 
1260 		/*
1261 		 * If vp/stubvp are same, we must be at system
1262 		 * root because untraverse returned same vp
1263 		 * for a VROOT object.  sarg->vap was setup
1264 		 * before we got here, so there's no need to do
1265 		 * another getattr -- just use the one in sarg.
1266 		 */
1267 		if (VN_CMP(vp, stubvp)) {
1268 			ASSERT(VN_CMP(vp, rootdir));
1269 			vap = sarg->vap;
1270 		} else {
1271 			va.va_mask = AT_NODEID;
1272 			vap = &va;
1273 			error = rfs4_vop_getattr(stubvp, vap, 0, sarg->cs->cr);
1274 		}
1275 
1276 		/*
1277 		 * Done with stub, time to rele.  If vp and stubvp
1278 		 * were the same, then we need to rele either vp or
1279 		 * stubvp.  If they weren't the same, then untraverse()
1280 		 * already took case of the extra hold on vp, and only
1281 		 * the stub needs to be rele'd.  Both cases are handled
1282 		 * by unconditionally rele'ing the stub.
1283 		 */
1284 		VN_RELE(stubvp);
1285 	} else
1286 		vap = sarg->vap;
1287 
1288 	/*
1289 	 * At this point, vap should contain "correct" AT_NODEID --
1290 	 * (for V_ROOT case, nodeid of stub, for non-VROOT case,
1291 	 * nodeid of vp).  If error or AT_NODEID not available, then
1292 	 * make the obligatory (yet mysterious) rdattr_error
1293 	 * check that is so common in the attr code.
1294 	 */
1295 	if (!error && (vap->va_mask & AT_NODEID)) {
1296 		sarg->mounted_on_fileid = vap->va_nodeid;
1297 		sarg->mntdfid_set = TRUE;
1298 	} else if (sarg->rdattr_error)
1299 		error = -1;
1300 
1301 	/*
1302 	 * error describes these cases:
1303 	 *	0 : success
1304 	 *	-1: failure due to previous attr processing error (rddir only).
1305 	 *	* : new attr failure  (if rddir, caller will set rdattr_error)
1306 	 */
1307 	return (error);
1308 }
1309 
1310 /* ARGSUSED */
1311 static int
1312 rfs4_fattr4_mounted_on_fileid(nfs4_attr_cmd_t cmd,
1313 	struct nfs4_svgetit_arg *sarg, union nfs4_attr_u *na)
1314 {
1315 	int	error = 0;
1316 
1317 	if (RFS4_MANDATTR_ONLY)
1318 		return (ENOTSUP);
1319 
1320 	switch (cmd) {
1321 	case NFS4ATTR_SUPPORTED:
1322 		if (sarg->op == NFS4ATTR_SETIT)
1323 			error = EINVAL;
1324 		break;		/* this attr is supported */
1325 	case NFS4ATTR_GETIT:
1326 	case NFS4ATTR_VERIT:
1327 		if (! sarg->mntdfid_set)
1328 			error = rfs4_get_mntdfileid(cmd, sarg);
1329 
1330 		if (! error && sarg->mntdfid_set) {
1331 			if (cmd == NFS4ATTR_GETIT)
1332 				na->mounted_on_fileid = sarg->mounted_on_fileid;
1333 			else
1334 				if (na->mounted_on_fileid !=
1335 				    sarg->mounted_on_fileid)
1336 					error = -1;
1337 		}
1338 		break;
1339 	case NFS4ATTR_SETIT:
1340 		/* read-only attr */
1341 		error = EINVAL;
1342 		break;
1343 	case NFS4ATTR_FREEIT:
1344 		break;
1345 	}
1346 	return (error);
1347 }
1348 
1349 /* ARGSUSED */
1350 static int
1351 rfs4_fattr4_files_avail(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1352 	union nfs4_attr_u *na)
1353 {
1354 	int	error = 0;
1355 
1356 	if (RFS4_MANDATTR_ONLY)
1357 		return (ENOTSUP);
1358 
1359 	switch (cmd) {
1360 	case NFS4ATTR_SUPPORTED:
1361 		if (sarg->op == NFS4ATTR_SETIT)
1362 			error = EINVAL;
1363 		break;		/* this attr is supported */
1364 	case NFS4ATTR_GETIT:
1365 		if (sarg->rdattr_error && (sarg->sbp == NULL)) {
1366 			error = -1;	/* may be okay if rdattr_error */
1367 			break;
1368 		}
1369 		ASSERT(sarg->sbp != NULL);
1370 		na->files_avail = sarg->sbp->f_favail;
1371 		break;
1372 	case NFS4ATTR_SETIT:
1373 		/*
1374 		 * read-only attr
1375 		 */
1376 		error = EINVAL;
1377 		break;
1378 	case NFS4ATTR_VERIT:
1379 		ASSERT(sarg->sbp != NULL);
1380 		if (sarg->sbp->f_favail != na->files_avail)
1381 			error = -1;	/* no match */
1382 		break;
1383 	case NFS4ATTR_FREEIT:
1384 		break;
1385 	}
1386 	return (error);
1387 }
1388 
1389 /* ARGSUSED */
1390 static int
1391 rfs4_fattr4_files_free(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1392 	union nfs4_attr_u *na)
1393 {
1394 	int	error = 0;
1395 
1396 	if (RFS4_MANDATTR_ONLY)
1397 		return (ENOTSUP);
1398 
1399 	switch (cmd) {
1400 	case NFS4ATTR_SUPPORTED:
1401 		if (sarg->op == NFS4ATTR_SETIT)
1402 			error = EINVAL;
1403 		break;		/* this attr is supported */
1404 	case NFS4ATTR_GETIT:
1405 		if (sarg->rdattr_error && (sarg->sbp == NULL)) {
1406 			error = -1;	/* may be okay if rdattr_error */
1407 			break;
1408 		}
1409 		ASSERT(sarg->sbp != NULL);
1410 		na->files_free = sarg->sbp->f_ffree;
1411 		break;
1412 	case NFS4ATTR_SETIT:
1413 		/*
1414 		 * read-only attr
1415 		 */
1416 		error = EINVAL;
1417 		break;
1418 	case NFS4ATTR_VERIT:
1419 		ASSERT(sarg->sbp != NULL);
1420 		if (sarg->sbp->f_ffree != na->files_free)
1421 			error = -1;	/* no match */
1422 		break;
1423 	case NFS4ATTR_FREEIT:
1424 		break;
1425 	}
1426 	return (error);
1427 }
1428 
1429 /* ARGSUSED */
1430 static int
1431 rfs4_fattr4_files_total(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1432 	union nfs4_attr_u *na)
1433 {
1434 	int	error = 0;
1435 
1436 	if (RFS4_MANDATTR_ONLY)
1437 		return (ENOTSUP);
1438 
1439 	switch (cmd) {
1440 	case NFS4ATTR_SUPPORTED:
1441 		if (sarg->op == NFS4ATTR_SETIT)
1442 			error = EINVAL;
1443 		break;		/* this attr is supported */
1444 	case NFS4ATTR_GETIT:
1445 		if (sarg->rdattr_error && (sarg->sbp == NULL)) {
1446 			error = -1;	/* may be okay if rdattr_error */
1447 			break;
1448 		}
1449 		ASSERT(sarg->sbp != NULL);
1450 		na->files_total = sarg->sbp->f_files;
1451 		break;
1452 	case NFS4ATTR_SETIT:
1453 		/*
1454 		 * read-only attr
1455 		 */
1456 		error = EINVAL;
1457 		break;
1458 	case NFS4ATTR_VERIT:
1459 		ASSERT(sarg->sbp != NULL);
1460 		if (sarg->sbp->f_files != na->files_total)
1461 			error = -1;	/* no match */
1462 		break;
1463 	case NFS4ATTR_FREEIT:
1464 		break;
1465 	}
1466 	return (error);
1467 }
1468 
1469 /* ARGSUSED */
1470 static int
1471 rfs4_fattr4_fs_locations(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1472 	union nfs4_attr_u *na)
1473 {
1474 	return (ENOTSUP);
1475 }
1476 
1477 /* ARGSUSED */
1478 static int
1479 rfs4_fattr4_hidden(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1480 	union nfs4_attr_u *na)
1481 {
1482 	return (ENOTSUP);
1483 }
1484 
1485 /* ARGSUSED */
1486 static int
1487 rfs4_fattr4_homogeneous(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1488 	union nfs4_attr_u *na)
1489 {
1490 	int error = 0;
1491 
1492 	if (RFS4_MANDATTR_ONLY)
1493 		return (ENOTSUP);
1494 
1495 	switch (cmd) {
1496 	case NFS4ATTR_SUPPORTED:
1497 		if (sarg->op == NFS4ATTR_SETIT)
1498 			error = EINVAL;
1499 		break;		/* this attr is supported */
1500 	case NFS4ATTR_GETIT:
1501 		na->homogeneous = TRUE; /* XXX - need a VOP extension */
1502 		break;
1503 	case NFS4ATTR_SETIT:
1504 		/*
1505 		 * read-only attr
1506 		 */
1507 		error = EINVAL;
1508 		break;
1509 	case NFS4ATTR_VERIT:
1510 		if (!na->homogeneous)
1511 			error = -1;	/* no match */
1512 		break;
1513 	case NFS4ATTR_FREEIT:
1514 		break;
1515 	}
1516 	return (error);
1517 }
1518 
1519 /* ARGSUSED */
1520 static int
1521 rfs4_fattr4_maxfilesize(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1522 	union nfs4_attr_u *na)
1523 {
1524 	int error = 0;
1525 	ulong_t val;
1526 	fattr4_maxfilesize maxfilesize;
1527 
1528 	if (RFS4_MANDATTR_ONLY)
1529 		return (ENOTSUP);
1530 
1531 	switch (cmd) {
1532 	case NFS4ATTR_SUPPORTED:
1533 		if (sarg->op == NFS4ATTR_SETIT)
1534 			error = EINVAL;
1535 		break;		/* this attr is supported */
1536 	case NFS4ATTR_GETIT:
1537 		if (sarg->rdattr_error && (sarg->cs->vp == NULL)) {
1538 			error = -1;	/* may be okay if rdattr_error */
1539 			break;
1540 		}
1541 		ASSERT(sarg->cs->vp != NULL);
1542 		error = VOP_PATHCONF(sarg->cs->vp, _PC_FILESIZEBITS, &val,
1543 				sarg->cs->cr);
1544 		if (error)
1545 			break;
1546 		if (val >= (sizeof (uint64_t) * 8))
1547 			na->maxfilesize = UINT64_MAX;
1548 		else
1549 			na->maxfilesize = ((1LL << val) - 1);
1550 		break;
1551 	case NFS4ATTR_SETIT:
1552 		/*
1553 		 * read-only attr
1554 		 */
1555 		error = EINVAL;
1556 		break;
1557 	case NFS4ATTR_VERIT:
1558 		ASSERT(sarg->cs->vp != NULL);
1559 		error = VOP_PATHCONF(sarg->cs->vp, _PC_FILESIZEBITS, &val,
1560 				sarg->cs->cr);
1561 		if (error)
1562 			break;
1563 		if (val >= (sizeof (uint64_t) * 8))
1564 			maxfilesize = UINT64_MAX;
1565 		else
1566 			maxfilesize = ((1LL << val) - 1);
1567 		if (na->maxfilesize != maxfilesize)
1568 			error = -1;	/* no match */
1569 		break;
1570 	case NFS4ATTR_FREEIT:
1571 		break;
1572 	}
1573 	return (error);
1574 }
1575 
1576 /* ARGSUSED */
1577 static int
1578 rfs4_fattr4_maxlink(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1579 	union nfs4_attr_u *na)
1580 {
1581 	int error = 0;
1582 	ulong_t val;
1583 
1584 	if (RFS4_MANDATTR_ONLY)
1585 		return (ENOTSUP);
1586 
1587 	switch (cmd) {
1588 	case NFS4ATTR_SUPPORTED:
1589 		if (sarg->op == NFS4ATTR_SETIT)
1590 			error = EINVAL;
1591 		break;		/* this attr is supported */
1592 	case NFS4ATTR_GETIT:
1593 		if (sarg->rdattr_error && (sarg->cs->vp == NULL)) {
1594 			error = -1;	/* may be okay if rdattr_error */
1595 			break;
1596 		}
1597 		ASSERT(sarg->cs->vp != NULL);
1598 		error = VOP_PATHCONF(sarg->cs->vp, _PC_LINK_MAX, &val,
1599 				sarg->cs->cr);
1600 		if (error == 0) {
1601 			na->maxlink = val;
1602 		}
1603 		break;
1604 	case NFS4ATTR_SETIT:
1605 		/*
1606 		 * read-only attr
1607 		 */
1608 		error = EINVAL;
1609 		break;
1610 	case NFS4ATTR_VERIT:
1611 		ASSERT(sarg->cs->vp != NULL);
1612 		error = VOP_PATHCONF(sarg->cs->vp, _PC_LINK_MAX, &val,
1613 				sarg->cs->cr);
1614 		if (!error && (na->maxlink != val))
1615 			error = -1;	/* no match */
1616 		break;
1617 	case NFS4ATTR_FREEIT:
1618 		break;
1619 	}
1620 	return (error);
1621 }
1622 
1623 /* ARGSUSED */
1624 static int
1625 rfs4_fattr4_maxname(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1626 	union nfs4_attr_u *na)
1627 {
1628 	int error = 0;
1629 	ulong_t val;
1630 
1631 	if (RFS4_MANDATTR_ONLY)
1632 		return (ENOTSUP);
1633 
1634 	switch (cmd) {
1635 	case NFS4ATTR_SUPPORTED:
1636 		if (sarg->op == NFS4ATTR_SETIT)
1637 			error = EINVAL;
1638 		break;		/* this attr is supported */
1639 	case NFS4ATTR_GETIT:
1640 		if (sarg->rdattr_error && (sarg->cs->vp == NULL)) {
1641 			error = -1;	/* may be okay if rdattr_error */
1642 			break;
1643 		}
1644 		ASSERT(sarg->cs->vp != NULL);
1645 		error = VOP_PATHCONF(sarg->cs->vp, _PC_NAME_MAX, &val,
1646 				sarg->cs->cr);
1647 		if (error == 0) {
1648 			na->maxname = val;
1649 		}
1650 		break;
1651 	case NFS4ATTR_SETIT:
1652 		/*
1653 		 * read-only attr
1654 		 */
1655 		error = EINVAL;
1656 		break;
1657 	case NFS4ATTR_VERIT:
1658 		ASSERT(sarg->cs->vp != NULL);
1659 		error = VOP_PATHCONF(sarg->cs->vp, _PC_NAME_MAX, &val,
1660 				sarg->cs->cr);
1661 		if (!error && (na->maxname != val))
1662 			error = -1;	/* no match */
1663 		break;
1664 	case NFS4ATTR_FREEIT:
1665 		break;
1666 	}
1667 	return (error);
1668 }
1669 
1670 /* ARGSUSED */
1671 static int
1672 rfs4_fattr4_maxread(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1673 	union nfs4_attr_u *na)
1674 {
1675 	int error = 0;
1676 
1677 	if (RFS4_MANDATTR_ONLY)
1678 		return (ENOTSUP);
1679 
1680 	switch (cmd) {
1681 	case NFS4ATTR_SUPPORTED:
1682 		if (sarg->op == NFS4ATTR_SETIT)
1683 			error = EINVAL;
1684 		break;		/* this attr is supported */
1685 	case NFS4ATTR_GETIT:
1686 		na->maxread = rfs4_tsize(sarg->cs->req);
1687 		break;
1688 	case NFS4ATTR_SETIT:
1689 		/*
1690 		 * read-only attr
1691 		 */
1692 		error = EINVAL;
1693 		break;
1694 	case NFS4ATTR_VERIT:
1695 		if (na->maxread != rfs4_tsize(sarg->cs->req))
1696 			error = -1;	/* no match */
1697 		break;
1698 	case NFS4ATTR_FREEIT:
1699 		break;
1700 	}
1701 	return (error);
1702 }
1703 
1704 /* ARGSUSED */
1705 static int
1706 rfs4_fattr4_maxwrite(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1707 	union nfs4_attr_u *na)
1708 {
1709 	int error = 0;
1710 
1711 	if (RFS4_MANDATTR_ONLY)
1712 		return (ENOTSUP);
1713 
1714 	switch (cmd) {
1715 	case NFS4ATTR_SUPPORTED:
1716 		if (sarg->op == NFS4ATTR_SETIT)
1717 			error = EINVAL;
1718 		break;		/* this attr is supported */
1719 	case NFS4ATTR_GETIT:
1720 		na->maxwrite = rfs4_tsize(sarg->cs->req);
1721 		break;
1722 	case NFS4ATTR_SETIT:
1723 		/*
1724 		 * read-only attr
1725 		 */
1726 		error = EINVAL;
1727 		break;
1728 	case NFS4ATTR_VERIT:
1729 		if (na->maxwrite != rfs4_tsize(sarg->cs->req))
1730 			error = -1;	/* no match */
1731 		break;
1732 	case NFS4ATTR_FREEIT:
1733 		break;
1734 	}
1735 	return (error);
1736 }
1737 
1738 /* ARGSUSED */
1739 static int
1740 rfs4_fattr4_mimetype(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1741 	union nfs4_attr_u *na)
1742 {
1743 	return (ENOTSUP);
1744 }
1745 
1746 /* ARGSUSED */
1747 static int
1748 rfs4_fattr4_mode(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1749 	union nfs4_attr_u *na)
1750 {
1751 	int	error = 0;
1752 
1753 	if (RFS4_MANDATTR_ONLY)
1754 		return (ENOTSUP);
1755 
1756 	switch (cmd) {
1757 	case NFS4ATTR_SUPPORTED:
1758 		break;		/* this attr is supported */
1759 	case NFS4ATTR_GETIT:
1760 		if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_MODE)) {
1761 			error = -1;	/* may be okay if rdattr_error */
1762 			break;
1763 		}
1764 		ASSERT(sarg->vap->va_mask & AT_MODE);
1765 		na->mode = sarg->vap->va_mode;
1766 		break;
1767 	case NFS4ATTR_SETIT:
1768 		ASSERT(sarg->vap->va_mask & AT_MODE);
1769 		sarg->vap->va_mode = na->mode;
1770 		/*
1771 		 * If the filesystem is exported with nosuid, then mask off
1772 		 * the setuid and setgid bits.
1773 		 */
1774 		if (sarg->cs->vp->v_type == VREG &&
1775 			(sarg->cs->exi->exi_export.ex_flags & EX_NOSUID))
1776 			sarg->vap->va_mode &= ~(VSUID | VSGID);
1777 		break;
1778 	case NFS4ATTR_VERIT:
1779 		ASSERT(sarg->vap->va_mask & AT_MODE);
1780 		if (sarg->vap->va_mode != na->mode)
1781 			error = -1;	/* no match */
1782 		break;
1783 	case NFS4ATTR_FREEIT:
1784 		break;
1785 	}
1786 	return (error);
1787 }
1788 
1789 /* ARGSUSED */
1790 static int
1791 rfs4_fattr4_no_trunc(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1792 	union nfs4_attr_u *na)
1793 {
1794 	int error = 0;
1795 
1796 	if (RFS4_MANDATTR_ONLY)
1797 		return (ENOTSUP);
1798 
1799 	switch (cmd) {
1800 	case NFS4ATTR_SUPPORTED:
1801 		if (sarg->op == NFS4ATTR_SETIT)
1802 			error = EINVAL;
1803 		break;		/* this attr is supported */
1804 	case NFS4ATTR_GETIT:
1805 		na->no_trunc = TRUE;
1806 		break;
1807 	case NFS4ATTR_SETIT:
1808 		/*
1809 		 * read-only attr
1810 		 */
1811 		error = EINVAL;
1812 		break;
1813 	case NFS4ATTR_VERIT:
1814 		if (!na->no_trunc)
1815 			error = -1;	/* no match */
1816 		break;
1817 	case NFS4ATTR_FREEIT:
1818 		break;
1819 	}
1820 	return (error);
1821 }
1822 
1823 /* ARGSUSED */
1824 static int
1825 rfs4_fattr4_numlinks(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1826 	union nfs4_attr_u *na)
1827 {
1828 	int	error = 0;
1829 
1830 	if (RFS4_MANDATTR_ONLY)
1831 		return (ENOTSUP);
1832 
1833 	switch (cmd) {
1834 	case NFS4ATTR_SUPPORTED:
1835 		if (sarg->op == NFS4ATTR_SETIT)
1836 			error = EINVAL;
1837 		break;		/* this attr is supported */
1838 	case NFS4ATTR_GETIT:
1839 		if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_NLINK)) {
1840 			error = -1;	/* may be okay if rdattr_error */
1841 			break;
1842 		}
1843 		ASSERT(sarg->vap->va_mask & AT_NLINK);
1844 		na->numlinks = sarg->vap->va_nlink;
1845 		break;
1846 	case NFS4ATTR_SETIT:
1847 		/*
1848 		 * read-only attr
1849 		 */
1850 		error = EINVAL;
1851 		break;
1852 	case NFS4ATTR_VERIT:
1853 		ASSERT(sarg->vap->va_mask & AT_NLINK);
1854 		if (sarg->vap->va_nlink != na->numlinks)
1855 			error = -1;	/* no match */
1856 		break;
1857 	case NFS4ATTR_FREEIT:
1858 		break;
1859 	}
1860 	return (error);
1861 }
1862 
1863 /* ARGSUSED */
1864 static int
1865 rfs4_fattr4_owner(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1866 	union nfs4_attr_u *na)
1867 {
1868 	int	error = 0;
1869 	uid_t	uid;
1870 
1871 	if (RFS4_MANDATTR_ONLY)
1872 		return (ENOTSUP);
1873 
1874 	switch (cmd) {
1875 	case NFS4ATTR_SUPPORTED:
1876 		break;		/* this attr is supported */
1877 	case NFS4ATTR_GETIT:
1878 		if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_UID)) {
1879 			error = -1;	/* may be okay if rdattr_error */
1880 			break;
1881 		}
1882 		ASSERT(sarg->vap->va_mask & AT_UID);
1883 
1884 		/*
1885 		 * There are well defined polices for what happens on server-
1886 		 * side GETATTR when uid to attribute string conversion cannot
1887 		 * occur. Please refer to nfs4_idmap.c for details.
1888 		 */
1889 		error = nfs_idmap_uid_str(sarg->vap->va_uid, &na->owner, TRUE);
1890 		switch (error) {
1891 		case ECONNREFUSED:
1892 			error = NFS4ERR_DELAY;
1893 			break;
1894 		default:
1895 			break;
1896 		}
1897 		break;
1898 
1899 	case NFS4ATTR_SETIT:
1900 		ASSERT(sarg->vap->va_mask & AT_UID);
1901 
1902 		/*
1903 		 * There are well defined policies for what happens on server-
1904 		 * side SETATTR of 'owner' when a "user@domain" mapping cannot
1905 		 * occur. Please refer to nfs4_idmap.c for details.
1906 		 *
1907 		 * Any other errors, such as the mapping not being found by
1908 		 * nfsmapid(1m), and interrupted clnt_call, etc, will result
1909 		 * in NFS4ERR_BADOWNER.
1910 		 *
1911 		 * XXX need to return consistent errors, perhaps all
1912 		 * server side attribute routines should return NFS4ERR*.
1913 		 */
1914 		error = nfs_idmap_str_uid(&na->owner, &sarg->vap->va_uid, TRUE);
1915 		switch (error) {
1916 		case NFS4_OK:
1917 		case ENOTSUP:
1918 			/*
1919 			 * Ignore warning that we are the
1920 			 * nfsmapid (can't happen on srv)
1921 			 */
1922 			error = 0;
1923 			MSG_PRT_DEBUG = FALSE;
1924 			break;
1925 
1926 		case ECOMM:
1927 		case ECONNREFUSED:
1928 			if (!MSG_PRT_DEBUG) {
1929 				/*
1930 				 * printed just once per daemon death,
1931 				 * inform the user and then stay silent
1932 				 */
1933 				cmn_err(CE_WARN, "!Unable to contact "
1934 				    "nfsmapid");
1935 				MSG_PRT_DEBUG = TRUE;
1936 			}
1937 			error = NFS4ERR_DELAY;
1938 			break;
1939 
1940 		case EINVAL:
1941 			error = NFS4ERR_INVAL;
1942 			break;
1943 
1944 		default:
1945 			error = NFS4ERR_BADOWNER;
1946 			break;
1947 		}
1948 		break;
1949 
1950 	case NFS4ATTR_VERIT:
1951 		ASSERT(sarg->vap->va_mask & AT_UID);
1952 		error = nfs_idmap_str_uid(&na->owner, &uid, TRUE);
1953 		/*
1954 		 * Ignore warning that we are the nfsmapid (can't happen on srv)
1955 		 */
1956 		if (error == ENOTSUP)
1957 			error = 0;
1958 		if (error)
1959 			error = -1;	/* no match */
1960 		else if (sarg->vap->va_uid != uid)
1961 			error = -1;	/* no match */
1962 		break;
1963 	case NFS4ATTR_FREEIT:
1964 		if (sarg->op == NFS4ATTR_GETIT) {
1965 			if (na->owner.utf8string_val) {
1966 				UTF8STRING_FREE(na->owner)
1967 				bzero(&na->owner, sizeof (na->owner));
1968 			}
1969 		}
1970 		break;
1971 	}
1972 	return (error);
1973 }
1974 
1975 /* ARGSUSED */
1976 static int
1977 rfs4_fattr4_owner_group(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1978 	union nfs4_attr_u *na)
1979 {
1980 	int	error = 0;
1981 	gid_t	gid;
1982 
1983 	if (RFS4_MANDATTR_ONLY)
1984 		return (ENOTSUP);
1985 
1986 	switch (cmd) {
1987 	case NFS4ATTR_SUPPORTED:
1988 		break;		/* this attr is supported */
1989 	case NFS4ATTR_GETIT:
1990 		if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_GID)) {
1991 			error = -1;	/* may be okay if rdattr_error */
1992 			break;
1993 		}
1994 		ASSERT(sarg->vap->va_mask & AT_GID);
1995 
1996 		/*
1997 		 * There are well defined polices for what happens on server-
1998 		 * side GETATTR when gid to attribute string conversion cannot
1999 		 * occur. Please refer to nfs4_idmap.c for details.
2000 		 */
2001 		error = nfs_idmap_gid_str(sarg->vap->va_gid, &na->owner_group,
2002 		    TRUE);
2003 		switch (error) {
2004 		case ECONNREFUSED:
2005 			error = NFS4ERR_DELAY;
2006 			break;
2007 		default:
2008 			break;
2009 		}
2010 		break;
2011 
2012 	case NFS4ATTR_SETIT:
2013 		ASSERT(sarg->vap->va_mask & AT_GID);
2014 
2015 		/*
2016 		 * There are well defined policies for what happens on server-
2017 		 * side SETATTR of 'owner_group' when a "group@domain" mapping
2018 		 * cannot occur. Please refer to nfs4_idmap.c for details.
2019 		 *
2020 		 * Any other errors, such as the mapping not being found by
2021 		 * nfsmapid(1m), and interrupted clnt_call, etc, will result
2022 		 * in NFS4ERR_BADOWNER.
2023 		 *
2024 		 * XXX need to return consistent errors, perhaps all
2025 		 * server side attribute routines should return NFS4ERR*.
2026 		 */
2027 		error = nfs_idmap_str_gid(&na->owner_group, &sarg->vap->va_gid,
2028 		    TRUE);
2029 		switch (error) {
2030 		case NFS4_OK:
2031 		case ENOTSUP:
2032 			/*
2033 			 * Ignore warning that we are the
2034 			 * nfsmapid (can't happen on srv)
2035 			 */
2036 			error = 0;
2037 			MSG_PRT_DEBUG = FALSE;
2038 			break;
2039 
2040 		case ECOMM:
2041 		case ECONNREFUSED:
2042 			if (!MSG_PRT_DEBUG) {
2043 				/*
2044 				 * printed just once per daemon death,
2045 				 * inform the user and then stay silent
2046 				 */
2047 				cmn_err(CE_WARN, "!Unable to contact "
2048 				    "nfsmapid");
2049 				MSG_PRT_DEBUG = TRUE;
2050 			}
2051 			error = NFS4ERR_DELAY;
2052 			break;
2053 
2054 		case EINVAL:
2055 			error = NFS4ERR_INVAL;
2056 			break;
2057 
2058 		default:
2059 			error = NFS4ERR_BADOWNER;
2060 			break;
2061 		}
2062 		break;
2063 
2064 	case NFS4ATTR_VERIT:
2065 		ASSERT(sarg->vap->va_mask & AT_GID);
2066 		error = nfs_idmap_str_gid(&na->owner_group, &gid, TRUE);
2067 		/*
2068 		 * Ignore warning that we are the nfsmapid (can't happen on srv)
2069 		 */
2070 		if (error == ENOTSUP)
2071 			error = 0;
2072 		if (error)
2073 			error = -1;	/* no match */
2074 		else if (sarg->vap->va_gid != gid)
2075 			error = -1;	/* no match */
2076 		break;
2077 	case NFS4ATTR_FREEIT:
2078 		if (sarg->op == NFS4ATTR_GETIT) {
2079 			if (na->owner_group.utf8string_val) {
2080 				UTF8STRING_FREE(na->owner_group)
2081 				bzero(&na->owner_group,
2082 					sizeof (na->owner_group));
2083 			}
2084 		}
2085 		break;
2086 	}
2087 	return (error);
2088 }
2089 
2090 /* XXX - quota attributes should be supportable on Solaris 2 */
2091 /* ARGSUSED */
2092 static int
2093 rfs4_fattr4_quota_avail_hard(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2094 	union nfs4_attr_u *na)
2095 {
2096 	return (ENOTSUP);
2097 }
2098 
2099 /* ARGSUSED */
2100 static int
2101 rfs4_fattr4_quota_avail_soft(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2102 	union nfs4_attr_u *na)
2103 {
2104 	return (ENOTSUP);
2105 }
2106 
2107 /* ARGSUSED */
2108 static int
2109 rfs4_fattr4_quota_used(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2110 	union nfs4_attr_u *na)
2111 {
2112 	return (ENOTSUP);
2113 }
2114 
2115 /* ARGSUSED */
2116 static int
2117 rfs4_fattr4_rawdev(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2118 	union nfs4_attr_u *na)
2119 {
2120 	int	error = 0;
2121 
2122 	if (RFS4_MANDATTR_ONLY)
2123 		return (ENOTSUP);
2124 
2125 	switch (cmd) {
2126 	case NFS4ATTR_SUPPORTED:
2127 		if (sarg->op == NFS4ATTR_SETIT)
2128 			error = EINVAL;
2129 		break;		/* this attr is supported */
2130 	case NFS4ATTR_GETIT:
2131 		if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_RDEV)) {
2132 			error = -1;	/* may be okay if rdattr_error */
2133 			break;
2134 		}
2135 		ASSERT(sarg->vap->va_mask & AT_RDEV);
2136 		na->rawdev.specdata1 =  (uint32)getmajor(sarg->vap->va_rdev);
2137 		na->rawdev.specdata2 =  (uint32)getminor(sarg->vap->va_rdev);
2138 		break;
2139 	case NFS4ATTR_SETIT:
2140 		/*
2141 		 * read-only attr
2142 		 */
2143 		error = EINVAL;
2144 		break;
2145 	case NFS4ATTR_VERIT:
2146 		ASSERT(sarg->vap->va_mask & AT_RDEV);
2147 		if ((na->rawdev.specdata1 !=
2148 			(uint32)getmajor(sarg->vap->va_rdev)) ||
2149 		    (na->rawdev.specdata2 !=
2150 			(uint32)getminor(sarg->vap->va_rdev)))
2151 			error = -1;	/* no match */
2152 		break;
2153 	case NFS4ATTR_FREEIT:
2154 		break;
2155 	}
2156 	return (error);
2157 }
2158 
2159 /* ARGSUSED */
2160 static int
2161 rfs4_fattr4_space_avail(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2162 	union nfs4_attr_u *na)
2163 {
2164 	int	error = 0;
2165 
2166 	if (RFS4_MANDATTR_ONLY)
2167 		return (ENOTSUP);
2168 
2169 	switch (cmd) {
2170 	case NFS4ATTR_SUPPORTED:
2171 		if (sarg->op == NFS4ATTR_SETIT)
2172 			error = EINVAL;
2173 		break;		/* this attr is supported */
2174 	case NFS4ATTR_GETIT:
2175 		if (sarg->rdattr_error && (sarg->sbp == NULL)) {
2176 			error = -1;	/* may be okay if rdattr_error */
2177 			break;
2178 		}
2179 		ASSERT(sarg->sbp != NULL);
2180 		if (sarg->sbp->f_bavail != (fsblkcnt64_t)-1) {
2181 			na->space_avail =
2182 				(fattr4_space_avail) sarg->sbp->f_frsize *
2183 				(fattr4_space_avail) sarg->sbp->f_bavail;
2184 		} else {
2185 			na->space_avail =
2186 				(fattr4_space_avail) sarg->sbp->f_bavail;
2187 		}
2188 		break;
2189 	case NFS4ATTR_SETIT:
2190 		/*
2191 		 * read-only attr
2192 		 */
2193 		error = EINVAL;
2194 		break;
2195 	case NFS4ATTR_VERIT:
2196 		ASSERT(sarg->sbp != NULL);
2197 		if (sarg->sbp->f_bavail != na->space_avail)
2198 			error = -1;	/* no match */
2199 		break;
2200 	case NFS4ATTR_FREEIT:
2201 		break;
2202 	}
2203 	return (error);
2204 }
2205 
2206 /* ARGSUSED */
2207 static int
2208 rfs4_fattr4_space_free(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2209 	union nfs4_attr_u *na)
2210 {
2211 	int	error = 0;
2212 
2213 	if (RFS4_MANDATTR_ONLY)
2214 		return (ENOTSUP);
2215 
2216 	switch (cmd) {
2217 	case NFS4ATTR_SUPPORTED:
2218 		if (sarg->op == NFS4ATTR_SETIT)
2219 			error = EINVAL;
2220 		break;		/* this attr is supported */
2221 	case NFS4ATTR_GETIT:
2222 		if (sarg->rdattr_error && (sarg->sbp == NULL)) {
2223 			error = -1;	/* may be okay if rdattr_error */
2224 			break;
2225 		}
2226 		ASSERT(sarg->sbp != NULL);
2227 		if (sarg->sbp->f_bfree != (fsblkcnt64_t)-1) {
2228 			na->space_free =
2229 				(fattr4_space_free) sarg->sbp->f_frsize *
2230 				(fattr4_space_free) sarg->sbp->f_bfree;
2231 		} else {
2232 			na->space_free =
2233 				(fattr4_space_free) sarg->sbp->f_bfree;
2234 		}
2235 		break;
2236 	case NFS4ATTR_SETIT:
2237 		/*
2238 		 * read-only attr
2239 		 */
2240 		error = EINVAL;
2241 		break;
2242 	case NFS4ATTR_VERIT:
2243 		ASSERT(sarg->sbp != NULL);
2244 		if (sarg->sbp->f_bfree != na->space_free)
2245 			error = -1;	/* no match */
2246 		break;
2247 	case NFS4ATTR_FREEIT:
2248 		break;
2249 	}
2250 	return (error);
2251 }
2252 
2253 /* ARGSUSED */
2254 static int
2255 rfs4_fattr4_space_total(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2256 	union nfs4_attr_u *na)
2257 {
2258 	int	error = 0;
2259 
2260 	if (RFS4_MANDATTR_ONLY)
2261 		return (ENOTSUP);
2262 
2263 	switch (cmd) {
2264 	case NFS4ATTR_SUPPORTED:
2265 		if (sarg->op == NFS4ATTR_SETIT)
2266 			error = EINVAL;
2267 		break;		/* this attr is supported */
2268 	case NFS4ATTR_GETIT:
2269 		if (sarg->rdattr_error_req && (sarg->sbp == NULL)) {
2270 			error = -1;	/* may be okay if rdattr_error */
2271 			break;
2272 		}
2273 		ASSERT(sarg->sbp != NULL);
2274 		if (sarg->sbp->f_blocks != (fsblkcnt64_t)-1) {
2275 			na->space_total =
2276 				(fattr4_space_total) sarg->sbp->f_frsize *
2277 				(fattr4_space_total) sarg->sbp->f_blocks;
2278 		} else {
2279 			na->space_total =
2280 				(fattr4_space_total) sarg->sbp->f_blocks;
2281 		}
2282 		break;
2283 	case NFS4ATTR_SETIT:
2284 		/*
2285 		 * read-only attr
2286 		 */
2287 		error = EINVAL;
2288 		break;
2289 	case NFS4ATTR_VERIT:
2290 		ASSERT(sarg->sbp != NULL);
2291 		if (sarg->sbp->f_blocks != na->space_total)
2292 			error = -1;	/* no match */
2293 		break;
2294 	case NFS4ATTR_FREEIT:
2295 		break;
2296 	}
2297 	return (error);
2298 }
2299 
2300 /* ARGSUSED */
2301 static int
2302 rfs4_fattr4_space_used(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2303 	union nfs4_attr_u *na)
2304 {
2305 	int	error = 0;
2306 
2307 	if (RFS4_MANDATTR_ONLY)
2308 		return (ENOTSUP);
2309 
2310 	switch (cmd) {
2311 	case NFS4ATTR_SUPPORTED:
2312 		if (sarg->op == NFS4ATTR_SETIT)
2313 			error = EINVAL;
2314 		break;		/* this attr is supported */
2315 	case NFS4ATTR_GETIT:
2316 		if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_NBLOCKS)) {
2317 			error = -1;	/* may be okay if rdattr_error */
2318 			break;
2319 		}
2320 		ASSERT(sarg->vap->va_mask & AT_NBLOCKS);
2321 		na->space_used =  (fattr4_space_used) DEV_BSIZE *
2322 			(fattr4_space_used) sarg->vap->va_nblocks;
2323 		break;
2324 	case NFS4ATTR_SETIT:
2325 		/*
2326 		 * read-only attr
2327 		 */
2328 		error = EINVAL;
2329 		break;
2330 	case NFS4ATTR_VERIT:
2331 		ASSERT(sarg->vap->va_mask & AT_NBLOCKS);
2332 		if (sarg->vap->va_nblocks != na->space_used)
2333 			error = -1;	/* no match */
2334 		break;
2335 	case NFS4ATTR_FREEIT:
2336 		break;
2337 	}
2338 	return (error);
2339 }
2340 
2341 /* ARGSUSED */
2342 static int
2343 rfs4_fattr4_system(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2344 	union nfs4_attr_u *na)
2345 {
2346 	return (ENOTSUP);
2347 }
2348 
2349 /* ARGSUSED */
2350 static int
2351 rfs4_fattr4_time_access(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2352 	union nfs4_attr_u *na)
2353 {
2354 	int	error = 0;
2355 	timestruc_t atime;
2356 
2357 	if (RFS4_MANDATTR_ONLY)
2358 		return (ENOTSUP);
2359 
2360 	switch (cmd) {
2361 	case NFS4ATTR_SUPPORTED:
2362 		if (sarg->op == NFS4ATTR_SETIT)
2363 			error = EINVAL;
2364 		break;		/* this attr is supported */
2365 	case NFS4ATTR_GETIT:
2366 		if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_ATIME)) {
2367 			error = -1;	/* may be okay if rdattr_error */
2368 			break;
2369 		}
2370 		ASSERT(sarg->vap->va_mask & AT_ATIME);
2371 		error = nfs4_time_vton(&sarg->vap->va_atime, &na->time_access);
2372 		break;
2373 	case NFS4ATTR_SETIT:
2374 		/*
2375 		 * read-only attr
2376 		 */
2377 		error = EINVAL;
2378 		break;
2379 	case NFS4ATTR_VERIT:
2380 		ASSERT(sarg->vap->va_mask & AT_ATIME);
2381 		error = nfs4_time_ntov(&na->time_access, &atime);
2382 		if (error)
2383 			break;
2384 		if (bcmp(&atime, &sarg->vap->va_atime, sizeof (atime)))
2385 			error = -1;	/* no match */
2386 		break;
2387 	case NFS4ATTR_FREEIT:
2388 		break;
2389 	}
2390 	return (error);
2391 }
2392 
2393 /*
2394  * XXX - need to support the setting of access time
2395  */
2396 /* ARGSUSED */
2397 static int
2398 rfs4_fattr4_time_access_set(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2399 	union nfs4_attr_u *na)
2400 {
2401 	int	error = 0;
2402 	settime4 *ta;
2403 
2404 	if (RFS4_MANDATTR_ONLY)
2405 		return (ENOTSUP);
2406 
2407 	switch (cmd) {
2408 	case NFS4ATTR_SUPPORTED:
2409 		if ((sarg->op == NFS4ATTR_GETIT) ||
2410 		    (sarg->op == NFS4ATTR_VERIT))
2411 			error = EINVAL;
2412 		break;		/* this attr is supported */
2413 	case NFS4ATTR_GETIT:
2414 	case NFS4ATTR_VERIT:
2415 		/*
2416 		 * write only attr
2417 		 */
2418 		error = EINVAL;
2419 		break;
2420 	case NFS4ATTR_SETIT:
2421 		ASSERT(sarg->vap->va_mask & AT_ATIME);
2422 		/*
2423 		 * Set access time (by server or by client)
2424 		 */
2425 		ta = &na->time_access_set;
2426 		if (ta->set_it == SET_TO_CLIENT_TIME4) {
2427 			error = nfs4_time_ntov(&ta->time, &sarg->vap->va_atime);
2428 		} else if (ta->set_it == SET_TO_SERVER_TIME4) {
2429 			gethrestime(&sarg->vap->va_atime);
2430 		} else {
2431 			error = EINVAL;
2432 		}
2433 		break;
2434 	case NFS4ATTR_FREEIT:
2435 		break;
2436 	}
2437 	return (error);
2438 }
2439 
2440 /* ARGSUSED */
2441 static int
2442 rfs4_fattr4_time_backup(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2443 	union nfs4_attr_u *na)
2444 {
2445 	return (ENOTSUP);
2446 }
2447 
2448 /* ARGSUSED */
2449 static int
2450 rfs4_fattr4_time_create(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2451 	union nfs4_attr_u *na)
2452 {
2453 	return (ENOTSUP);
2454 }
2455 
2456 /* ARGSUSED */
2457 static int
2458 rfs4_fattr4_time_delta(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2459 	union nfs4_attr_u *na)
2460 {
2461 	int error = 0;
2462 
2463 	if (RFS4_MANDATTR_ONLY)
2464 		return (ENOTSUP);
2465 
2466 	switch (cmd) {
2467 	case NFS4ATTR_SUPPORTED:
2468 		if (sarg->op == NFS4ATTR_SETIT)
2469 			error = EINVAL;
2470 		break;		/* this attr is supported */
2471 	case NFS4ATTR_GETIT:
2472 		na->time_delta.seconds = 0;
2473 		na->time_delta.nseconds = 1000;
2474 		break;
2475 	case NFS4ATTR_SETIT:
2476 		/*
2477 		 * write only attr
2478 		 */
2479 		error = EINVAL;
2480 		break;
2481 	case NFS4ATTR_VERIT:
2482 		if ((na->time_delta.seconds != 0) ||
2483 		    (na->time_delta.nseconds != 1000))
2484 			error = -1;	/* no match */
2485 		break;
2486 	case NFS4ATTR_FREEIT:
2487 		break;
2488 	}
2489 	return (error);
2490 }
2491 
2492 /* ARGSUSED */
2493 static int
2494 rfs4_fattr4_time_metadata(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2495 	union nfs4_attr_u *na)
2496 {
2497 	int	error = 0;
2498 	timestruc_t ctime;
2499 
2500 	if (RFS4_MANDATTR_ONLY)
2501 		return (ENOTSUP);
2502 
2503 	switch (cmd) {
2504 	case NFS4ATTR_SUPPORTED:
2505 		if (sarg->op == NFS4ATTR_SETIT)
2506 			error = EINVAL;
2507 		break;		/* this attr is supported */
2508 	case NFS4ATTR_GETIT:
2509 		if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_CTIME)) {
2510 			error = -1;	/* may be okay if rdattr_error */
2511 			break;
2512 		}
2513 		ASSERT(sarg->vap->va_mask & AT_CTIME);
2514 		error = nfs4_time_vton(&sarg->vap->va_ctime,
2515 				&na->time_metadata);
2516 		break;
2517 	case NFS4ATTR_SETIT:
2518 		/*
2519 		 * read-only attr
2520 		 */
2521 		error = EINVAL;
2522 		break;
2523 	case NFS4ATTR_VERIT:
2524 		ASSERT(sarg->vap->va_mask & AT_CTIME);
2525 		error = nfs4_time_ntov(&na->time_metadata, &ctime);
2526 		if (error)
2527 			break;
2528 		if (bcmp(&ctime, &sarg->vap->va_ctime, sizeof (ctime)))
2529 			error = -1;	/* no match */
2530 		break;
2531 	case NFS4ATTR_FREEIT:
2532 		break;
2533 	}
2534 	return (error);
2535 }
2536 
2537 /* ARGSUSED */
2538 static int
2539 rfs4_fattr4_time_modify(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2540 	union nfs4_attr_u *na)
2541 {
2542 	int	error = 0;
2543 	timestruc_t mtime;
2544 
2545 	if (RFS4_MANDATTR_ONLY)
2546 		return (ENOTSUP);
2547 
2548 	switch (cmd) {
2549 	case NFS4ATTR_SUPPORTED:
2550 		if (sarg->op == NFS4ATTR_SETIT)
2551 			error = EINVAL;
2552 		break;		/* this attr is supported */
2553 	case NFS4ATTR_GETIT:
2554 		if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_MTIME)) {
2555 			error = -1;	/* may be okay if rdattr_error */
2556 			break;
2557 		}
2558 		ASSERT(sarg->vap->va_mask & AT_MTIME);
2559 		error = nfs4_time_vton(&sarg->vap->va_mtime, &na->time_modify);
2560 		break;
2561 	case NFS4ATTR_SETIT:
2562 		/*
2563 		 * read-only attr
2564 		 */
2565 		error = EINVAL;
2566 		break;
2567 	case NFS4ATTR_VERIT:
2568 		ASSERT(sarg->vap->va_mask & AT_MTIME);
2569 		error = nfs4_time_ntov(&na->time_modify, &mtime);
2570 		if (error)
2571 			break;
2572 		if (bcmp(&mtime, &sarg->vap->va_mtime, sizeof (mtime)))
2573 			error = -1;	/* no match */
2574 		break;
2575 	case NFS4ATTR_FREEIT:
2576 		break;
2577 	}
2578 	return (error);
2579 }
2580 
2581 /*
2582  * XXX - need to add support for setting modify time
2583  */
2584 /* ARGSUSED */
2585 static int
2586 rfs4_fattr4_time_modify_set(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2587 	union nfs4_attr_u *na)
2588 {
2589 	int	error = 0;
2590 	settime4 *tm;
2591 
2592 	if (RFS4_MANDATTR_ONLY)
2593 		return (ENOTSUP);
2594 
2595 	switch (cmd) {
2596 	case NFS4ATTR_SUPPORTED:
2597 		if ((sarg->op == NFS4ATTR_GETIT) ||
2598 		    (sarg->op == NFS4ATTR_VERIT))
2599 			error = EINVAL;
2600 		break;		/* this attr is supported */
2601 	case NFS4ATTR_GETIT:
2602 	case NFS4ATTR_VERIT:
2603 		/*
2604 		 * write only attr
2605 		 */
2606 		error = EINVAL;
2607 		break;
2608 	case NFS4ATTR_SETIT:
2609 		ASSERT(sarg->vap->va_mask & AT_MTIME);
2610 		/*
2611 		 * Set modify time (by server or by client)
2612 		 */
2613 		tm = &na->time_modify_set;
2614 		if (tm->set_it == SET_TO_CLIENT_TIME4) {
2615 			error = nfs4_time_ntov(&tm->time, &sarg->vap->va_mtime);
2616 			sarg->flag = ATTR_UTIME;
2617 		} else if (tm->set_it == SET_TO_SERVER_TIME4) {
2618 			gethrestime(&sarg->vap->va_mtime);
2619 		} else {
2620 			error = EINVAL;
2621 		}
2622 		break;
2623 	case NFS4ATTR_FREEIT:
2624 		break;
2625 	}
2626 	return (error);
2627 }
2628 
2629 
2630 static void
2631 rfs4_ntov_init(void)
2632 {
2633 	/* index must be same as corresponding FATTR4_* define */
2634 	nfs4_ntov_map[0].sv_getit = rfs4_fattr4_supported_attrs;
2635 	nfs4_ntov_map[1].sv_getit = rfs4_fattr4_type;
2636 	nfs4_ntov_map[2].sv_getit = rfs4_fattr4_fh_expire_type;
2637 	nfs4_ntov_map[3].sv_getit = rfs4_fattr4_change;
2638 	nfs4_ntov_map[4].sv_getit = rfs4_fattr4_size;
2639 	nfs4_ntov_map[5].sv_getit = rfs4_fattr4_link_support;
2640 	nfs4_ntov_map[6].sv_getit = rfs4_fattr4_symlink_support;
2641 	nfs4_ntov_map[7].sv_getit = rfs4_fattr4_named_attr;
2642 	nfs4_ntov_map[8].sv_getit = rfs4_fattr4_fsid;
2643 	nfs4_ntov_map[9].sv_getit = rfs4_fattr4_unique_handles;
2644 	nfs4_ntov_map[10].sv_getit = rfs4_fattr4_lease_time;
2645 	nfs4_ntov_map[11].sv_getit = rfs4_fattr4_rdattr_error;
2646 	nfs4_ntov_map[12].sv_getit = rfs4_fattr4_acl;
2647 	nfs4_ntov_map[13].sv_getit = rfs4_fattr4_aclsupport;
2648 	nfs4_ntov_map[14].sv_getit = rfs4_fattr4_archive;
2649 	nfs4_ntov_map[15].sv_getit = rfs4_fattr4_cansettime;
2650 	nfs4_ntov_map[16].sv_getit = rfs4_fattr4_case_insensitive;
2651 	nfs4_ntov_map[17].sv_getit = rfs4_fattr4_case_preserving;
2652 	nfs4_ntov_map[18].sv_getit = rfs4_fattr4_chown_restricted;
2653 	nfs4_ntov_map[19].sv_getit = rfs4_fattr4_filehandle;
2654 	nfs4_ntov_map[20].sv_getit = rfs4_fattr4_fileid;
2655 	nfs4_ntov_map[21].sv_getit = rfs4_fattr4_files_avail;
2656 	nfs4_ntov_map[22].sv_getit = rfs4_fattr4_files_free;
2657 	nfs4_ntov_map[23].sv_getit = rfs4_fattr4_files_total;
2658 	nfs4_ntov_map[24].sv_getit = rfs4_fattr4_fs_locations;
2659 	nfs4_ntov_map[25].sv_getit = rfs4_fattr4_hidden;
2660 	nfs4_ntov_map[26].sv_getit = rfs4_fattr4_homogeneous;
2661 	nfs4_ntov_map[27].sv_getit = rfs4_fattr4_maxfilesize;
2662 	nfs4_ntov_map[28].sv_getit = rfs4_fattr4_maxlink;
2663 	nfs4_ntov_map[29].sv_getit = rfs4_fattr4_maxname;
2664 	nfs4_ntov_map[30].sv_getit = rfs4_fattr4_maxread;
2665 	nfs4_ntov_map[31].sv_getit = rfs4_fattr4_maxwrite;
2666 	nfs4_ntov_map[32].sv_getit = rfs4_fattr4_mimetype;
2667 	nfs4_ntov_map[33].sv_getit = rfs4_fattr4_mode;
2668 	nfs4_ntov_map[34].sv_getit = rfs4_fattr4_no_trunc;
2669 	nfs4_ntov_map[35].sv_getit = rfs4_fattr4_numlinks;
2670 	nfs4_ntov_map[36].sv_getit = rfs4_fattr4_owner;
2671 	nfs4_ntov_map[37].sv_getit = rfs4_fattr4_owner_group;
2672 	nfs4_ntov_map[38].sv_getit = rfs4_fattr4_quota_avail_hard;
2673 	nfs4_ntov_map[39].sv_getit = rfs4_fattr4_quota_avail_soft;
2674 	nfs4_ntov_map[40].sv_getit = rfs4_fattr4_quota_used;
2675 	nfs4_ntov_map[41].sv_getit = rfs4_fattr4_rawdev;
2676 	nfs4_ntov_map[42].sv_getit = rfs4_fattr4_space_avail;
2677 	nfs4_ntov_map[43].sv_getit = rfs4_fattr4_space_free;
2678 	nfs4_ntov_map[44].sv_getit = rfs4_fattr4_space_total;
2679 	nfs4_ntov_map[45].sv_getit = rfs4_fattr4_space_used;
2680 	nfs4_ntov_map[46].sv_getit = rfs4_fattr4_system;
2681 	nfs4_ntov_map[47].sv_getit = rfs4_fattr4_time_access;
2682 	nfs4_ntov_map[48].sv_getit = rfs4_fattr4_time_access_set;
2683 	nfs4_ntov_map[49].sv_getit = rfs4_fattr4_time_backup;
2684 	nfs4_ntov_map[50].sv_getit = rfs4_fattr4_time_create;
2685 	nfs4_ntov_map[51].sv_getit = rfs4_fattr4_time_delta;
2686 	nfs4_ntov_map[52].sv_getit = rfs4_fattr4_time_metadata;
2687 	nfs4_ntov_map[53].sv_getit = rfs4_fattr4_time_modify;
2688 	nfs4_ntov_map[54].sv_getit = rfs4_fattr4_time_modify_set;
2689 	nfs4_ntov_map[55].sv_getit = rfs4_fattr4_mounted_on_fileid;
2690 }
2691