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