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