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