xref: /illumos-gate/usr/src/uts/common/fs/nfs/nfs4_srv_attr.c (revision a7123019ed2e4decef929dc2e426f3f310788fa1)
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,
891 			    vp->v_type == VDIR, TRUE);
892 			vs_acet_destroy(&vs_native);
893 		} else {
894 			error = vs_aent_to_ace4(&vs_native, &vs_ace4,
895 			    vp->v_type == VDIR, TRUE);
896 			vs_aent_destroy(&vs_native);
897 		}
898 		if (error != 0)
899 			break;
900 
901 		if (cmd == NFS4ATTR_GETIT) {
902 			na->acl.fattr4_acl_len = vs_ace4.vsa_aclcnt;
903 			/* see case NFS4ATTR_FREEIT for this being freed */
904 			na->acl.fattr4_acl_val = vs_ace4.vsa_aclentp;
905 		} else {
906 			if (na->acl.fattr4_acl_len != vs_ace4.vsa_aclcnt)
907 				error = -1; /* no match */
908 			else if (ln_ace4_cmp(na->acl.fattr4_acl_val,
909 			    vs_ace4.vsa_aclentp,
910 			    vs_ace4.vsa_aclcnt) != 0)
911 				error = -1; /* no match */
912 		}
913 
914 		break;
915 
916 	case NFS4ATTR_SETIT:
917 		if (sarg->rdattr_error && (vp == NULL)) {
918 			return (-1);
919 		}
920 		ASSERT(vp != NULL);
921 
922 		/* prepare vs_ace4 from fattr4 data */
923 		bzero(&vs_ace4, sizeof (vs_ace4));
924 		vs_ace4.vsa_mask = VSA_ACE | VSA_ACECNT;
925 		vs_ace4.vsa_aclcnt = na->acl.fattr4_acl_len;
926 		vs_ace4.vsa_aclentp = na->acl.fattr4_acl_val;
927 
928 		/* make sure we have correct owner/group */
929 		if ((vap->va_mask & (AT_UID | AT_GID)) !=
930 		    (AT_UID | AT_GID)) {
931 			vap = &va;
932 			vap->va_mask = AT_UID | AT_GID;
933 			status = rfs4_vop_getattr(vp,
934 			    vap, 0, sarg->cs->cr);
935 			if (status != NFS4_OK)
936 				return (geterrno4(status));
937 		}
938 
939 		/* see which ACLs the fs supports */
940 		error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &whichacl,
941 		    sarg->cs->cr);
942 		if (error != 0) {
943 			/*
944 			 * If we got an error, then the filesystem
945 			 * likely does not understand the _PC_ACL_ENABLED
946 			 * pathconf.  In this case, we fall back to trying
947 			 * POSIX-draft (aka UFS-style) ACLs, since that's
948 			 * the behavior used by earlier version of NFS.
949 			 */
950 			error = 0;
951 			whichacl = _ACL_ACLENT_ENABLED;
952 		}
953 
954 		if (!(whichacl & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED))) {
955 			/*
956 			 * If the file system supports neither ACE nor
957 			 * ACLENT ACLs we will fall back to UFS-style ACLs
958 			 * like we did above if there was an error upon
959 			 * calling VOP_PATHCONF.
960 			 *
961 			 * ACE and ACLENT type ACLs are the only interfaces
962 			 * supported thus far.  If any other bits are set on
963 			 * 'whichacl' upon return from VOP_PATHCONF, we will
964 			 * ignore them.
965 			 */
966 			whichacl = _ACL_ACLENT_ENABLED;
967 		}
968 
969 		if (whichacl & _ACL_ACE_ENABLED) {
970 			error = vs_ace4_to_acet(&vs_ace4, &vs_native,
971 			    vap->va_uid, vap->va_gid, vp->v_type == VDIR, TRUE,
972 			    FALSE);
973 			if (error != 0)
974 				break;
975 			(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
976 			error = VOP_SETSECATTR(vp, &vs_native,
977 			    0, sarg->cs->cr);
978 			VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
979 			vs_acet_destroy(&vs_native);
980 		} else if (whichacl & _ACL_ACLENT_ENABLED) {
981 			error = vs_ace4_to_aent(&vs_ace4, &vs_native,
982 			    vap->va_uid, vap->va_gid, vp->v_type == VDIR, TRUE,
983 			    FALSE);
984 			if (error != 0)
985 				break;
986 			(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
987 			error = VOP_SETSECATTR(vp, &vs_native,
988 			    0, sarg->cs->cr);
989 			VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
990 			vs_aent_destroy(&vs_native);
991 		}
992 		break;
993 
994 	case NFS4ATTR_FREEIT:
995 		if (sarg->op == NFS4ATTR_GETIT) {
996 			vs_ace4.vsa_mask = VSA_ACE | VSA_ACECNT;
997 			vs_ace4.vsa_aclcnt = na->acl.fattr4_acl_len;
998 			vs_ace4.vsa_aclentp = na->acl.fattr4_acl_val;
999 			vs_ace4_destroy(&vs_ace4);
1000 		}
1001 		break;
1002 	}
1003 
1004 	return (error);
1005 }
1006 
1007 /* ARGSUSED */
1008 static int
1009 rfs4_fattr4_aclsupport(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1010 	union nfs4_attr_u *na)
1011 {
1012 	int error = 0;
1013 
1014 	if (RFS4_MANDATTR_ONLY)
1015 		return (ENOTSUP);
1016 
1017 	switch (cmd) {
1018 	case NFS4ATTR_SUPPORTED:
1019 		if (sarg->op == NFS4ATTR_SETIT)
1020 			error = EINVAL;
1021 		break;	/* supported */
1022 	case NFS4ATTR_GETIT:
1023 		na->aclsupport = ACL4_SUPPORT_ALLOW_ACL |
1024 		    ACL4_SUPPORT_DENY_ACL;
1025 		break;
1026 	case NFS4ATTR_SETIT:
1027 		error = EINVAL;
1028 		break;
1029 	case NFS4ATTR_VERIT:
1030 		if (na->aclsupport != (ACL4_SUPPORT_ALLOW_ACL |
1031 		    ACL4_SUPPORT_DENY_ACL))
1032 			error = -1;	/* no match */
1033 		break;
1034 	}
1035 
1036 	return (error);
1037 }
1038 
1039 /* ARGSUSED */
1040 static int
1041 rfs4_fattr4_archive(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1042 	union nfs4_attr_u *na)
1043 {
1044 	return (ENOTSUP);
1045 }
1046 
1047 /* ARGSUSED */
1048 static int
1049 rfs4_fattr4_cansettime(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1050 	union nfs4_attr_u *na)
1051 {
1052 	int error = 0;
1053 
1054 	if (RFS4_MANDATTR_ONLY)
1055 		return (ENOTSUP);
1056 
1057 	switch (cmd) {
1058 	case NFS4ATTR_SUPPORTED:
1059 		if (sarg->op == NFS4ATTR_SETIT)
1060 			error = EINVAL;
1061 		break;		/* this attr is supported */
1062 	case NFS4ATTR_GETIT:
1063 		na->cansettime = TRUE;
1064 		break;
1065 	case NFS4ATTR_SETIT:
1066 		/*
1067 		 * read-only attr
1068 		 */
1069 		error = EINVAL;
1070 		break;
1071 	case NFS4ATTR_VERIT:
1072 		if (!na->cansettime)
1073 			error = -1;	/* no match */
1074 		break;
1075 	case NFS4ATTR_FREEIT:
1076 		break;
1077 	}
1078 	return (error);
1079 }
1080 
1081 /*
1082  * XXX - need VOP extension to ask file system (e.g. pcfs) if it supports
1083  * case insenstive.
1084  */
1085 /* ARGSUSED */
1086 static int
1087 rfs4_fattr4_case_insensitive(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1088 	union nfs4_attr_u *na)
1089 {
1090 	int error = 0;
1091 
1092 	if (RFS4_MANDATTR_ONLY)
1093 		return (ENOTSUP);
1094 
1095 	switch (cmd) {
1096 	case NFS4ATTR_SUPPORTED:
1097 		if (sarg->op == NFS4ATTR_SETIT)
1098 			error = EINVAL;
1099 		break;		/* this attr is supported */
1100 	case NFS4ATTR_GETIT:
1101 		na->case_insensitive = FALSE;
1102 		break;
1103 	case NFS4ATTR_SETIT:
1104 		/*
1105 		 * read-only attr
1106 		 */
1107 		error = EINVAL;
1108 		break;
1109 	case NFS4ATTR_VERIT:
1110 		if (!na->case_insensitive)
1111 			error = -1;	/* no match */
1112 		break;
1113 	case NFS4ATTR_FREEIT:
1114 		break;
1115 	}
1116 	return (error);
1117 }
1118 
1119 /* ARGSUSED */
1120 static int
1121 rfs4_fattr4_case_preserving(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1122 	union nfs4_attr_u *na)
1123 {
1124 	int error = 0;
1125 
1126 	if (RFS4_MANDATTR_ONLY)
1127 		return (ENOTSUP);
1128 
1129 	switch (cmd) {
1130 	case NFS4ATTR_SUPPORTED:
1131 		if (sarg->op == NFS4ATTR_SETIT)
1132 			error = EINVAL;
1133 		break;		/* this attr is supported */
1134 	case NFS4ATTR_GETIT:
1135 		na->case_preserving = TRUE;
1136 		break;
1137 	case NFS4ATTR_SETIT:
1138 		/*
1139 		 * read-only attr
1140 		 */
1141 		error = EINVAL;
1142 		break;
1143 	case NFS4ATTR_VERIT:
1144 		if (!na->case_preserving)
1145 			error = -1;	/* no match */
1146 		break;
1147 	case NFS4ATTR_FREEIT:
1148 		break;
1149 	}
1150 	return (error);
1151 }
1152 
1153 /* fattr4_chown_restricted should reall be fattr4_chown_allowed */
1154 /* ARGSUSED */
1155 static int
1156 rfs4_fattr4_chown_restricted(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1157 	union nfs4_attr_u *na)
1158 {
1159 	int error = 0;
1160 	ulong_t val;
1161 
1162 	if (RFS4_MANDATTR_ONLY)
1163 		return (ENOTSUP);
1164 
1165 	switch (cmd) {
1166 	case NFS4ATTR_SUPPORTED:
1167 		if (sarg->op == NFS4ATTR_SETIT)
1168 			error = EINVAL;
1169 		break;		/* this attr is supported */
1170 	case NFS4ATTR_GETIT:
1171 		if (sarg->rdattr_error && (sarg->cs->vp == NULL)) {
1172 			error = -1;	/* may be okay if rdattr_error */
1173 			break;
1174 		}
1175 		ASSERT(sarg->cs->vp != NULL);
1176 		error = VOP_PATHCONF(sarg->cs->vp,
1177 				_PC_CHOWN_RESTRICTED, &val, sarg->cs->cr);
1178 		if (error)
1179 			break;
1180 
1181 		na->chown_restricted = (val == 1);
1182 		break;
1183 	case NFS4ATTR_SETIT:
1184 		/*
1185 		 * read-only attr
1186 		 */
1187 		error = EINVAL;
1188 		break;
1189 	case NFS4ATTR_VERIT:
1190 		ASSERT(sarg->cs->vp != NULL);
1191 		error = VOP_PATHCONF(sarg->cs->vp,
1192 				_PC_CHOWN_RESTRICTED, &val, sarg->cs->cr);
1193 		if (error)
1194 			break;
1195 		if (na->chown_restricted != (val == 1))
1196 			error = -1;	/* no match */
1197 		break;
1198 	case NFS4ATTR_FREEIT:
1199 		break;
1200 	}
1201 	return (error);
1202 }
1203 
1204 /* ARGSUSED */
1205 static int
1206 rfs4_fattr4_fileid(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1207 	union nfs4_attr_u *na)
1208 {
1209 	int	error = 0;
1210 
1211 	if (RFS4_MANDATTR_ONLY)
1212 		return (ENOTSUP);
1213 
1214 	switch (cmd) {
1215 	case NFS4ATTR_SUPPORTED:
1216 		if (sarg->op == NFS4ATTR_SETIT)
1217 			error = EINVAL;
1218 		break;		/* this attr is supported */
1219 	case NFS4ATTR_GETIT:
1220 		if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_NODEID)) {
1221 			error = -1;	/* may be okay if rdattr_error */
1222 			break;
1223 		}
1224 		ASSERT(sarg->vap->va_mask & AT_NODEID);
1225 		na->fileid = sarg->vap->va_nodeid;
1226 		break;
1227 	case NFS4ATTR_SETIT:
1228 		/*
1229 		 * read-only attr
1230 		 */
1231 		error = EINVAL;
1232 		break;
1233 	case NFS4ATTR_VERIT:
1234 		ASSERT(sarg->vap->va_mask & AT_NODEID);
1235 		if (sarg->vap->va_nodeid != na->fileid)
1236 			error = -1;	/* no match */
1237 		break;
1238 	case NFS4ATTR_FREEIT:
1239 		break;
1240 	}
1241 	return (error);
1242 }
1243 
1244 /* ARGSUSED */
1245 static int
1246 rfs4_get_mntdfileid(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg)
1247 {
1248 	int error = 0;
1249 	vattr_t	*vap, va;
1250 	vnode_t *stubvp = NULL, *vp;
1251 
1252 	vp = sarg->cs->vp;
1253 	sarg->mntdfid_set = FALSE;
1254 
1255 	/* VROOT object, must untraverse */
1256 	if (vp->v_flag & VROOT) {
1257 
1258 		/* extra hold for vp since untraverse might rele */
1259 		VN_HOLD(vp);
1260 		stubvp = untraverse(vp);
1261 
1262 		/*
1263 		 * If vp/stubvp are same, we must be at system
1264 		 * root because untraverse returned same vp
1265 		 * for a VROOT object.  sarg->vap was setup
1266 		 * before we got here, so there's no need to do
1267 		 * another getattr -- just use the one in sarg.
1268 		 */
1269 		if (VN_CMP(vp, stubvp)) {
1270 			ASSERT(VN_CMP(vp, rootdir));
1271 			vap = sarg->vap;
1272 		} else {
1273 			va.va_mask = AT_NODEID;
1274 			vap = &va;
1275 			error = rfs4_vop_getattr(stubvp, vap, 0, sarg->cs->cr);
1276 		}
1277 
1278 		/*
1279 		 * Done with stub, time to rele.  If vp and stubvp
1280 		 * were the same, then we need to rele either vp or
1281 		 * stubvp.  If they weren't the same, then untraverse()
1282 		 * already took case of the extra hold on vp, and only
1283 		 * the stub needs to be rele'd.  Both cases are handled
1284 		 * by unconditionally rele'ing the stub.
1285 		 */
1286 		VN_RELE(stubvp);
1287 	} else
1288 		vap = sarg->vap;
1289 
1290 	/*
1291 	 * At this point, vap should contain "correct" AT_NODEID --
1292 	 * (for V_ROOT case, nodeid of stub, for non-VROOT case,
1293 	 * nodeid of vp).  If error or AT_NODEID not available, then
1294 	 * make the obligatory (yet mysterious) rdattr_error
1295 	 * check that is so common in the attr code.
1296 	 */
1297 	if (!error && (vap->va_mask & AT_NODEID)) {
1298 		sarg->mounted_on_fileid = vap->va_nodeid;
1299 		sarg->mntdfid_set = TRUE;
1300 	} else if (sarg->rdattr_error)
1301 		error = -1;
1302 
1303 	/*
1304 	 * error describes these cases:
1305 	 *	0 : success
1306 	 *	-1: failure due to previous attr processing error (rddir only).
1307 	 *	* : new attr failure  (if rddir, caller will set rdattr_error)
1308 	 */
1309 	return (error);
1310 }
1311 
1312 /* ARGSUSED */
1313 static int
1314 rfs4_fattr4_mounted_on_fileid(nfs4_attr_cmd_t cmd,
1315 	struct nfs4_svgetit_arg *sarg, union nfs4_attr_u *na)
1316 {
1317 	int	error = 0;
1318 
1319 	if (RFS4_MANDATTR_ONLY)
1320 		return (ENOTSUP);
1321 
1322 	switch (cmd) {
1323 	case NFS4ATTR_SUPPORTED:
1324 		if (sarg->op == NFS4ATTR_SETIT)
1325 			error = EINVAL;
1326 		break;		/* this attr is supported */
1327 	case NFS4ATTR_GETIT:
1328 	case NFS4ATTR_VERIT:
1329 		if (! sarg->mntdfid_set)
1330 			error = rfs4_get_mntdfileid(cmd, sarg);
1331 
1332 		if (! error && sarg->mntdfid_set) {
1333 			if (cmd == NFS4ATTR_GETIT)
1334 				na->mounted_on_fileid = sarg->mounted_on_fileid;
1335 			else
1336 				if (na->mounted_on_fileid !=
1337 				    sarg->mounted_on_fileid)
1338 					error = -1;
1339 		}
1340 		break;
1341 	case NFS4ATTR_SETIT:
1342 		/* read-only attr */
1343 		error = EINVAL;
1344 		break;
1345 	case NFS4ATTR_FREEIT:
1346 		break;
1347 	}
1348 	return (error);
1349 }
1350 
1351 /* ARGSUSED */
1352 static int
1353 rfs4_fattr4_files_avail(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1354 	union nfs4_attr_u *na)
1355 {
1356 	int	error = 0;
1357 
1358 	if (RFS4_MANDATTR_ONLY)
1359 		return (ENOTSUP);
1360 
1361 	switch (cmd) {
1362 	case NFS4ATTR_SUPPORTED:
1363 		if (sarg->op == NFS4ATTR_SETIT)
1364 			error = EINVAL;
1365 		break;		/* this attr is supported */
1366 	case NFS4ATTR_GETIT:
1367 		if (sarg->rdattr_error && (sarg->sbp == NULL)) {
1368 			error = -1;	/* may be okay if rdattr_error */
1369 			break;
1370 		}
1371 		ASSERT(sarg->sbp != NULL);
1372 		na->files_avail = sarg->sbp->f_favail;
1373 		break;
1374 	case NFS4ATTR_SETIT:
1375 		/*
1376 		 * read-only attr
1377 		 */
1378 		error = EINVAL;
1379 		break;
1380 	case NFS4ATTR_VERIT:
1381 		ASSERT(sarg->sbp != NULL);
1382 		if (sarg->sbp->f_favail != na->files_avail)
1383 			error = -1;	/* no match */
1384 		break;
1385 	case NFS4ATTR_FREEIT:
1386 		break;
1387 	}
1388 	return (error);
1389 }
1390 
1391 /* ARGSUSED */
1392 static int
1393 rfs4_fattr4_files_free(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1394 	union nfs4_attr_u *na)
1395 {
1396 	int	error = 0;
1397 
1398 	if (RFS4_MANDATTR_ONLY)
1399 		return (ENOTSUP);
1400 
1401 	switch (cmd) {
1402 	case NFS4ATTR_SUPPORTED:
1403 		if (sarg->op == NFS4ATTR_SETIT)
1404 			error = EINVAL;
1405 		break;		/* this attr is supported */
1406 	case NFS4ATTR_GETIT:
1407 		if (sarg->rdattr_error && (sarg->sbp == NULL)) {
1408 			error = -1;	/* may be okay if rdattr_error */
1409 			break;
1410 		}
1411 		ASSERT(sarg->sbp != NULL);
1412 		na->files_free = sarg->sbp->f_ffree;
1413 		break;
1414 	case NFS4ATTR_SETIT:
1415 		/*
1416 		 * read-only attr
1417 		 */
1418 		error = EINVAL;
1419 		break;
1420 	case NFS4ATTR_VERIT:
1421 		ASSERT(sarg->sbp != NULL);
1422 		if (sarg->sbp->f_ffree != na->files_free)
1423 			error = -1;	/* no match */
1424 		break;
1425 	case NFS4ATTR_FREEIT:
1426 		break;
1427 	}
1428 	return (error);
1429 }
1430 
1431 /* ARGSUSED */
1432 static int
1433 rfs4_fattr4_files_total(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1434 	union nfs4_attr_u *na)
1435 {
1436 	int	error = 0;
1437 
1438 	if (RFS4_MANDATTR_ONLY)
1439 		return (ENOTSUP);
1440 
1441 	switch (cmd) {
1442 	case NFS4ATTR_SUPPORTED:
1443 		if (sarg->op == NFS4ATTR_SETIT)
1444 			error = EINVAL;
1445 		break;		/* this attr is supported */
1446 	case NFS4ATTR_GETIT:
1447 		if (sarg->rdattr_error && (sarg->sbp == NULL)) {
1448 			error = -1;	/* may be okay if rdattr_error */
1449 			break;
1450 		}
1451 		ASSERT(sarg->sbp != NULL);
1452 		na->files_total = sarg->sbp->f_files;
1453 		break;
1454 	case NFS4ATTR_SETIT:
1455 		/*
1456 		 * read-only attr
1457 		 */
1458 		error = EINVAL;
1459 		break;
1460 	case NFS4ATTR_VERIT:
1461 		ASSERT(sarg->sbp != NULL);
1462 		if (sarg->sbp->f_files != na->files_total)
1463 			error = -1;	/* no match */
1464 		break;
1465 	case NFS4ATTR_FREEIT:
1466 		break;
1467 	}
1468 	return (error);
1469 }
1470 
1471 /* ARGSUSED */
1472 static int
1473 rfs4_fattr4_fs_locations(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1474 	union nfs4_attr_u *na)
1475 {
1476 	return (ENOTSUP);
1477 }
1478 
1479 /* ARGSUSED */
1480 static int
1481 rfs4_fattr4_hidden(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1482 	union nfs4_attr_u *na)
1483 {
1484 	return (ENOTSUP);
1485 }
1486 
1487 /* ARGSUSED */
1488 static int
1489 rfs4_fattr4_homogeneous(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1490 	union nfs4_attr_u *na)
1491 {
1492 	int error = 0;
1493 
1494 	if (RFS4_MANDATTR_ONLY)
1495 		return (ENOTSUP);
1496 
1497 	switch (cmd) {
1498 	case NFS4ATTR_SUPPORTED:
1499 		if (sarg->op == NFS4ATTR_SETIT)
1500 			error = EINVAL;
1501 		break;		/* this attr is supported */
1502 	case NFS4ATTR_GETIT:
1503 		na->homogeneous = TRUE; /* XXX - need a VOP extension */
1504 		break;
1505 	case NFS4ATTR_SETIT:
1506 		/*
1507 		 * read-only attr
1508 		 */
1509 		error = EINVAL;
1510 		break;
1511 	case NFS4ATTR_VERIT:
1512 		if (!na->homogeneous)
1513 			error = -1;	/* no match */
1514 		break;
1515 	case NFS4ATTR_FREEIT:
1516 		break;
1517 	}
1518 	return (error);
1519 }
1520 
1521 /* ARGSUSED */
1522 static int
1523 rfs4_fattr4_maxfilesize(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1524 	union nfs4_attr_u *na)
1525 {
1526 	int error = 0;
1527 	ulong_t val;
1528 	fattr4_maxfilesize maxfilesize;
1529 
1530 	if (RFS4_MANDATTR_ONLY)
1531 		return (ENOTSUP);
1532 
1533 	switch (cmd) {
1534 	case NFS4ATTR_SUPPORTED:
1535 		if (sarg->op == NFS4ATTR_SETIT)
1536 			error = EINVAL;
1537 		break;		/* this attr is supported */
1538 	case NFS4ATTR_GETIT:
1539 		if (sarg->rdattr_error && (sarg->cs->vp == NULL)) {
1540 			error = -1;	/* may be okay if rdattr_error */
1541 			break;
1542 		}
1543 		ASSERT(sarg->cs->vp != NULL);
1544 		error = VOP_PATHCONF(sarg->cs->vp, _PC_FILESIZEBITS, &val,
1545 				sarg->cs->cr);
1546 		if (error)
1547 			break;
1548 		if (val >= (sizeof (uint64_t) * 8))
1549 			na->maxfilesize = UINT64_MAX;
1550 		else
1551 			na->maxfilesize = ((1LL << val) - 1);
1552 		break;
1553 	case NFS4ATTR_SETIT:
1554 		/*
1555 		 * read-only attr
1556 		 */
1557 		error = EINVAL;
1558 		break;
1559 	case NFS4ATTR_VERIT:
1560 		ASSERT(sarg->cs->vp != NULL);
1561 		error = VOP_PATHCONF(sarg->cs->vp, _PC_FILESIZEBITS, &val,
1562 				sarg->cs->cr);
1563 		if (error)
1564 			break;
1565 		if (val >= (sizeof (uint64_t) * 8))
1566 			maxfilesize = UINT64_MAX;
1567 		else
1568 			maxfilesize = ((1LL << val) - 1);
1569 		if (na->maxfilesize != maxfilesize)
1570 			error = -1;	/* no match */
1571 		break;
1572 	case NFS4ATTR_FREEIT:
1573 		break;
1574 	}
1575 	return (error);
1576 }
1577 
1578 /* ARGSUSED */
1579 static int
1580 rfs4_fattr4_maxlink(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1581 	union nfs4_attr_u *na)
1582 {
1583 	int error = 0;
1584 	ulong_t val;
1585 
1586 	if (RFS4_MANDATTR_ONLY)
1587 		return (ENOTSUP);
1588 
1589 	switch (cmd) {
1590 	case NFS4ATTR_SUPPORTED:
1591 		if (sarg->op == NFS4ATTR_SETIT)
1592 			error = EINVAL;
1593 		break;		/* this attr is supported */
1594 	case NFS4ATTR_GETIT:
1595 		if (sarg->rdattr_error && (sarg->cs->vp == NULL)) {
1596 			error = -1;	/* may be okay if rdattr_error */
1597 			break;
1598 		}
1599 		ASSERT(sarg->cs->vp != NULL);
1600 		error = VOP_PATHCONF(sarg->cs->vp, _PC_LINK_MAX, &val,
1601 				sarg->cs->cr);
1602 		if (error == 0) {
1603 			na->maxlink = val;
1604 		}
1605 		break;
1606 	case NFS4ATTR_SETIT:
1607 		/*
1608 		 * read-only attr
1609 		 */
1610 		error = EINVAL;
1611 		break;
1612 	case NFS4ATTR_VERIT:
1613 		ASSERT(sarg->cs->vp != NULL);
1614 		error = VOP_PATHCONF(sarg->cs->vp, _PC_LINK_MAX, &val,
1615 				sarg->cs->cr);
1616 		if (!error && (na->maxlink != val))
1617 			error = -1;	/* no match */
1618 		break;
1619 	case NFS4ATTR_FREEIT:
1620 		break;
1621 	}
1622 	return (error);
1623 }
1624 
1625 /* ARGSUSED */
1626 static int
1627 rfs4_fattr4_maxname(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1628 	union nfs4_attr_u *na)
1629 {
1630 	int error = 0;
1631 	ulong_t val;
1632 
1633 	if (RFS4_MANDATTR_ONLY)
1634 		return (ENOTSUP);
1635 
1636 	switch (cmd) {
1637 	case NFS4ATTR_SUPPORTED:
1638 		if (sarg->op == NFS4ATTR_SETIT)
1639 			error = EINVAL;
1640 		break;		/* this attr is supported */
1641 	case NFS4ATTR_GETIT:
1642 		if (sarg->rdattr_error && (sarg->cs->vp == NULL)) {
1643 			error = -1;	/* may be okay if rdattr_error */
1644 			break;
1645 		}
1646 		ASSERT(sarg->cs->vp != NULL);
1647 		error = VOP_PATHCONF(sarg->cs->vp, _PC_NAME_MAX, &val,
1648 				sarg->cs->cr);
1649 		if (error == 0) {
1650 			na->maxname = val;
1651 		}
1652 		break;
1653 	case NFS4ATTR_SETIT:
1654 		/*
1655 		 * read-only attr
1656 		 */
1657 		error = EINVAL;
1658 		break;
1659 	case NFS4ATTR_VERIT:
1660 		ASSERT(sarg->cs->vp != NULL);
1661 		error = VOP_PATHCONF(sarg->cs->vp, _PC_NAME_MAX, &val,
1662 				sarg->cs->cr);
1663 		if (!error && (na->maxname != val))
1664 			error = -1;	/* no match */
1665 		break;
1666 	case NFS4ATTR_FREEIT:
1667 		break;
1668 	}
1669 	return (error);
1670 }
1671 
1672 /* ARGSUSED */
1673 static int
1674 rfs4_fattr4_maxread(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1675 	union nfs4_attr_u *na)
1676 {
1677 	int error = 0;
1678 
1679 	if (RFS4_MANDATTR_ONLY)
1680 		return (ENOTSUP);
1681 
1682 	switch (cmd) {
1683 	case NFS4ATTR_SUPPORTED:
1684 		if (sarg->op == NFS4ATTR_SETIT)
1685 			error = EINVAL;
1686 		break;		/* this attr is supported */
1687 	case NFS4ATTR_GETIT:
1688 		na->maxread = rfs4_tsize(sarg->cs->req);
1689 		break;
1690 	case NFS4ATTR_SETIT:
1691 		/*
1692 		 * read-only attr
1693 		 */
1694 		error = EINVAL;
1695 		break;
1696 	case NFS4ATTR_VERIT:
1697 		if (na->maxread != rfs4_tsize(sarg->cs->req))
1698 			error = -1;	/* no match */
1699 		break;
1700 	case NFS4ATTR_FREEIT:
1701 		break;
1702 	}
1703 	return (error);
1704 }
1705 
1706 /* ARGSUSED */
1707 static int
1708 rfs4_fattr4_maxwrite(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1709 	union nfs4_attr_u *na)
1710 {
1711 	int error = 0;
1712 
1713 	if (RFS4_MANDATTR_ONLY)
1714 		return (ENOTSUP);
1715 
1716 	switch (cmd) {
1717 	case NFS4ATTR_SUPPORTED:
1718 		if (sarg->op == NFS4ATTR_SETIT)
1719 			error = EINVAL;
1720 		break;		/* this attr is supported */
1721 	case NFS4ATTR_GETIT:
1722 		na->maxwrite = rfs4_tsize(sarg->cs->req);
1723 		break;
1724 	case NFS4ATTR_SETIT:
1725 		/*
1726 		 * read-only attr
1727 		 */
1728 		error = EINVAL;
1729 		break;
1730 	case NFS4ATTR_VERIT:
1731 		if (na->maxwrite != rfs4_tsize(sarg->cs->req))
1732 			error = -1;	/* no match */
1733 		break;
1734 	case NFS4ATTR_FREEIT:
1735 		break;
1736 	}
1737 	return (error);
1738 }
1739 
1740 /* ARGSUSED */
1741 static int
1742 rfs4_fattr4_mimetype(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1743 	union nfs4_attr_u *na)
1744 {
1745 	return (ENOTSUP);
1746 }
1747 
1748 /* ARGSUSED */
1749 static int
1750 rfs4_fattr4_mode(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1751 	union nfs4_attr_u *na)
1752 {
1753 	int	error = 0;
1754 
1755 	if (RFS4_MANDATTR_ONLY)
1756 		return (ENOTSUP);
1757 
1758 	switch (cmd) {
1759 	case NFS4ATTR_SUPPORTED:
1760 		break;		/* this attr is supported */
1761 	case NFS4ATTR_GETIT:
1762 		if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_MODE)) {
1763 			error = -1;	/* may be okay if rdattr_error */
1764 			break;
1765 		}
1766 		ASSERT(sarg->vap->va_mask & AT_MODE);
1767 		na->mode = sarg->vap->va_mode;
1768 		break;
1769 	case NFS4ATTR_SETIT:
1770 		ASSERT(sarg->vap->va_mask & AT_MODE);
1771 		sarg->vap->va_mode = na->mode;
1772 		/*
1773 		 * If the filesystem is exported with nosuid, then mask off
1774 		 * the setuid and setgid bits.
1775 		 */
1776 		if (sarg->cs->vp->v_type == VREG &&
1777 			(sarg->cs->exi->exi_export.ex_flags & EX_NOSUID))
1778 			sarg->vap->va_mode &= ~(VSUID | VSGID);
1779 		break;
1780 	case NFS4ATTR_VERIT:
1781 		ASSERT(sarg->vap->va_mask & AT_MODE);
1782 		if (sarg->vap->va_mode != na->mode)
1783 			error = -1;	/* no match */
1784 		break;
1785 	case NFS4ATTR_FREEIT:
1786 		break;
1787 	}
1788 	return (error);
1789 }
1790 
1791 /* ARGSUSED */
1792 static int
1793 rfs4_fattr4_no_trunc(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1794 	union nfs4_attr_u *na)
1795 {
1796 	int error = 0;
1797 
1798 	if (RFS4_MANDATTR_ONLY)
1799 		return (ENOTSUP);
1800 
1801 	switch (cmd) {
1802 	case NFS4ATTR_SUPPORTED:
1803 		if (sarg->op == NFS4ATTR_SETIT)
1804 			error = EINVAL;
1805 		break;		/* this attr is supported */
1806 	case NFS4ATTR_GETIT:
1807 		na->no_trunc = TRUE;
1808 		break;
1809 	case NFS4ATTR_SETIT:
1810 		/*
1811 		 * read-only attr
1812 		 */
1813 		error = EINVAL;
1814 		break;
1815 	case NFS4ATTR_VERIT:
1816 		if (!na->no_trunc)
1817 			error = -1;	/* no match */
1818 		break;
1819 	case NFS4ATTR_FREEIT:
1820 		break;
1821 	}
1822 	return (error);
1823 }
1824 
1825 /* ARGSUSED */
1826 static int
1827 rfs4_fattr4_numlinks(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1828 	union nfs4_attr_u *na)
1829 {
1830 	int	error = 0;
1831 
1832 	if (RFS4_MANDATTR_ONLY)
1833 		return (ENOTSUP);
1834 
1835 	switch (cmd) {
1836 	case NFS4ATTR_SUPPORTED:
1837 		if (sarg->op == NFS4ATTR_SETIT)
1838 			error = EINVAL;
1839 		break;		/* this attr is supported */
1840 	case NFS4ATTR_GETIT:
1841 		if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_NLINK)) {
1842 			error = -1;	/* may be okay if rdattr_error */
1843 			break;
1844 		}
1845 		ASSERT(sarg->vap->va_mask & AT_NLINK);
1846 		na->numlinks = sarg->vap->va_nlink;
1847 		break;
1848 	case NFS4ATTR_SETIT:
1849 		/*
1850 		 * read-only attr
1851 		 */
1852 		error = EINVAL;
1853 		break;
1854 	case NFS4ATTR_VERIT:
1855 		ASSERT(sarg->vap->va_mask & AT_NLINK);
1856 		if (sarg->vap->va_nlink != na->numlinks)
1857 			error = -1;	/* no match */
1858 		break;
1859 	case NFS4ATTR_FREEIT:
1860 		break;
1861 	}
1862 	return (error);
1863 }
1864 
1865 /* ARGSUSED */
1866 static int
1867 rfs4_fattr4_owner(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1868 	union nfs4_attr_u *na)
1869 {
1870 	int	error = 0;
1871 	uid_t	uid;
1872 
1873 	if (RFS4_MANDATTR_ONLY)
1874 		return (ENOTSUP);
1875 
1876 	switch (cmd) {
1877 	case NFS4ATTR_SUPPORTED:
1878 		break;		/* this attr is supported */
1879 	case NFS4ATTR_GETIT:
1880 		if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_UID)) {
1881 			error = -1;	/* may be okay if rdattr_error */
1882 			break;
1883 		}
1884 		ASSERT(sarg->vap->va_mask & AT_UID);
1885 
1886 		/*
1887 		 * There are well defined polices for what happens on server-
1888 		 * side GETATTR when uid to attribute string conversion cannot
1889 		 * occur. Please refer to nfs4_idmap.c for details.
1890 		 */
1891 		error = nfs_idmap_uid_str(sarg->vap->va_uid, &na->owner, TRUE);
1892 		switch (error) {
1893 		case ECONNREFUSED:
1894 			error = NFS4ERR_DELAY;
1895 			break;
1896 		default:
1897 			break;
1898 		}
1899 		break;
1900 
1901 	case NFS4ATTR_SETIT:
1902 		ASSERT(sarg->vap->va_mask & AT_UID);
1903 
1904 		/*
1905 		 * There are well defined policies for what happens on server-
1906 		 * side SETATTR of 'owner' when a "user@domain" mapping cannot
1907 		 * occur. Please refer to nfs4_idmap.c for details.
1908 		 *
1909 		 * Any other errors, such as the mapping not being found by
1910 		 * nfsmapid(1m), and interrupted clnt_call, etc, will result
1911 		 * in NFS4ERR_BADOWNER.
1912 		 *
1913 		 * XXX need to return consistent errors, perhaps all
1914 		 * server side attribute routines should return NFS4ERR*.
1915 		 */
1916 		error = nfs_idmap_str_uid(&na->owner, &sarg->vap->va_uid, TRUE);
1917 		switch (error) {
1918 		case NFS4_OK:
1919 		case ENOTSUP:
1920 			/*
1921 			 * Ignore warning that we are the
1922 			 * nfsmapid (can't happen on srv)
1923 			 */
1924 			error = 0;
1925 			MSG_PRT_DEBUG = FALSE;
1926 			break;
1927 
1928 		case ECOMM:
1929 		case ECONNREFUSED:
1930 			if (!MSG_PRT_DEBUG) {
1931 				/*
1932 				 * printed just once per daemon death,
1933 				 * inform the user and then stay silent
1934 				 */
1935 				cmn_err(CE_WARN, "!Unable to contact "
1936 				    "nfsmapid");
1937 				MSG_PRT_DEBUG = TRUE;
1938 			}
1939 			error = NFS4ERR_DELAY;
1940 			break;
1941 
1942 		case EINVAL:
1943 			error = NFS4ERR_INVAL;
1944 			break;
1945 
1946 		default:
1947 			error = NFS4ERR_BADOWNER;
1948 			break;
1949 		}
1950 		break;
1951 
1952 	case NFS4ATTR_VERIT:
1953 		ASSERT(sarg->vap->va_mask & AT_UID);
1954 		error = nfs_idmap_str_uid(&na->owner, &uid, TRUE);
1955 		/*
1956 		 * Ignore warning that we are the nfsmapid (can't happen on srv)
1957 		 */
1958 		if (error == ENOTSUP)
1959 			error = 0;
1960 		if (error)
1961 			error = -1;	/* no match */
1962 		else if (sarg->vap->va_uid != uid)
1963 			error = -1;	/* no match */
1964 		break;
1965 	case NFS4ATTR_FREEIT:
1966 		if (sarg->op == NFS4ATTR_GETIT) {
1967 			if (na->owner.utf8string_val) {
1968 				UTF8STRING_FREE(na->owner)
1969 				bzero(&na->owner, sizeof (na->owner));
1970 			}
1971 		}
1972 		break;
1973 	}
1974 	return (error);
1975 }
1976 
1977 /* ARGSUSED */
1978 static int
1979 rfs4_fattr4_owner_group(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1980 	union nfs4_attr_u *na)
1981 {
1982 	int	error = 0;
1983 	gid_t	gid;
1984 
1985 	if (RFS4_MANDATTR_ONLY)
1986 		return (ENOTSUP);
1987 
1988 	switch (cmd) {
1989 	case NFS4ATTR_SUPPORTED:
1990 		break;		/* this attr is supported */
1991 	case NFS4ATTR_GETIT:
1992 		if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_GID)) {
1993 			error = -1;	/* may be okay if rdattr_error */
1994 			break;
1995 		}
1996 		ASSERT(sarg->vap->va_mask & AT_GID);
1997 
1998 		/*
1999 		 * There are well defined polices for what happens on server-
2000 		 * side GETATTR when gid to attribute string conversion cannot
2001 		 * occur. Please refer to nfs4_idmap.c for details.
2002 		 */
2003 		error = nfs_idmap_gid_str(sarg->vap->va_gid, &na->owner_group,
2004 		    TRUE);
2005 		switch (error) {
2006 		case ECONNREFUSED:
2007 			error = NFS4ERR_DELAY;
2008 			break;
2009 		default:
2010 			break;
2011 		}
2012 		break;
2013 
2014 	case NFS4ATTR_SETIT:
2015 		ASSERT(sarg->vap->va_mask & AT_GID);
2016 
2017 		/*
2018 		 * There are well defined policies for what happens on server-
2019 		 * side SETATTR of 'owner_group' when a "group@domain" mapping
2020 		 * cannot occur. Please refer to nfs4_idmap.c for details.
2021 		 *
2022 		 * Any other errors, such as the mapping not being found by
2023 		 * nfsmapid(1m), and interrupted clnt_call, etc, will result
2024 		 * in NFS4ERR_BADOWNER.
2025 		 *
2026 		 * XXX need to return consistent errors, perhaps all
2027 		 * server side attribute routines should return NFS4ERR*.
2028 		 */
2029 		error = nfs_idmap_str_gid(&na->owner_group, &sarg->vap->va_gid,
2030 		    TRUE);
2031 		switch (error) {
2032 		case NFS4_OK:
2033 		case ENOTSUP:
2034 			/*
2035 			 * Ignore warning that we are the
2036 			 * nfsmapid (can't happen on srv)
2037 			 */
2038 			error = 0;
2039 			MSG_PRT_DEBUG = FALSE;
2040 			break;
2041 
2042 		case ECOMM:
2043 		case ECONNREFUSED:
2044 			if (!MSG_PRT_DEBUG) {
2045 				/*
2046 				 * printed just once per daemon death,
2047 				 * inform the user and then stay silent
2048 				 */
2049 				cmn_err(CE_WARN, "!Unable to contact "
2050 				    "nfsmapid");
2051 				MSG_PRT_DEBUG = TRUE;
2052 			}
2053 			error = NFS4ERR_DELAY;
2054 			break;
2055 
2056 		case EINVAL:
2057 			error = NFS4ERR_INVAL;
2058 			break;
2059 
2060 		default:
2061 			error = NFS4ERR_BADOWNER;
2062 			break;
2063 		}
2064 		break;
2065 
2066 	case NFS4ATTR_VERIT:
2067 		ASSERT(sarg->vap->va_mask & AT_GID);
2068 		error = nfs_idmap_str_gid(&na->owner_group, &gid, TRUE);
2069 		/*
2070 		 * Ignore warning that we are the nfsmapid (can't happen on srv)
2071 		 */
2072 		if (error == ENOTSUP)
2073 			error = 0;
2074 		if (error)
2075 			error = -1;	/* no match */
2076 		else if (sarg->vap->va_gid != gid)
2077 			error = -1;	/* no match */
2078 		break;
2079 	case NFS4ATTR_FREEIT:
2080 		if (sarg->op == NFS4ATTR_GETIT) {
2081 			if (na->owner_group.utf8string_val) {
2082 				UTF8STRING_FREE(na->owner_group)
2083 				bzero(&na->owner_group,
2084 					sizeof (na->owner_group));
2085 			}
2086 		}
2087 		break;
2088 	}
2089 	return (error);
2090 }
2091 
2092 /* XXX - quota attributes should be supportable on Solaris 2 */
2093 /* ARGSUSED */
2094 static int
2095 rfs4_fattr4_quota_avail_hard(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2096 	union nfs4_attr_u *na)
2097 {
2098 	return (ENOTSUP);
2099 }
2100 
2101 /* ARGSUSED */
2102 static int
2103 rfs4_fattr4_quota_avail_soft(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2104 	union nfs4_attr_u *na)
2105 {
2106 	return (ENOTSUP);
2107 }
2108 
2109 /* ARGSUSED */
2110 static int
2111 rfs4_fattr4_quota_used(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2112 	union nfs4_attr_u *na)
2113 {
2114 	return (ENOTSUP);
2115 }
2116 
2117 /* ARGSUSED */
2118 static int
2119 rfs4_fattr4_rawdev(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2120 	union nfs4_attr_u *na)
2121 {
2122 	int	error = 0;
2123 
2124 	if (RFS4_MANDATTR_ONLY)
2125 		return (ENOTSUP);
2126 
2127 	switch (cmd) {
2128 	case NFS4ATTR_SUPPORTED:
2129 		if (sarg->op == NFS4ATTR_SETIT)
2130 			error = EINVAL;
2131 		break;		/* this attr is supported */
2132 	case NFS4ATTR_GETIT:
2133 		if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_RDEV)) {
2134 			error = -1;	/* may be okay if rdattr_error */
2135 			break;
2136 		}
2137 		ASSERT(sarg->vap->va_mask & AT_RDEV);
2138 		na->rawdev.specdata1 =  (uint32)getmajor(sarg->vap->va_rdev);
2139 		na->rawdev.specdata2 =  (uint32)getminor(sarg->vap->va_rdev);
2140 		break;
2141 	case NFS4ATTR_SETIT:
2142 		/*
2143 		 * read-only attr
2144 		 */
2145 		error = EINVAL;
2146 		break;
2147 	case NFS4ATTR_VERIT:
2148 		ASSERT(sarg->vap->va_mask & AT_RDEV);
2149 		if ((na->rawdev.specdata1 !=
2150 			(uint32)getmajor(sarg->vap->va_rdev)) ||
2151 		    (na->rawdev.specdata2 !=
2152 			(uint32)getminor(sarg->vap->va_rdev)))
2153 			error = -1;	/* no match */
2154 		break;
2155 	case NFS4ATTR_FREEIT:
2156 		break;
2157 	}
2158 	return (error);
2159 }
2160 
2161 /* ARGSUSED */
2162 static int
2163 rfs4_fattr4_space_avail(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2164 	union nfs4_attr_u *na)
2165 {
2166 	int	error = 0;
2167 
2168 	if (RFS4_MANDATTR_ONLY)
2169 		return (ENOTSUP);
2170 
2171 	switch (cmd) {
2172 	case NFS4ATTR_SUPPORTED:
2173 		if (sarg->op == NFS4ATTR_SETIT)
2174 			error = EINVAL;
2175 		break;		/* this attr is supported */
2176 	case NFS4ATTR_GETIT:
2177 		if (sarg->rdattr_error && (sarg->sbp == NULL)) {
2178 			error = -1;	/* may be okay if rdattr_error */
2179 			break;
2180 		}
2181 		ASSERT(sarg->sbp != NULL);
2182 		if (sarg->sbp->f_bavail != (fsblkcnt64_t)-1) {
2183 			na->space_avail =
2184 				(fattr4_space_avail) sarg->sbp->f_frsize *
2185 				(fattr4_space_avail) sarg->sbp->f_bavail;
2186 		} else {
2187 			na->space_avail =
2188 				(fattr4_space_avail) sarg->sbp->f_bavail;
2189 		}
2190 		break;
2191 	case NFS4ATTR_SETIT:
2192 		/*
2193 		 * read-only attr
2194 		 */
2195 		error = EINVAL;
2196 		break;
2197 	case NFS4ATTR_VERIT:
2198 		ASSERT(sarg->sbp != NULL);
2199 		if (sarg->sbp->f_bavail != na->space_avail)
2200 			error = -1;	/* no match */
2201 		break;
2202 	case NFS4ATTR_FREEIT:
2203 		break;
2204 	}
2205 	return (error);
2206 }
2207 
2208 /* ARGSUSED */
2209 static int
2210 rfs4_fattr4_space_free(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2211 	union nfs4_attr_u *na)
2212 {
2213 	int	error = 0;
2214 
2215 	if (RFS4_MANDATTR_ONLY)
2216 		return (ENOTSUP);
2217 
2218 	switch (cmd) {
2219 	case NFS4ATTR_SUPPORTED:
2220 		if (sarg->op == NFS4ATTR_SETIT)
2221 			error = EINVAL;
2222 		break;		/* this attr is supported */
2223 	case NFS4ATTR_GETIT:
2224 		if (sarg->rdattr_error && (sarg->sbp == NULL)) {
2225 			error = -1;	/* may be okay if rdattr_error */
2226 			break;
2227 		}
2228 		ASSERT(sarg->sbp != NULL);
2229 		if (sarg->sbp->f_bfree != (fsblkcnt64_t)-1) {
2230 			na->space_free =
2231 				(fattr4_space_free) sarg->sbp->f_frsize *
2232 				(fattr4_space_free) sarg->sbp->f_bfree;
2233 		} else {
2234 			na->space_free =
2235 				(fattr4_space_free) sarg->sbp->f_bfree;
2236 		}
2237 		break;
2238 	case NFS4ATTR_SETIT:
2239 		/*
2240 		 * read-only attr
2241 		 */
2242 		error = EINVAL;
2243 		break;
2244 	case NFS4ATTR_VERIT:
2245 		ASSERT(sarg->sbp != NULL);
2246 		if (sarg->sbp->f_bfree != na->space_free)
2247 			error = -1;	/* no match */
2248 		break;
2249 	case NFS4ATTR_FREEIT:
2250 		break;
2251 	}
2252 	return (error);
2253 }
2254 
2255 /* ARGSUSED */
2256 static int
2257 rfs4_fattr4_space_total(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2258 	union nfs4_attr_u *na)
2259 {
2260 	int	error = 0;
2261 
2262 	if (RFS4_MANDATTR_ONLY)
2263 		return (ENOTSUP);
2264 
2265 	switch (cmd) {
2266 	case NFS4ATTR_SUPPORTED:
2267 		if (sarg->op == NFS4ATTR_SETIT)
2268 			error = EINVAL;
2269 		break;		/* this attr is supported */
2270 	case NFS4ATTR_GETIT:
2271 		if (sarg->rdattr_error_req && (sarg->sbp == NULL)) {
2272 			error = -1;	/* may be okay if rdattr_error */
2273 			break;
2274 		}
2275 		ASSERT(sarg->sbp != NULL);
2276 		if (sarg->sbp->f_blocks != (fsblkcnt64_t)-1) {
2277 			na->space_total =
2278 				(fattr4_space_total) sarg->sbp->f_frsize *
2279 				(fattr4_space_total) sarg->sbp->f_blocks;
2280 		} else {
2281 			na->space_total =
2282 				(fattr4_space_total) sarg->sbp->f_blocks;
2283 		}
2284 		break;
2285 	case NFS4ATTR_SETIT:
2286 		/*
2287 		 * read-only attr
2288 		 */
2289 		error = EINVAL;
2290 		break;
2291 	case NFS4ATTR_VERIT:
2292 		ASSERT(sarg->sbp != NULL);
2293 		if (sarg->sbp->f_blocks != na->space_total)
2294 			error = -1;	/* no match */
2295 		break;
2296 	case NFS4ATTR_FREEIT:
2297 		break;
2298 	}
2299 	return (error);
2300 }
2301 
2302 /* ARGSUSED */
2303 static int
2304 rfs4_fattr4_space_used(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2305 	union nfs4_attr_u *na)
2306 {
2307 	int	error = 0;
2308 
2309 	if (RFS4_MANDATTR_ONLY)
2310 		return (ENOTSUP);
2311 
2312 	switch (cmd) {
2313 	case NFS4ATTR_SUPPORTED:
2314 		if (sarg->op == NFS4ATTR_SETIT)
2315 			error = EINVAL;
2316 		break;		/* this attr is supported */
2317 	case NFS4ATTR_GETIT:
2318 		if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_NBLOCKS)) {
2319 			error = -1;	/* may be okay if rdattr_error */
2320 			break;
2321 		}
2322 		ASSERT(sarg->vap->va_mask & AT_NBLOCKS);
2323 		na->space_used =  (fattr4_space_used) DEV_BSIZE *
2324 			(fattr4_space_used) sarg->vap->va_nblocks;
2325 		break;
2326 	case NFS4ATTR_SETIT:
2327 		/*
2328 		 * read-only attr
2329 		 */
2330 		error = EINVAL;
2331 		break;
2332 	case NFS4ATTR_VERIT:
2333 		ASSERT(sarg->vap->va_mask & AT_NBLOCKS);
2334 		if (sarg->vap->va_nblocks != na->space_used)
2335 			error = -1;	/* no match */
2336 		break;
2337 	case NFS4ATTR_FREEIT:
2338 		break;
2339 	}
2340 	return (error);
2341 }
2342 
2343 /* ARGSUSED */
2344 static int
2345 rfs4_fattr4_system(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2346 	union nfs4_attr_u *na)
2347 {
2348 	return (ENOTSUP);
2349 }
2350 
2351 /* ARGSUSED */
2352 static int
2353 rfs4_fattr4_time_access(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2354 	union nfs4_attr_u *na)
2355 {
2356 	int	error = 0;
2357 	timestruc_t atime;
2358 
2359 	if (RFS4_MANDATTR_ONLY)
2360 		return (ENOTSUP);
2361 
2362 	switch (cmd) {
2363 	case NFS4ATTR_SUPPORTED:
2364 		if (sarg->op == NFS4ATTR_SETIT)
2365 			error = EINVAL;
2366 		break;		/* this attr is supported */
2367 	case NFS4ATTR_GETIT:
2368 		if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_ATIME)) {
2369 			error = -1;	/* may be okay if rdattr_error */
2370 			break;
2371 		}
2372 		ASSERT(sarg->vap->va_mask & AT_ATIME);
2373 		error = nfs4_time_vton(&sarg->vap->va_atime, &na->time_access);
2374 		break;
2375 	case NFS4ATTR_SETIT:
2376 		/*
2377 		 * read-only attr
2378 		 */
2379 		error = EINVAL;
2380 		break;
2381 	case NFS4ATTR_VERIT:
2382 		ASSERT(sarg->vap->va_mask & AT_ATIME);
2383 		error = nfs4_time_ntov(&na->time_access, &atime);
2384 		if (error)
2385 			break;
2386 		if (bcmp(&atime, &sarg->vap->va_atime, sizeof (atime)))
2387 			error = -1;	/* no match */
2388 		break;
2389 	case NFS4ATTR_FREEIT:
2390 		break;
2391 	}
2392 	return (error);
2393 }
2394 
2395 /*
2396  * XXX - need to support the setting of access time
2397  */
2398 /* ARGSUSED */
2399 static int
2400 rfs4_fattr4_time_access_set(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2401 	union nfs4_attr_u *na)
2402 {
2403 	int	error = 0;
2404 	settime4 *ta;
2405 
2406 	if (RFS4_MANDATTR_ONLY)
2407 		return (ENOTSUP);
2408 
2409 	switch (cmd) {
2410 	case NFS4ATTR_SUPPORTED:
2411 		if ((sarg->op == NFS4ATTR_GETIT) ||
2412 		    (sarg->op == NFS4ATTR_VERIT))
2413 			error = EINVAL;
2414 		break;		/* this attr is supported */
2415 	case NFS4ATTR_GETIT:
2416 	case NFS4ATTR_VERIT:
2417 		/*
2418 		 * write only attr
2419 		 */
2420 		error = EINVAL;
2421 		break;
2422 	case NFS4ATTR_SETIT:
2423 		ASSERT(sarg->vap->va_mask & AT_ATIME);
2424 		/*
2425 		 * Set access time (by server or by client)
2426 		 */
2427 		ta = &na->time_access_set;
2428 		if (ta->set_it == SET_TO_CLIENT_TIME4) {
2429 			error = nfs4_time_ntov(&ta->time, &sarg->vap->va_atime);
2430 		} else if (ta->set_it == SET_TO_SERVER_TIME4) {
2431 			gethrestime(&sarg->vap->va_atime);
2432 		} else {
2433 			error = EINVAL;
2434 		}
2435 		break;
2436 	case NFS4ATTR_FREEIT:
2437 		break;
2438 	}
2439 	return (error);
2440 }
2441 
2442 /* ARGSUSED */
2443 static int
2444 rfs4_fattr4_time_backup(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2445 	union nfs4_attr_u *na)
2446 {
2447 	return (ENOTSUP);
2448 }
2449 
2450 /* ARGSUSED */
2451 static int
2452 rfs4_fattr4_time_create(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2453 	union nfs4_attr_u *na)
2454 {
2455 	return (ENOTSUP);
2456 }
2457 
2458 /* ARGSUSED */
2459 static int
2460 rfs4_fattr4_time_delta(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2461 	union nfs4_attr_u *na)
2462 {
2463 	int error = 0;
2464 
2465 	if (RFS4_MANDATTR_ONLY)
2466 		return (ENOTSUP);
2467 
2468 	switch (cmd) {
2469 	case NFS4ATTR_SUPPORTED:
2470 		if (sarg->op == NFS4ATTR_SETIT)
2471 			error = EINVAL;
2472 		break;		/* this attr is supported */
2473 	case NFS4ATTR_GETIT:
2474 		na->time_delta.seconds = 0;
2475 		na->time_delta.nseconds = 1000;
2476 		break;
2477 	case NFS4ATTR_SETIT:
2478 		/*
2479 		 * write only attr
2480 		 */
2481 		error = EINVAL;
2482 		break;
2483 	case NFS4ATTR_VERIT:
2484 		if ((na->time_delta.seconds != 0) ||
2485 		    (na->time_delta.nseconds != 1000))
2486 			error = -1;	/* no match */
2487 		break;
2488 	case NFS4ATTR_FREEIT:
2489 		break;
2490 	}
2491 	return (error);
2492 }
2493 
2494 /* ARGSUSED */
2495 static int
2496 rfs4_fattr4_time_metadata(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2497 	union nfs4_attr_u *na)
2498 {
2499 	int	error = 0;
2500 	timestruc_t ctime;
2501 
2502 	if (RFS4_MANDATTR_ONLY)
2503 		return (ENOTSUP);
2504 
2505 	switch (cmd) {
2506 	case NFS4ATTR_SUPPORTED:
2507 		if (sarg->op == NFS4ATTR_SETIT)
2508 			error = EINVAL;
2509 		break;		/* this attr is supported */
2510 	case NFS4ATTR_GETIT:
2511 		if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_CTIME)) {
2512 			error = -1;	/* may be okay if rdattr_error */
2513 			break;
2514 		}
2515 		ASSERT(sarg->vap->va_mask & AT_CTIME);
2516 		error = nfs4_time_vton(&sarg->vap->va_ctime,
2517 				&na->time_metadata);
2518 		break;
2519 	case NFS4ATTR_SETIT:
2520 		/*
2521 		 * read-only attr
2522 		 */
2523 		error = EINVAL;
2524 		break;
2525 	case NFS4ATTR_VERIT:
2526 		ASSERT(sarg->vap->va_mask & AT_CTIME);
2527 		error = nfs4_time_ntov(&na->time_metadata, &ctime);
2528 		if (error)
2529 			break;
2530 		if (bcmp(&ctime, &sarg->vap->va_ctime, sizeof (ctime)))
2531 			error = -1;	/* no match */
2532 		break;
2533 	case NFS4ATTR_FREEIT:
2534 		break;
2535 	}
2536 	return (error);
2537 }
2538 
2539 /* ARGSUSED */
2540 static int
2541 rfs4_fattr4_time_modify(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2542 	union nfs4_attr_u *na)
2543 {
2544 	int	error = 0;
2545 	timestruc_t mtime;
2546 
2547 	if (RFS4_MANDATTR_ONLY)
2548 		return (ENOTSUP);
2549 
2550 	switch (cmd) {
2551 	case NFS4ATTR_SUPPORTED:
2552 		if (sarg->op == NFS4ATTR_SETIT)
2553 			error = EINVAL;
2554 		break;		/* this attr is supported */
2555 	case NFS4ATTR_GETIT:
2556 		if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_MTIME)) {
2557 			error = -1;	/* may be okay if rdattr_error */
2558 			break;
2559 		}
2560 		ASSERT(sarg->vap->va_mask & AT_MTIME);
2561 		error = nfs4_time_vton(&sarg->vap->va_mtime, &na->time_modify);
2562 		break;
2563 	case NFS4ATTR_SETIT:
2564 		/*
2565 		 * read-only attr
2566 		 */
2567 		error = EINVAL;
2568 		break;
2569 	case NFS4ATTR_VERIT:
2570 		ASSERT(sarg->vap->va_mask & AT_MTIME);
2571 		error = nfs4_time_ntov(&na->time_modify, &mtime);
2572 		if (error)
2573 			break;
2574 		if (bcmp(&mtime, &sarg->vap->va_mtime, sizeof (mtime)))
2575 			error = -1;	/* no match */
2576 		break;
2577 	case NFS4ATTR_FREEIT:
2578 		break;
2579 	}
2580 	return (error);
2581 }
2582 
2583 /*
2584  * XXX - need to add support for setting modify time
2585  */
2586 /* ARGSUSED */
2587 static int
2588 rfs4_fattr4_time_modify_set(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2589 	union nfs4_attr_u *na)
2590 {
2591 	int	error = 0;
2592 	settime4 *tm;
2593 
2594 	if (RFS4_MANDATTR_ONLY)
2595 		return (ENOTSUP);
2596 
2597 	switch (cmd) {
2598 	case NFS4ATTR_SUPPORTED:
2599 		if ((sarg->op == NFS4ATTR_GETIT) ||
2600 		    (sarg->op == NFS4ATTR_VERIT))
2601 			error = EINVAL;
2602 		break;		/* this attr is supported */
2603 	case NFS4ATTR_GETIT:
2604 	case NFS4ATTR_VERIT:
2605 		/*
2606 		 * write only attr
2607 		 */
2608 		error = EINVAL;
2609 		break;
2610 	case NFS4ATTR_SETIT:
2611 		ASSERT(sarg->vap->va_mask & AT_MTIME);
2612 		/*
2613 		 * Set modify time (by server or by client)
2614 		 */
2615 		tm = &na->time_modify_set;
2616 		if (tm->set_it == SET_TO_CLIENT_TIME4) {
2617 			error = nfs4_time_ntov(&tm->time, &sarg->vap->va_mtime);
2618 			sarg->flag = ATTR_UTIME;
2619 		} else if (tm->set_it == SET_TO_SERVER_TIME4) {
2620 			gethrestime(&sarg->vap->va_mtime);
2621 		} else {
2622 			error = EINVAL;
2623 		}
2624 		break;
2625 	case NFS4ATTR_FREEIT:
2626 		break;
2627 	}
2628 	return (error);
2629 }
2630 
2631 
2632 static void
2633 rfs4_ntov_init(void)
2634 {
2635 	/* index must be same as corresponding FATTR4_* define */
2636 	nfs4_ntov_map[0].sv_getit = rfs4_fattr4_supported_attrs;
2637 	nfs4_ntov_map[1].sv_getit = rfs4_fattr4_type;
2638 	nfs4_ntov_map[2].sv_getit = rfs4_fattr4_fh_expire_type;
2639 	nfs4_ntov_map[3].sv_getit = rfs4_fattr4_change;
2640 	nfs4_ntov_map[4].sv_getit = rfs4_fattr4_size;
2641 	nfs4_ntov_map[5].sv_getit = rfs4_fattr4_link_support;
2642 	nfs4_ntov_map[6].sv_getit = rfs4_fattr4_symlink_support;
2643 	nfs4_ntov_map[7].sv_getit = rfs4_fattr4_named_attr;
2644 	nfs4_ntov_map[8].sv_getit = rfs4_fattr4_fsid;
2645 	nfs4_ntov_map[9].sv_getit = rfs4_fattr4_unique_handles;
2646 	nfs4_ntov_map[10].sv_getit = rfs4_fattr4_lease_time;
2647 	nfs4_ntov_map[11].sv_getit = rfs4_fattr4_rdattr_error;
2648 	nfs4_ntov_map[12].sv_getit = rfs4_fattr4_acl;
2649 	nfs4_ntov_map[13].sv_getit = rfs4_fattr4_aclsupport;
2650 	nfs4_ntov_map[14].sv_getit = rfs4_fattr4_archive;
2651 	nfs4_ntov_map[15].sv_getit = rfs4_fattr4_cansettime;
2652 	nfs4_ntov_map[16].sv_getit = rfs4_fattr4_case_insensitive;
2653 	nfs4_ntov_map[17].sv_getit = rfs4_fattr4_case_preserving;
2654 	nfs4_ntov_map[18].sv_getit = rfs4_fattr4_chown_restricted;
2655 	nfs4_ntov_map[19].sv_getit = rfs4_fattr4_filehandle;
2656 	nfs4_ntov_map[20].sv_getit = rfs4_fattr4_fileid;
2657 	nfs4_ntov_map[21].sv_getit = rfs4_fattr4_files_avail;
2658 	nfs4_ntov_map[22].sv_getit = rfs4_fattr4_files_free;
2659 	nfs4_ntov_map[23].sv_getit = rfs4_fattr4_files_total;
2660 	nfs4_ntov_map[24].sv_getit = rfs4_fattr4_fs_locations;
2661 	nfs4_ntov_map[25].sv_getit = rfs4_fattr4_hidden;
2662 	nfs4_ntov_map[26].sv_getit = rfs4_fattr4_homogeneous;
2663 	nfs4_ntov_map[27].sv_getit = rfs4_fattr4_maxfilesize;
2664 	nfs4_ntov_map[28].sv_getit = rfs4_fattr4_maxlink;
2665 	nfs4_ntov_map[29].sv_getit = rfs4_fattr4_maxname;
2666 	nfs4_ntov_map[30].sv_getit = rfs4_fattr4_maxread;
2667 	nfs4_ntov_map[31].sv_getit = rfs4_fattr4_maxwrite;
2668 	nfs4_ntov_map[32].sv_getit = rfs4_fattr4_mimetype;
2669 	nfs4_ntov_map[33].sv_getit = rfs4_fattr4_mode;
2670 	nfs4_ntov_map[34].sv_getit = rfs4_fattr4_no_trunc;
2671 	nfs4_ntov_map[35].sv_getit = rfs4_fattr4_numlinks;
2672 	nfs4_ntov_map[36].sv_getit = rfs4_fattr4_owner;
2673 	nfs4_ntov_map[37].sv_getit = rfs4_fattr4_owner_group;
2674 	nfs4_ntov_map[38].sv_getit = rfs4_fattr4_quota_avail_hard;
2675 	nfs4_ntov_map[39].sv_getit = rfs4_fattr4_quota_avail_soft;
2676 	nfs4_ntov_map[40].sv_getit = rfs4_fattr4_quota_used;
2677 	nfs4_ntov_map[41].sv_getit = rfs4_fattr4_rawdev;
2678 	nfs4_ntov_map[42].sv_getit = rfs4_fattr4_space_avail;
2679 	nfs4_ntov_map[43].sv_getit = rfs4_fattr4_space_free;
2680 	nfs4_ntov_map[44].sv_getit = rfs4_fattr4_space_total;
2681 	nfs4_ntov_map[45].sv_getit = rfs4_fattr4_space_used;
2682 	nfs4_ntov_map[46].sv_getit = rfs4_fattr4_system;
2683 	nfs4_ntov_map[47].sv_getit = rfs4_fattr4_time_access;
2684 	nfs4_ntov_map[48].sv_getit = rfs4_fattr4_time_access_set;
2685 	nfs4_ntov_map[49].sv_getit = rfs4_fattr4_time_backup;
2686 	nfs4_ntov_map[50].sv_getit = rfs4_fattr4_time_create;
2687 	nfs4_ntov_map[51].sv_getit = rfs4_fattr4_time_delta;
2688 	nfs4_ntov_map[52].sv_getit = rfs4_fattr4_time_metadata;
2689 	nfs4_ntov_map[53].sv_getit = rfs4_fattr4_time_modify;
2690 	nfs4_ntov_map[54].sv_getit = rfs4_fattr4_time_modify_set;
2691 	nfs4_ntov_map[55].sv_getit = rfs4_fattr4_mounted_on_fileid;
2692 }
2693