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