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