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