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