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 #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);
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 			if (error != 0)
1022 				break;
1023 			(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
1024 			error = VOP_SETSECATTR(vp, &vs_native,
1025 			    0, sarg->cs->cr, NULL);
1026 			VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
1027 			vs_aent_destroy(&vs_native);
1028 		}
1029 		break;
1030 
1031 	case NFS4ATTR_FREEIT:
1032 		if (sarg->op == NFS4ATTR_GETIT) {
1033 			vs_ace4.vsa_mask = VSA_ACE | VSA_ACECNT;
1034 			vs_ace4.vsa_aclcnt = na->acl.fattr4_acl_len;
1035 			vs_ace4.vsa_aclentp = na->acl.fattr4_acl_val;
1036 			vs_ace4_destroy(&vs_ace4);
1037 		}
1038 		break;
1039 	}
1040 
1041 	return (error);
1042 }
1043 
1044 /* ARGSUSED */
1045 static int
1046 rfs4_fattr4_aclsupport(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1047 	union nfs4_attr_u *na)
1048 {
1049 	int error = 0;
1050 
1051 	if (RFS4_MANDATTR_ONLY)
1052 		return (ENOTSUP);
1053 
1054 	switch (cmd) {
1055 	case NFS4ATTR_SUPPORTED:
1056 		if (sarg->op == NFS4ATTR_SETIT)
1057 			error = EINVAL;
1058 		break;	/* supported */
1059 	case NFS4ATTR_GETIT:
1060 		na->aclsupport = ACL4_SUPPORT_ALLOW_ACL |
1061 		    ACL4_SUPPORT_DENY_ACL;
1062 		break;
1063 	case NFS4ATTR_SETIT:
1064 		error = EINVAL;
1065 		break;
1066 	case NFS4ATTR_VERIT:
1067 		if (na->aclsupport != (ACL4_SUPPORT_ALLOW_ACL |
1068 		    ACL4_SUPPORT_DENY_ACL))
1069 			error = -1;	/* no match */
1070 		break;
1071 	}
1072 
1073 	return (error);
1074 }
1075 
1076 /* ARGSUSED */
1077 static int
1078 rfs4_fattr4_archive(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1079 	union nfs4_attr_u *na)
1080 {
1081 	return (ENOTSUP);
1082 }
1083 
1084 /* ARGSUSED */
1085 static int
1086 rfs4_fattr4_cansettime(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1087 	union nfs4_attr_u *na)
1088 {
1089 	int error = 0;
1090 
1091 	if (RFS4_MANDATTR_ONLY)
1092 		return (ENOTSUP);
1093 
1094 	switch (cmd) {
1095 	case NFS4ATTR_SUPPORTED:
1096 		if (sarg->op == NFS4ATTR_SETIT)
1097 			error = EINVAL;
1098 		break;		/* this attr is supported */
1099 	case NFS4ATTR_GETIT:
1100 		na->cansettime = TRUE;
1101 		break;
1102 	case NFS4ATTR_SETIT:
1103 		/*
1104 		 * read-only attr
1105 		 */
1106 		error = EINVAL;
1107 		break;
1108 	case NFS4ATTR_VERIT:
1109 		if (!na->cansettime)
1110 			error = -1;	/* no match */
1111 		break;
1112 	case NFS4ATTR_FREEIT:
1113 		break;
1114 	}
1115 	return (error);
1116 }
1117 
1118 /*
1119  * XXX - need VOP extension to ask file system (e.g. pcfs) if it supports
1120  * case insensitive.
1121  */
1122 /* ARGSUSED */
1123 static int
1124 rfs4_fattr4_case_insensitive(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1125 	union nfs4_attr_u *na)
1126 {
1127 	int error = 0;
1128 
1129 	if (RFS4_MANDATTR_ONLY)
1130 		return (ENOTSUP);
1131 
1132 	switch (cmd) {
1133 	case NFS4ATTR_SUPPORTED:
1134 		if (sarg->op == NFS4ATTR_SETIT)
1135 			error = EINVAL;
1136 		break;		/* this attr is supported */
1137 	case NFS4ATTR_GETIT:
1138 		na->case_insensitive = FALSE;
1139 		break;
1140 	case NFS4ATTR_SETIT:
1141 		/*
1142 		 * read-only attr
1143 		 */
1144 		error = EINVAL;
1145 		break;
1146 	case NFS4ATTR_VERIT:
1147 		if (!na->case_insensitive)
1148 			error = -1;	/* no match */
1149 		break;
1150 	case NFS4ATTR_FREEIT:
1151 		break;
1152 	}
1153 	return (error);
1154 }
1155 
1156 /* ARGSUSED */
1157 static int
1158 rfs4_fattr4_case_preserving(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1159 	union nfs4_attr_u *na)
1160 {
1161 	int error = 0;
1162 
1163 	if (RFS4_MANDATTR_ONLY)
1164 		return (ENOTSUP);
1165 
1166 	switch (cmd) {
1167 	case NFS4ATTR_SUPPORTED:
1168 		if (sarg->op == NFS4ATTR_SETIT)
1169 			error = EINVAL;
1170 		break;		/* this attr is supported */
1171 	case NFS4ATTR_GETIT:
1172 		na->case_preserving = TRUE;
1173 		break;
1174 	case NFS4ATTR_SETIT:
1175 		/*
1176 		 * read-only attr
1177 		 */
1178 		error = EINVAL;
1179 		break;
1180 	case NFS4ATTR_VERIT:
1181 		if (!na->case_preserving)
1182 			error = -1;	/* no match */
1183 		break;
1184 	case NFS4ATTR_FREEIT:
1185 		break;
1186 	}
1187 	return (error);
1188 }
1189 
1190 /* fattr4_chown_restricted should reall be fattr4_chown_allowed */
1191 /* ARGSUSED */
1192 static int
1193 rfs4_fattr4_chown_restricted(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1194 	union nfs4_attr_u *na)
1195 {
1196 	int error = 0;
1197 	ulong_t val;
1198 
1199 	if (RFS4_MANDATTR_ONLY)
1200 		return (ENOTSUP);
1201 
1202 	switch (cmd) {
1203 	case NFS4ATTR_SUPPORTED:
1204 		if (sarg->op == NFS4ATTR_SETIT)
1205 			error = EINVAL;
1206 		break;		/* this attr is supported */
1207 	case NFS4ATTR_GETIT:
1208 		if (sarg->rdattr_error && (sarg->cs->vp == NULL)) {
1209 			error = -1;	/* may be okay if rdattr_error */
1210 			break;
1211 		}
1212 		ASSERT(sarg->cs->vp != NULL);
1213 		error = VOP_PATHCONF(sarg->cs->vp,
1214 		    _PC_CHOWN_RESTRICTED, &val, sarg->cs->cr, NULL);
1215 		if (error)
1216 			break;
1217 
1218 		na->chown_restricted = (val == 1);
1219 		break;
1220 	case NFS4ATTR_SETIT:
1221 		/*
1222 		 * read-only attr
1223 		 */
1224 		error = EINVAL;
1225 		break;
1226 	case NFS4ATTR_VERIT:
1227 		ASSERT(sarg->cs->vp != NULL);
1228 		error = VOP_PATHCONF(sarg->cs->vp,
1229 		    _PC_CHOWN_RESTRICTED, &val, sarg->cs->cr, NULL);
1230 		if (error)
1231 			break;
1232 		if (na->chown_restricted != (val == 1))
1233 			error = -1;	/* no match */
1234 		break;
1235 	case NFS4ATTR_FREEIT:
1236 		break;
1237 	}
1238 	return (error);
1239 }
1240 
1241 /* ARGSUSED */
1242 static int
1243 rfs4_fattr4_fileid(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1244 	union nfs4_attr_u *na)
1245 {
1246 	int	error = 0;
1247 
1248 	if (RFS4_MANDATTR_ONLY)
1249 		return (ENOTSUP);
1250 
1251 	switch (cmd) {
1252 	case NFS4ATTR_SUPPORTED:
1253 		if (sarg->op == NFS4ATTR_SETIT)
1254 			error = EINVAL;
1255 		break;		/* this attr is supported */
1256 	case NFS4ATTR_GETIT:
1257 		if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_NODEID)) {
1258 			error = -1;	/* may be okay if rdattr_error */
1259 			break;
1260 		}
1261 		ASSERT(sarg->vap->va_mask & AT_NODEID);
1262 		na->fileid = sarg->vap->va_nodeid;
1263 		break;
1264 	case NFS4ATTR_SETIT:
1265 		/*
1266 		 * read-only attr
1267 		 */
1268 		error = EINVAL;
1269 		break;
1270 	case NFS4ATTR_VERIT:
1271 		ASSERT(sarg->vap->va_mask & AT_NODEID);
1272 		if (sarg->vap->va_nodeid != na->fileid)
1273 			error = -1;	/* no match */
1274 		break;
1275 	case NFS4ATTR_FREEIT:
1276 		break;
1277 	}
1278 	return (error);
1279 }
1280 
1281 /* ARGSUSED */
1282 static int
1283 rfs4_get_mntdfileid(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg)
1284 {
1285 	int error = 0;
1286 	vattr_t	*vap, va;
1287 	vnode_t *stubvp = NULL, *vp;
1288 
1289 	vp = sarg->cs->vp;
1290 	sarg->mntdfid_set = FALSE;
1291 
1292 	/* VROOT object, must untraverse */
1293 	if (vp->v_flag & VROOT) {
1294 
1295 		/* extra hold for vp since untraverse might rele */
1296 		VN_HOLD(vp);
1297 		stubvp = untraverse(vp);
1298 
1299 		/*
1300 		 * If vp/stubvp are same, we must be at system
1301 		 * root because untraverse returned same vp
1302 		 * for a VROOT object.  sarg->vap was setup
1303 		 * before we got here, so there's no need to do
1304 		 * another getattr -- just use the one in sarg.
1305 		 */
1306 		if (VN_CMP(vp, stubvp)) {
1307 			ASSERT(VN_CMP(vp, rootdir));
1308 			vap = sarg->vap;
1309 		} else {
1310 			va.va_mask = AT_NODEID;
1311 			vap = &va;
1312 			error = rfs4_vop_getattr(stubvp, vap, 0, sarg->cs->cr);
1313 		}
1314 
1315 		/*
1316 		 * Done with stub, time to rele.  If vp and stubvp
1317 		 * were the same, then we need to rele either vp or
1318 		 * stubvp.  If they weren't the same, then untraverse()
1319 		 * already took case of the extra hold on vp, and only
1320 		 * the stub needs to be rele'd.  Both cases are handled
1321 		 * by unconditionally rele'ing the stub.
1322 		 */
1323 		VN_RELE(stubvp);
1324 	} else
1325 		vap = sarg->vap;
1326 
1327 	/*
1328 	 * At this point, vap should contain "correct" AT_NODEID --
1329 	 * (for V_ROOT case, nodeid of stub, for non-VROOT case,
1330 	 * nodeid of vp).  If error or AT_NODEID not available, then
1331 	 * make the obligatory (yet mysterious) rdattr_error
1332 	 * check that is so common in the attr code.
1333 	 */
1334 	if (!error && (vap->va_mask & AT_NODEID)) {
1335 		sarg->mounted_on_fileid = vap->va_nodeid;
1336 		sarg->mntdfid_set = TRUE;
1337 	} else if (sarg->rdattr_error)
1338 		error = -1;
1339 
1340 	/*
1341 	 * error describes these cases:
1342 	 *	0 : success
1343 	 *	-1: failure due to previous attr processing error (rddir only).
1344 	 *	* : new attr failure  (if rddir, caller will set rdattr_error)
1345 	 */
1346 	return (error);
1347 }
1348 
1349 /* ARGSUSED */
1350 static int
1351 rfs4_fattr4_mounted_on_fileid(nfs4_attr_cmd_t cmd,
1352 	struct nfs4_svgetit_arg *sarg, union nfs4_attr_u *na)
1353 {
1354 	int	error = 0;
1355 
1356 	if (RFS4_MANDATTR_ONLY)
1357 		return (ENOTSUP);
1358 
1359 	switch (cmd) {
1360 	case NFS4ATTR_SUPPORTED:
1361 		if (sarg->op == NFS4ATTR_SETIT)
1362 			error = EINVAL;
1363 		break;		/* this attr is supported */
1364 	case NFS4ATTR_GETIT:
1365 	case NFS4ATTR_VERIT:
1366 		if (! sarg->mntdfid_set)
1367 			error = rfs4_get_mntdfileid(cmd, sarg);
1368 
1369 		if (! error && sarg->mntdfid_set) {
1370 			if (cmd == NFS4ATTR_GETIT)
1371 				na->mounted_on_fileid = sarg->mounted_on_fileid;
1372 			else
1373 				if (na->mounted_on_fileid !=
1374 				    sarg->mounted_on_fileid)
1375 					error = -1;
1376 		}
1377 		break;
1378 	case NFS4ATTR_SETIT:
1379 		/* read-only attr */
1380 		error = EINVAL;
1381 		break;
1382 	case NFS4ATTR_FREEIT:
1383 		break;
1384 	}
1385 	return (error);
1386 }
1387 
1388 /* ARGSUSED */
1389 static int
1390 rfs4_fattr4_files_avail(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1391 	union nfs4_attr_u *na)
1392 {
1393 	int	error = 0;
1394 
1395 	if (RFS4_MANDATTR_ONLY)
1396 		return (ENOTSUP);
1397 
1398 	switch (cmd) {
1399 	case NFS4ATTR_SUPPORTED:
1400 		if (sarg->op == NFS4ATTR_SETIT)
1401 			error = EINVAL;
1402 		break;		/* this attr is supported */
1403 	case NFS4ATTR_GETIT:
1404 		if (sarg->rdattr_error && (sarg->sbp == NULL)) {
1405 			error = -1;	/* may be okay if rdattr_error */
1406 			break;
1407 		}
1408 		ASSERT(sarg->sbp != NULL);
1409 		na->files_avail = sarg->sbp->f_favail;
1410 		break;
1411 	case NFS4ATTR_SETIT:
1412 		/*
1413 		 * read-only attr
1414 		 */
1415 		error = EINVAL;
1416 		break;
1417 	case NFS4ATTR_VERIT:
1418 		ASSERT(sarg->sbp != NULL);
1419 		if (sarg->sbp->f_favail != na->files_avail)
1420 			error = -1;	/* no match */
1421 		break;
1422 	case NFS4ATTR_FREEIT:
1423 		break;
1424 	}
1425 	return (error);
1426 }
1427 
1428 /* ARGSUSED */
1429 static int
1430 rfs4_fattr4_files_free(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1431 	union nfs4_attr_u *na)
1432 {
1433 	int	error = 0;
1434 
1435 	if (RFS4_MANDATTR_ONLY)
1436 		return (ENOTSUP);
1437 
1438 	switch (cmd) {
1439 	case NFS4ATTR_SUPPORTED:
1440 		if (sarg->op == NFS4ATTR_SETIT)
1441 			error = EINVAL;
1442 		break;		/* this attr is supported */
1443 	case NFS4ATTR_GETIT:
1444 		if (sarg->rdattr_error && (sarg->sbp == NULL)) {
1445 			error = -1;	/* may be okay if rdattr_error */
1446 			break;
1447 		}
1448 		ASSERT(sarg->sbp != NULL);
1449 		na->files_free = sarg->sbp->f_ffree;
1450 		break;
1451 	case NFS4ATTR_SETIT:
1452 		/*
1453 		 * read-only attr
1454 		 */
1455 		error = EINVAL;
1456 		break;
1457 	case NFS4ATTR_VERIT:
1458 		ASSERT(sarg->sbp != NULL);
1459 		if (sarg->sbp->f_ffree != na->files_free)
1460 			error = -1;	/* no match */
1461 		break;
1462 	case NFS4ATTR_FREEIT:
1463 		break;
1464 	}
1465 	return (error);
1466 }
1467 
1468 /* ARGSUSED */
1469 static int
1470 rfs4_fattr4_files_total(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1471 	union nfs4_attr_u *na)
1472 {
1473 	int	error = 0;
1474 
1475 	if (RFS4_MANDATTR_ONLY)
1476 		return (ENOTSUP);
1477 
1478 	switch (cmd) {
1479 	case NFS4ATTR_SUPPORTED:
1480 		if (sarg->op == NFS4ATTR_SETIT)
1481 			error = EINVAL;
1482 		break;		/* this attr is supported */
1483 	case NFS4ATTR_GETIT:
1484 		if (sarg->rdattr_error && (sarg->sbp == NULL)) {
1485 			error = -1;	/* may be okay if rdattr_error */
1486 			break;
1487 		}
1488 		ASSERT(sarg->sbp != NULL);
1489 		na->files_total = sarg->sbp->f_files;
1490 		break;
1491 	case NFS4ATTR_SETIT:
1492 		/*
1493 		 * read-only attr
1494 		 */
1495 		error = EINVAL;
1496 		break;
1497 	case NFS4ATTR_VERIT:
1498 		ASSERT(sarg->sbp != NULL);
1499 		if (sarg->sbp->f_files != na->files_total)
1500 			error = -1;	/* no match */
1501 		break;
1502 	case NFS4ATTR_FREEIT:
1503 		break;
1504 	}
1505 	return (error);
1506 }
1507 
1508 static void
1509 rfs4_free_pathname4(pathname4 *pn4)
1510 {
1511 	int i, len;
1512 	utf8string *utf8s;
1513 
1514 	if (pn4 == NULL || (len = pn4->pathname4_len) == 0 ||
1515 	    (utf8s = pn4->pathname4_val) == NULL)
1516 		return;
1517 
1518 	for (i = 0; i < len; i++, utf8s++) {
1519 		if (utf8s->utf8string_val == NULL ||
1520 		    utf8s->utf8string_len == 0)
1521 			continue;
1522 
1523 		kmem_free(utf8s->utf8string_val, utf8s->utf8string_len);
1524 		utf8s->utf8string_val = NULL;
1525 	}
1526 
1527 	kmem_free(pn4->pathname4_val,
1528 	    sizeof (utf8string) * pn4->pathname4_len);
1529 	pn4->pathname4_val = 0;
1530 }
1531 
1532 static void
1533 rfs4_free_fs_location4(fs_location4 *fsl4)
1534 {
1535 	if (fsl4 == NULL)
1536 		return;
1537 
1538 	rfs4_free_pathname4((pathname4 *)&fsl4->server_len);
1539 	rfs4_free_pathname4(&fsl4->rootpath);
1540 }
1541 
1542 void
1543 rfs4_free_fs_locations4(fs_locations4 *fsls4)
1544 {
1545 	int i, len;
1546 	fs_location4 *fsl4;
1547 
1548 	if (fsls4 == NULL)
1549 		return;
1550 
1551 	/* free fs_root */
1552 	rfs4_free_pathname4(&fsls4->fs_root);
1553 
1554 	if ((len = fsls4->locations_len) == 0 ||
1555 	    (fsl4 = fsls4->locations_val) == NULL)
1556 		return;
1557 
1558 	/* free fs_location4 */
1559 	for (i = 0; i < len; i++) {
1560 		rfs4_free_fs_location4(fsl4);
1561 		fsl4++;
1562 	}
1563 
1564 	kmem_free(fsls4->locations_val, sizeof (fs_location4) * len);
1565 	fsls4->locations_val = NULL;
1566 }
1567 
1568 /* ARGSUSED */
1569 static int
1570 rfs4_fattr4_fs_locations(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1571 	union nfs4_attr_u *na)
1572 {
1573 	int error = 0;
1574 	fs_locations4 *fsl;
1575 
1576 	if (RFS4_MANDATTR_ONLY)
1577 		return (ENOTSUP);
1578 
1579 	switch (cmd) {
1580 	case NFS4ATTR_SUPPORTED:
1581 		if (sarg->op == NFS4ATTR_SETIT || sarg->op == NFS4ATTR_VERIT)
1582 			error = EINVAL;
1583 		break;  /* this attr is supported */
1584 
1585 	case NFS4ATTR_GETIT:
1586 		fsl = fetch_referral(sarg->cs->vp, sarg->cs->cr);
1587 		if (fsl == NULL)
1588 			error = EINVAL;
1589 		else {
1590 			na->fs_locations = *fsl;
1591 			kmem_free(fsl, sizeof (fs_locations4));
1592 		}
1593 		global_svstat_ptr[4][NFS_REFERRALS].value.ui64++;
1594 		break;
1595 
1596 	case NFS4ATTR_FREEIT:
1597 		if (sarg->op == NFS4ATTR_SETIT || sarg->op == NFS4ATTR_VERIT)
1598 			error = EINVAL;
1599 		rfs4_free_fs_locations4(&na->fs_locations);
1600 		break;
1601 
1602 	case NFS4ATTR_SETIT:
1603 	case NFS4ATTR_VERIT:
1604 		/*
1605 		 * read-only attr
1606 		 */
1607 		error = EINVAL;
1608 		break;
1609 	}
1610 	return (error);
1611 }
1612 
1613 /* ARGSUSED */
1614 static int
1615 rfs4_fattr4_hidden(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1616 	union nfs4_attr_u *na)
1617 {
1618 	return (ENOTSUP);
1619 }
1620 
1621 /* ARGSUSED */
1622 static int
1623 rfs4_fattr4_homogeneous(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1624 	union nfs4_attr_u *na)
1625 {
1626 	int error = 0;
1627 
1628 	if (RFS4_MANDATTR_ONLY)
1629 		return (ENOTSUP);
1630 
1631 	switch (cmd) {
1632 	case NFS4ATTR_SUPPORTED:
1633 		if (sarg->op == NFS4ATTR_SETIT)
1634 			error = EINVAL;
1635 		break;		/* this attr is supported */
1636 	case NFS4ATTR_GETIT:
1637 		na->homogeneous = TRUE; /* XXX - need a VOP extension */
1638 		break;
1639 	case NFS4ATTR_SETIT:
1640 		/*
1641 		 * read-only attr
1642 		 */
1643 		error = EINVAL;
1644 		break;
1645 	case NFS4ATTR_VERIT:
1646 		if (!na->homogeneous)
1647 			error = -1;	/* no match */
1648 		break;
1649 	case NFS4ATTR_FREEIT:
1650 		break;
1651 	}
1652 	return (error);
1653 }
1654 
1655 /* ARGSUSED */
1656 static int
1657 rfs4_fattr4_maxfilesize(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1658 	union nfs4_attr_u *na)
1659 {
1660 	int error = 0;
1661 	ulong_t val;
1662 	fattr4_maxfilesize maxfilesize;
1663 
1664 	if (RFS4_MANDATTR_ONLY)
1665 		return (ENOTSUP);
1666 
1667 	switch (cmd) {
1668 	case NFS4ATTR_SUPPORTED:
1669 		if (sarg->op == NFS4ATTR_SETIT)
1670 			error = EINVAL;
1671 		break;		/* this attr is supported */
1672 	case NFS4ATTR_GETIT:
1673 		if (sarg->rdattr_error && (sarg->cs->vp == NULL)) {
1674 			error = -1;	/* may be okay if rdattr_error */
1675 			break;
1676 		}
1677 		ASSERT(sarg->cs->vp != NULL);
1678 		error = VOP_PATHCONF(sarg->cs->vp, _PC_FILESIZEBITS, &val,
1679 		    sarg->cs->cr, NULL);
1680 		if (error)
1681 			break;
1682 
1683 		/*
1684 		 * If the underlying file system does not support
1685 		 * _PC_FILESIZEBITS, return a reasonable default. Note that
1686 		 * error code on VOP_PATHCONF will be 0, even if the underlying
1687 		 * file system does not support _PC_FILESIZEBITS.
1688 		 */
1689 		if (val == (ulong_t)-1) {
1690 			na->maxfilesize = MAXOFF32_T;
1691 		} else {
1692 			if (val >= (sizeof (uint64_t) * 8))
1693 				na->maxfilesize = INT64_MAX;
1694 			else
1695 				na->maxfilesize = ((1LL << (val - 1)) - 1);
1696 		}
1697 		break;
1698 	case NFS4ATTR_SETIT:
1699 		/*
1700 		 * read-only attr
1701 		 */
1702 		error = EINVAL;
1703 		break;
1704 	case NFS4ATTR_VERIT:
1705 		ASSERT(sarg->cs->vp != NULL);
1706 		error = VOP_PATHCONF(sarg->cs->vp, _PC_FILESIZEBITS, &val,
1707 		    sarg->cs->cr, NULL);
1708 		if (error)
1709 			break;
1710 		/*
1711 		 * If the underlying file system does not support
1712 		 * _PC_FILESIZEBITS, return a reasonable default. Note that
1713 		 * error code on VOP_PATHCONF will be 0, even if the underlying
1714 		 * file system does not support _PC_FILESIZEBITS.
1715 		 */
1716 		if (val == (ulong_t)-1) {
1717 			maxfilesize = MAXOFF32_T;
1718 		} else {
1719 			if (val >= (sizeof (uint64_t) * 8))
1720 				maxfilesize = INT64_MAX;
1721 			else
1722 				maxfilesize = ((1LL << (val - 1)) - 1);
1723 		}
1724 		if (na->maxfilesize != maxfilesize)
1725 			error = -1;	/* no match */
1726 		break;
1727 	case NFS4ATTR_FREEIT:
1728 		break;
1729 	}
1730 	return (error);
1731 }
1732 
1733 /* ARGSUSED */
1734 static int
1735 rfs4_fattr4_maxlink(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1736 	union nfs4_attr_u *na)
1737 {
1738 	int error = 0;
1739 	ulong_t val;
1740 
1741 	if (RFS4_MANDATTR_ONLY)
1742 		return (ENOTSUP);
1743 
1744 	switch (cmd) {
1745 	case NFS4ATTR_SUPPORTED:
1746 		if (sarg->op == NFS4ATTR_SETIT)
1747 			error = EINVAL;
1748 		break;		/* this attr is supported */
1749 	case NFS4ATTR_GETIT:
1750 		if (sarg->rdattr_error && (sarg->cs->vp == NULL)) {
1751 			error = -1;	/* may be okay if rdattr_error */
1752 			break;
1753 		}
1754 		ASSERT(sarg->cs->vp != NULL);
1755 		error = VOP_PATHCONF(sarg->cs->vp, _PC_LINK_MAX, &val,
1756 		    sarg->cs->cr, NULL);
1757 		if (error == 0) {
1758 			na->maxlink = val;
1759 		}
1760 		break;
1761 	case NFS4ATTR_SETIT:
1762 		/*
1763 		 * read-only attr
1764 		 */
1765 		error = EINVAL;
1766 		break;
1767 	case NFS4ATTR_VERIT:
1768 		ASSERT(sarg->cs->vp != NULL);
1769 		error = VOP_PATHCONF(sarg->cs->vp, _PC_LINK_MAX, &val,
1770 		    sarg->cs->cr, NULL);
1771 		if (!error && (na->maxlink != (uint32_t)val))
1772 			error = -1;	/* no match */
1773 		break;
1774 	case NFS4ATTR_FREEIT:
1775 		break;
1776 	}
1777 	return (error);
1778 }
1779 
1780 /* ARGSUSED */
1781 static int
1782 rfs4_fattr4_maxname(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1783 	union nfs4_attr_u *na)
1784 {
1785 	int error = 0;
1786 	ulong_t val;
1787 
1788 	if (RFS4_MANDATTR_ONLY)
1789 		return (ENOTSUP);
1790 
1791 	switch (cmd) {
1792 	case NFS4ATTR_SUPPORTED:
1793 		if (sarg->op == NFS4ATTR_SETIT)
1794 			error = EINVAL;
1795 		break;		/* this attr is supported */
1796 	case NFS4ATTR_GETIT:
1797 		if (sarg->rdattr_error && (sarg->cs->vp == NULL)) {
1798 			error = -1;	/* may be okay if rdattr_error */
1799 			break;
1800 		}
1801 		ASSERT(sarg->cs->vp != NULL);
1802 		error = VOP_PATHCONF(sarg->cs->vp, _PC_NAME_MAX, &val,
1803 		    sarg->cs->cr, NULL);
1804 		if (error == 0) {
1805 			na->maxname = val;
1806 		}
1807 		break;
1808 	case NFS4ATTR_SETIT:
1809 		/*
1810 		 * read-only attr
1811 		 */
1812 		error = EINVAL;
1813 		break;
1814 	case NFS4ATTR_VERIT:
1815 		ASSERT(sarg->cs->vp != NULL);
1816 		error = VOP_PATHCONF(sarg->cs->vp, _PC_NAME_MAX, &val,
1817 		    sarg->cs->cr, NULL);
1818 		if (!error && (na->maxname != val))
1819 			error = -1;	/* no match */
1820 		break;
1821 	case NFS4ATTR_FREEIT:
1822 		break;
1823 	}
1824 	return (error);
1825 }
1826 
1827 /* ARGSUSED */
1828 static int
1829 rfs4_fattr4_maxread(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1830 	union nfs4_attr_u *na)
1831 {
1832 	int error = 0;
1833 
1834 	if (RFS4_MANDATTR_ONLY)
1835 		return (ENOTSUP);
1836 
1837 	switch (cmd) {
1838 	case NFS4ATTR_SUPPORTED:
1839 		if (sarg->op == NFS4ATTR_SETIT)
1840 			error = EINVAL;
1841 		break;		/* this attr is supported */
1842 	case NFS4ATTR_GETIT:
1843 		na->maxread = rfs4_tsize(sarg->cs->req);
1844 		break;
1845 	case NFS4ATTR_SETIT:
1846 		/*
1847 		 * read-only attr
1848 		 */
1849 		error = EINVAL;
1850 		break;
1851 	case NFS4ATTR_VERIT:
1852 		if (na->maxread != rfs4_tsize(sarg->cs->req))
1853 			error = -1;	/* no match */
1854 		break;
1855 	case NFS4ATTR_FREEIT:
1856 		break;
1857 	}
1858 	return (error);
1859 }
1860 
1861 /* ARGSUSED */
1862 static int
1863 rfs4_fattr4_maxwrite(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1864 	union nfs4_attr_u *na)
1865 {
1866 	int error = 0;
1867 
1868 	if (RFS4_MANDATTR_ONLY)
1869 		return (ENOTSUP);
1870 
1871 	switch (cmd) {
1872 	case NFS4ATTR_SUPPORTED:
1873 		if (sarg->op == NFS4ATTR_SETIT)
1874 			error = EINVAL;
1875 		break;		/* this attr is supported */
1876 	case NFS4ATTR_GETIT:
1877 		na->maxwrite = rfs4_tsize(sarg->cs->req);
1878 		break;
1879 	case NFS4ATTR_SETIT:
1880 		/*
1881 		 * read-only attr
1882 		 */
1883 		error = EINVAL;
1884 		break;
1885 	case NFS4ATTR_VERIT:
1886 		if (na->maxwrite != rfs4_tsize(sarg->cs->req))
1887 			error = -1;	/* no match */
1888 		break;
1889 	case NFS4ATTR_FREEIT:
1890 		break;
1891 	}
1892 	return (error);
1893 }
1894 
1895 /* ARGSUSED */
1896 static int
1897 rfs4_fattr4_mimetype(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1898 	union nfs4_attr_u *na)
1899 {
1900 	return (ENOTSUP);
1901 }
1902 
1903 /* ARGSUSED */
1904 static int
1905 rfs4_fattr4_mode(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1906 	union nfs4_attr_u *na)
1907 {
1908 	int	error = 0;
1909 
1910 	if (RFS4_MANDATTR_ONLY)
1911 		return (ENOTSUP);
1912 
1913 	switch (cmd) {
1914 	case NFS4ATTR_SUPPORTED:
1915 		break;		/* this attr is supported */
1916 	case NFS4ATTR_GETIT:
1917 		if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_MODE)) {
1918 			error = -1;	/* may be okay if rdattr_error */
1919 			break;
1920 		}
1921 		ASSERT(sarg->vap->va_mask & AT_MODE);
1922 		na->mode = sarg->vap->va_mode;
1923 		break;
1924 	case NFS4ATTR_SETIT:
1925 		ASSERT(sarg->vap->va_mask & AT_MODE);
1926 		sarg->vap->va_mode = na->mode;
1927 		/*
1928 		 * If the filesystem is exported with nosuid, then mask off
1929 		 * the setuid and setgid bits.
1930 		 */
1931 		if (sarg->cs->vp->v_type == VREG &&
1932 		    (sarg->cs->exi->exi_export.ex_flags & EX_NOSUID))
1933 			sarg->vap->va_mode &= ~(VSUID | VSGID);
1934 		break;
1935 	case NFS4ATTR_VERIT:
1936 		ASSERT(sarg->vap->va_mask & AT_MODE);
1937 		if (sarg->vap->va_mode != na->mode)
1938 			error = -1;	/* no match */
1939 		break;
1940 	case NFS4ATTR_FREEIT:
1941 		break;
1942 	}
1943 	return (error);
1944 }
1945 
1946 /* ARGSUSED */
1947 static int
1948 rfs4_fattr4_no_trunc(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1949 	union nfs4_attr_u *na)
1950 {
1951 	int error = 0;
1952 
1953 	if (RFS4_MANDATTR_ONLY)
1954 		return (ENOTSUP);
1955 
1956 	switch (cmd) {
1957 	case NFS4ATTR_SUPPORTED:
1958 		if (sarg->op == NFS4ATTR_SETIT)
1959 			error = EINVAL;
1960 		break;		/* this attr is supported */
1961 	case NFS4ATTR_GETIT:
1962 		na->no_trunc = TRUE;
1963 		break;
1964 	case NFS4ATTR_SETIT:
1965 		/*
1966 		 * read-only attr
1967 		 */
1968 		error = EINVAL;
1969 		break;
1970 	case NFS4ATTR_VERIT:
1971 		if (!na->no_trunc)
1972 			error = -1;	/* no match */
1973 		break;
1974 	case NFS4ATTR_FREEIT:
1975 		break;
1976 	}
1977 	return (error);
1978 }
1979 
1980 /* ARGSUSED */
1981 static int
1982 rfs4_fattr4_numlinks(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
1983 	union nfs4_attr_u *na)
1984 {
1985 	int	error = 0;
1986 
1987 	if (RFS4_MANDATTR_ONLY)
1988 		return (ENOTSUP);
1989 
1990 	switch (cmd) {
1991 	case NFS4ATTR_SUPPORTED:
1992 		if (sarg->op == NFS4ATTR_SETIT)
1993 			error = EINVAL;
1994 		break;		/* this attr is supported */
1995 	case NFS4ATTR_GETIT:
1996 		if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_NLINK)) {
1997 			error = -1;	/* may be okay if rdattr_error */
1998 			break;
1999 		}
2000 		ASSERT(sarg->vap->va_mask & AT_NLINK);
2001 		na->numlinks = sarg->vap->va_nlink;
2002 		break;
2003 	case NFS4ATTR_SETIT:
2004 		/*
2005 		 * read-only attr
2006 		 */
2007 		error = EINVAL;
2008 		break;
2009 	case NFS4ATTR_VERIT:
2010 		ASSERT(sarg->vap->va_mask & AT_NLINK);
2011 		if (sarg->vap->va_nlink != na->numlinks)
2012 			error = -1;	/* no match */
2013 		break;
2014 	case NFS4ATTR_FREEIT:
2015 		break;
2016 	}
2017 	return (error);
2018 }
2019 
2020 /* ARGSUSED */
2021 static int
2022 rfs4_fattr4_owner(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2023 	union nfs4_attr_u *na)
2024 {
2025 	int	error = 0;
2026 	uid_t	uid;
2027 
2028 	if (RFS4_MANDATTR_ONLY)
2029 		return (ENOTSUP);
2030 
2031 	switch (cmd) {
2032 	case NFS4ATTR_SUPPORTED:
2033 		break;		/* this attr is supported */
2034 	case NFS4ATTR_GETIT:
2035 		if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_UID)) {
2036 			error = -1;	/* may be okay if rdattr_error */
2037 			break;
2038 		}
2039 		ASSERT(sarg->vap->va_mask & AT_UID);
2040 
2041 		/*
2042 		 * There are well defined polices for what happens on server-
2043 		 * side GETATTR when uid to attribute string conversion cannot
2044 		 * occur. Please refer to nfs4_idmap.c for details.
2045 		 */
2046 		error = nfs_idmap_uid_str(sarg->vap->va_uid, &na->owner, TRUE);
2047 		switch (error) {
2048 		case ECONNREFUSED:
2049 			error = NFS4ERR_DELAY;
2050 			break;
2051 		default:
2052 			break;
2053 		}
2054 		break;
2055 
2056 	case NFS4ATTR_SETIT:
2057 		ASSERT(sarg->vap->va_mask & AT_UID);
2058 
2059 		/*
2060 		 * There are well defined policies for what happens on server-
2061 		 * side SETATTR of 'owner' when a "user@domain" mapping cannot
2062 		 * occur. Please refer to nfs4_idmap.c for details.
2063 		 *
2064 		 * Any other errors, such as the mapping not being found by
2065 		 * nfsmapid(1m), and interrupted clnt_call, etc, will result
2066 		 * in NFS4ERR_BADOWNER.
2067 		 *
2068 		 * XXX need to return consistent errors, perhaps all
2069 		 * server side attribute routines should return NFS4ERR*.
2070 		 */
2071 		error = nfs_idmap_str_uid(&na->owner, &sarg->vap->va_uid, TRUE);
2072 		switch (error) {
2073 		case NFS4_OK:
2074 		case ENOTSUP:
2075 			/*
2076 			 * Ignore warning that we are the
2077 			 * nfsmapid (can't happen on srv)
2078 			 */
2079 			error = 0;
2080 			MSG_PRT_DEBUG = FALSE;
2081 			break;
2082 
2083 		case ECOMM:
2084 		case ECONNREFUSED:
2085 			if (!MSG_PRT_DEBUG) {
2086 				/*
2087 				 * printed just once per daemon death,
2088 				 * inform the user and then stay silent
2089 				 */
2090 				cmn_err(CE_WARN, "!Unable to contact "
2091 				    "nfsmapid");
2092 				MSG_PRT_DEBUG = TRUE;
2093 			}
2094 			error = NFS4ERR_DELAY;
2095 			break;
2096 
2097 		case EINVAL:
2098 			error = NFS4ERR_INVAL;
2099 			break;
2100 
2101 		default:
2102 			error = NFS4ERR_BADOWNER;
2103 			break;
2104 		}
2105 		break;
2106 
2107 	case NFS4ATTR_VERIT:
2108 		ASSERT(sarg->vap->va_mask & AT_UID);
2109 		error = nfs_idmap_str_uid(&na->owner, &uid, TRUE);
2110 		/*
2111 		 * Ignore warning that we are the nfsmapid (can't happen on srv)
2112 		 */
2113 		if (error == ENOTSUP)
2114 			error = 0;
2115 		if (error)
2116 			error = -1;	/* no match */
2117 		else if (sarg->vap->va_uid != uid)
2118 			error = -1;	/* no match */
2119 		break;
2120 	case NFS4ATTR_FREEIT:
2121 		if (sarg->op == NFS4ATTR_GETIT) {
2122 			if (na->owner.utf8string_val) {
2123 				UTF8STRING_FREE(na->owner)
2124 				bzero(&na->owner, sizeof (na->owner));
2125 			}
2126 		}
2127 		break;
2128 	}
2129 	return (error);
2130 }
2131 
2132 /* ARGSUSED */
2133 static int
2134 rfs4_fattr4_owner_group(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2135 	union nfs4_attr_u *na)
2136 {
2137 	int	error = 0;
2138 	gid_t	gid;
2139 
2140 	if (RFS4_MANDATTR_ONLY)
2141 		return (ENOTSUP);
2142 
2143 	switch (cmd) {
2144 	case NFS4ATTR_SUPPORTED:
2145 		break;		/* this attr is supported */
2146 	case NFS4ATTR_GETIT:
2147 		if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_GID)) {
2148 			error = -1;	/* may be okay if rdattr_error */
2149 			break;
2150 		}
2151 		ASSERT(sarg->vap->va_mask & AT_GID);
2152 
2153 		/*
2154 		 * There are well defined polices for what happens on server-
2155 		 * side GETATTR when gid to attribute string conversion cannot
2156 		 * occur. Please refer to nfs4_idmap.c for details.
2157 		 */
2158 		error = nfs_idmap_gid_str(sarg->vap->va_gid, &na->owner_group,
2159 		    TRUE);
2160 		switch (error) {
2161 		case ECONNREFUSED:
2162 			error = NFS4ERR_DELAY;
2163 			break;
2164 		default:
2165 			break;
2166 		}
2167 		break;
2168 
2169 	case NFS4ATTR_SETIT:
2170 		ASSERT(sarg->vap->va_mask & AT_GID);
2171 
2172 		/*
2173 		 * There are well defined policies for what happens on server-
2174 		 * side SETATTR of 'owner_group' when a "group@domain" mapping
2175 		 * cannot occur. Please refer to nfs4_idmap.c for details.
2176 		 *
2177 		 * Any other errors, such as the mapping not being found by
2178 		 * nfsmapid(1m), and interrupted clnt_call, etc, will result
2179 		 * in NFS4ERR_BADOWNER.
2180 		 *
2181 		 * XXX need to return consistent errors, perhaps all
2182 		 * server side attribute routines should return NFS4ERR*.
2183 		 */
2184 		error = nfs_idmap_str_gid(&na->owner_group, &sarg->vap->va_gid,
2185 		    TRUE);
2186 		switch (error) {
2187 		case NFS4_OK:
2188 		case ENOTSUP:
2189 			/*
2190 			 * Ignore warning that we are the
2191 			 * nfsmapid (can't happen on srv)
2192 			 */
2193 			error = 0;
2194 			MSG_PRT_DEBUG = FALSE;
2195 			break;
2196 
2197 		case ECOMM:
2198 		case ECONNREFUSED:
2199 			if (!MSG_PRT_DEBUG) {
2200 				/*
2201 				 * printed just once per daemon death,
2202 				 * inform the user and then stay silent
2203 				 */
2204 				cmn_err(CE_WARN, "!Unable to contact "
2205 				    "nfsmapid");
2206 				MSG_PRT_DEBUG = TRUE;
2207 			}
2208 			error = NFS4ERR_DELAY;
2209 			break;
2210 
2211 		case EINVAL:
2212 			error = NFS4ERR_INVAL;
2213 			break;
2214 
2215 		default:
2216 			error = NFS4ERR_BADOWNER;
2217 			break;
2218 		}
2219 		break;
2220 
2221 	case NFS4ATTR_VERIT:
2222 		ASSERT(sarg->vap->va_mask & AT_GID);
2223 		error = nfs_idmap_str_gid(&na->owner_group, &gid, TRUE);
2224 		/*
2225 		 * Ignore warning that we are the nfsmapid (can't happen on srv)
2226 		 */
2227 		if (error == ENOTSUP)
2228 			error = 0;
2229 		if (error)
2230 			error = -1;	/* no match */
2231 		else if (sarg->vap->va_gid != gid)
2232 			error = -1;	/* no match */
2233 		break;
2234 	case NFS4ATTR_FREEIT:
2235 		if (sarg->op == NFS4ATTR_GETIT) {
2236 			if (na->owner_group.utf8string_val) {
2237 				UTF8STRING_FREE(na->owner_group)
2238 				bzero(&na->owner_group,
2239 				    sizeof (na->owner_group));
2240 			}
2241 		}
2242 		break;
2243 	}
2244 	return (error);
2245 }
2246 
2247 /* XXX - quota attributes should be supportable on Solaris 2 */
2248 /* ARGSUSED */
2249 static int
2250 rfs4_fattr4_quota_avail_hard(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2251 	union nfs4_attr_u *na)
2252 {
2253 	return (ENOTSUP);
2254 }
2255 
2256 /* ARGSUSED */
2257 static int
2258 rfs4_fattr4_quota_avail_soft(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2259 	union nfs4_attr_u *na)
2260 {
2261 	return (ENOTSUP);
2262 }
2263 
2264 /* ARGSUSED */
2265 static int
2266 rfs4_fattr4_quota_used(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2267 	union nfs4_attr_u *na)
2268 {
2269 	return (ENOTSUP);
2270 }
2271 
2272 /* ARGSUSED */
2273 static int
2274 rfs4_fattr4_rawdev(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2275 	union nfs4_attr_u *na)
2276 {
2277 	int	error = 0;
2278 
2279 	if (RFS4_MANDATTR_ONLY)
2280 		return (ENOTSUP);
2281 
2282 	switch (cmd) {
2283 	case NFS4ATTR_SUPPORTED:
2284 		if (sarg->op == NFS4ATTR_SETIT)
2285 			error = EINVAL;
2286 		break;		/* this attr is supported */
2287 	case NFS4ATTR_GETIT:
2288 		if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_RDEV)) {
2289 			error = -1;	/* may be okay if rdattr_error */
2290 			break;
2291 		}
2292 		ASSERT(sarg->vap->va_mask & AT_RDEV);
2293 		na->rawdev.specdata1 =  (uint32)getmajor(sarg->vap->va_rdev);
2294 		na->rawdev.specdata2 =  (uint32)getminor(sarg->vap->va_rdev);
2295 		break;
2296 	case NFS4ATTR_SETIT:
2297 		/*
2298 		 * read-only attr
2299 		 */
2300 		error = EINVAL;
2301 		break;
2302 	case NFS4ATTR_VERIT:
2303 		ASSERT(sarg->vap->va_mask & AT_RDEV);
2304 		if ((na->rawdev.specdata1 !=
2305 		    (uint32)getmajor(sarg->vap->va_rdev)) ||
2306 		    (na->rawdev.specdata2 !=
2307 		    (uint32)getminor(sarg->vap->va_rdev)))
2308 			error = -1;	/* no match */
2309 		break;
2310 	case NFS4ATTR_FREEIT:
2311 		break;
2312 	}
2313 	return (error);
2314 }
2315 
2316 /* ARGSUSED */
2317 static int
2318 rfs4_fattr4_space_avail(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2319 	union nfs4_attr_u *na)
2320 {
2321 	int	error = 0;
2322 
2323 	if (RFS4_MANDATTR_ONLY)
2324 		return (ENOTSUP);
2325 
2326 	switch (cmd) {
2327 	case NFS4ATTR_SUPPORTED:
2328 		if (sarg->op == NFS4ATTR_SETIT)
2329 			error = EINVAL;
2330 		break;		/* this attr is supported */
2331 	case NFS4ATTR_GETIT:
2332 		if (sarg->rdattr_error && (sarg->sbp == NULL)) {
2333 			error = -1;	/* may be okay if rdattr_error */
2334 			break;
2335 		}
2336 		ASSERT(sarg->sbp != NULL);
2337 		if (sarg->sbp->f_bavail != (fsblkcnt64_t)-1) {
2338 			na->space_avail =
2339 			    (fattr4_space_avail) sarg->sbp->f_frsize *
2340 			    (fattr4_space_avail) sarg->sbp->f_bavail;
2341 		} else {
2342 			na->space_avail =
2343 			    (fattr4_space_avail) sarg->sbp->f_bavail;
2344 		}
2345 		break;
2346 	case NFS4ATTR_SETIT:
2347 		/*
2348 		 * read-only attr
2349 		 */
2350 		error = EINVAL;
2351 		break;
2352 	case NFS4ATTR_VERIT:
2353 		ASSERT(sarg->sbp != NULL);
2354 		if (sarg->sbp->f_bavail != na->space_avail)
2355 			error = -1;	/* no match */
2356 		break;
2357 	case NFS4ATTR_FREEIT:
2358 		break;
2359 	}
2360 	return (error);
2361 }
2362 
2363 /* ARGSUSED */
2364 static int
2365 rfs4_fattr4_space_free(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2366 	union nfs4_attr_u *na)
2367 {
2368 	int	error = 0;
2369 
2370 	if (RFS4_MANDATTR_ONLY)
2371 		return (ENOTSUP);
2372 
2373 	switch (cmd) {
2374 	case NFS4ATTR_SUPPORTED:
2375 		if (sarg->op == NFS4ATTR_SETIT)
2376 			error = EINVAL;
2377 		break;		/* this attr is supported */
2378 	case NFS4ATTR_GETIT:
2379 		if (sarg->rdattr_error && (sarg->sbp == NULL)) {
2380 			error = -1;	/* may be okay if rdattr_error */
2381 			break;
2382 		}
2383 		ASSERT(sarg->sbp != NULL);
2384 		if (sarg->sbp->f_bfree != (fsblkcnt64_t)-1) {
2385 			na->space_free =
2386 			    (fattr4_space_free) sarg->sbp->f_frsize *
2387 			    (fattr4_space_free) sarg->sbp->f_bfree;
2388 		} else {
2389 			na->space_free =
2390 			    (fattr4_space_free) sarg->sbp->f_bfree;
2391 		}
2392 		break;
2393 	case NFS4ATTR_SETIT:
2394 		/*
2395 		 * read-only attr
2396 		 */
2397 		error = EINVAL;
2398 		break;
2399 	case NFS4ATTR_VERIT:
2400 		ASSERT(sarg->sbp != NULL);
2401 		if (sarg->sbp->f_bfree != na->space_free)
2402 			error = -1;	/* no match */
2403 		break;
2404 	case NFS4ATTR_FREEIT:
2405 		break;
2406 	}
2407 	return (error);
2408 }
2409 
2410 /* ARGSUSED */
2411 static int
2412 rfs4_fattr4_space_total(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2413 	union nfs4_attr_u *na)
2414 {
2415 	int	error = 0;
2416 
2417 	if (RFS4_MANDATTR_ONLY)
2418 		return (ENOTSUP);
2419 
2420 	switch (cmd) {
2421 	case NFS4ATTR_SUPPORTED:
2422 		if (sarg->op == NFS4ATTR_SETIT)
2423 			error = EINVAL;
2424 		break;		/* this attr is supported */
2425 	case NFS4ATTR_GETIT:
2426 		if (sarg->rdattr_error_req && (sarg->sbp == NULL)) {
2427 			error = -1;	/* may be okay if rdattr_error */
2428 			break;
2429 		}
2430 		ASSERT(sarg->sbp != NULL);
2431 		if (sarg->sbp->f_blocks != (fsblkcnt64_t)-1) {
2432 			na->space_total =
2433 			    (fattr4_space_total) sarg->sbp->f_frsize *
2434 			    (fattr4_space_total) sarg->sbp->f_blocks;
2435 		} else {
2436 			na->space_total =
2437 			    (fattr4_space_total) sarg->sbp->f_blocks;
2438 		}
2439 		break;
2440 	case NFS4ATTR_SETIT:
2441 		/*
2442 		 * read-only attr
2443 		 */
2444 		error = EINVAL;
2445 		break;
2446 	case NFS4ATTR_VERIT:
2447 		ASSERT(sarg->sbp != NULL);
2448 		if (sarg->sbp->f_blocks != na->space_total)
2449 			error = -1;	/* no match */
2450 		break;
2451 	case NFS4ATTR_FREEIT:
2452 		break;
2453 	}
2454 	return (error);
2455 }
2456 
2457 /* ARGSUSED */
2458 static int
2459 rfs4_fattr4_space_used(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2460 	union nfs4_attr_u *na)
2461 {
2462 	int	error = 0;
2463 
2464 	if (RFS4_MANDATTR_ONLY)
2465 		return (ENOTSUP);
2466 
2467 	switch (cmd) {
2468 	case NFS4ATTR_SUPPORTED:
2469 		if (sarg->op == NFS4ATTR_SETIT)
2470 			error = EINVAL;
2471 		break;		/* this attr is supported */
2472 	case NFS4ATTR_GETIT:
2473 		if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_NBLOCKS)) {
2474 			error = -1;	/* may be okay if rdattr_error */
2475 			break;
2476 		}
2477 		ASSERT(sarg->vap->va_mask & AT_NBLOCKS);
2478 		na->space_used =  (fattr4_space_used) DEV_BSIZE *
2479 		    (fattr4_space_used) sarg->vap->va_nblocks;
2480 		break;
2481 	case NFS4ATTR_SETIT:
2482 		/*
2483 		 * read-only attr
2484 		 */
2485 		error = EINVAL;
2486 		break;
2487 	case NFS4ATTR_VERIT:
2488 		ASSERT(sarg->vap->va_mask & AT_NBLOCKS);
2489 		if (sarg->vap->va_nblocks != na->space_used)
2490 			error = -1;	/* no match */
2491 		break;
2492 	case NFS4ATTR_FREEIT:
2493 		break;
2494 	}
2495 	return (error);
2496 }
2497 
2498 /* ARGSUSED */
2499 static int
2500 rfs4_fattr4_system(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2501 	union nfs4_attr_u *na)
2502 {
2503 	return (ENOTSUP);
2504 }
2505 
2506 /* ARGSUSED */
2507 static int
2508 rfs4_fattr4_time_access(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2509 	union nfs4_attr_u *na)
2510 {
2511 	int	error = 0;
2512 	timestruc_t atime;
2513 
2514 	if (RFS4_MANDATTR_ONLY)
2515 		return (ENOTSUP);
2516 
2517 	switch (cmd) {
2518 	case NFS4ATTR_SUPPORTED:
2519 		if (sarg->op == NFS4ATTR_SETIT)
2520 			error = EINVAL;
2521 		break;		/* this attr is supported */
2522 	case NFS4ATTR_GETIT:
2523 		if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_ATIME)) {
2524 			error = -1;	/* may be okay if rdattr_error */
2525 			break;
2526 		}
2527 		ASSERT(sarg->vap->va_mask & AT_ATIME);
2528 		error = nfs4_time_vton(&sarg->vap->va_atime, &na->time_access);
2529 		break;
2530 	case NFS4ATTR_SETIT:
2531 		/*
2532 		 * read-only attr
2533 		 */
2534 		error = EINVAL;
2535 		break;
2536 	case NFS4ATTR_VERIT:
2537 		ASSERT(sarg->vap->va_mask & AT_ATIME);
2538 		error = nfs4_time_ntov(&na->time_access, &atime);
2539 		if (error)
2540 			break;
2541 		if (bcmp(&atime, &sarg->vap->va_atime, sizeof (atime)))
2542 			error = -1;	/* no match */
2543 		break;
2544 	case NFS4ATTR_FREEIT:
2545 		break;
2546 	}
2547 	return (error);
2548 }
2549 
2550 /*
2551  * XXX - need to support the setting of access time
2552  */
2553 /* ARGSUSED */
2554 static int
2555 rfs4_fattr4_time_access_set(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2556 	union nfs4_attr_u *na)
2557 {
2558 	int	error = 0;
2559 	settime4 *ta;
2560 
2561 	if (RFS4_MANDATTR_ONLY)
2562 		return (ENOTSUP);
2563 
2564 	switch (cmd) {
2565 	case NFS4ATTR_SUPPORTED:
2566 		if ((sarg->op == NFS4ATTR_GETIT) ||
2567 		    (sarg->op == NFS4ATTR_VERIT))
2568 			error = EINVAL;
2569 		break;		/* this attr is supported */
2570 	case NFS4ATTR_GETIT:
2571 	case NFS4ATTR_VERIT:
2572 		/*
2573 		 * write only attr
2574 		 */
2575 		error = EINVAL;
2576 		break;
2577 	case NFS4ATTR_SETIT:
2578 		ASSERT(sarg->vap->va_mask & AT_ATIME);
2579 		/*
2580 		 * Set access time (by server or by client)
2581 		 */
2582 		ta = &na->time_access_set;
2583 		if (ta->set_it == SET_TO_CLIENT_TIME4) {
2584 			error = nfs4_time_ntov(&ta->time, &sarg->vap->va_atime);
2585 		} else if (ta->set_it == SET_TO_SERVER_TIME4) {
2586 			gethrestime(&sarg->vap->va_atime);
2587 		} else {
2588 			error = EINVAL;
2589 		}
2590 		break;
2591 	case NFS4ATTR_FREEIT:
2592 		break;
2593 	}
2594 	return (error);
2595 }
2596 
2597 /* ARGSUSED */
2598 static int
2599 rfs4_fattr4_time_backup(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2600 	union nfs4_attr_u *na)
2601 {
2602 	return (ENOTSUP);
2603 }
2604 
2605 /* ARGSUSED */
2606 static int
2607 rfs4_fattr4_time_create(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2608 	union nfs4_attr_u *na)
2609 {
2610 	return (ENOTSUP);
2611 }
2612 
2613 /* ARGSUSED */
2614 static int
2615 rfs4_fattr4_time_delta(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2616 	union nfs4_attr_u *na)
2617 {
2618 	int error = 0;
2619 
2620 	if (RFS4_MANDATTR_ONLY)
2621 		return (ENOTSUP);
2622 
2623 	switch (cmd) {
2624 	case NFS4ATTR_SUPPORTED:
2625 		if (sarg->op == NFS4ATTR_SETIT)
2626 			error = EINVAL;
2627 		break;		/* this attr is supported */
2628 	case NFS4ATTR_GETIT:
2629 		na->time_delta.seconds = 0;
2630 		na->time_delta.nseconds = 1000;
2631 		break;
2632 	case NFS4ATTR_SETIT:
2633 		/*
2634 		 * write only attr
2635 		 */
2636 		error = EINVAL;
2637 		break;
2638 	case NFS4ATTR_VERIT:
2639 		if ((na->time_delta.seconds != 0) ||
2640 		    (na->time_delta.nseconds != 1000))
2641 			error = -1;	/* no match */
2642 		break;
2643 	case NFS4ATTR_FREEIT:
2644 		break;
2645 	}
2646 	return (error);
2647 }
2648 
2649 /* ARGSUSED */
2650 static int
2651 rfs4_fattr4_time_metadata(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2652 	union nfs4_attr_u *na)
2653 {
2654 	int	error = 0;
2655 	timestruc_t ctime;
2656 
2657 	if (RFS4_MANDATTR_ONLY)
2658 		return (ENOTSUP);
2659 
2660 	switch (cmd) {
2661 	case NFS4ATTR_SUPPORTED:
2662 		if (sarg->op == NFS4ATTR_SETIT)
2663 			error = EINVAL;
2664 		break;		/* this attr is supported */
2665 	case NFS4ATTR_GETIT:
2666 		if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_CTIME)) {
2667 			error = -1;	/* may be okay if rdattr_error */
2668 			break;
2669 		}
2670 		ASSERT(sarg->vap->va_mask & AT_CTIME);
2671 		error = nfs4_time_vton(&sarg->vap->va_ctime,
2672 		    &na->time_metadata);
2673 		break;
2674 	case NFS4ATTR_SETIT:
2675 		/*
2676 		 * read-only attr
2677 		 */
2678 		error = EINVAL;
2679 		break;
2680 	case NFS4ATTR_VERIT:
2681 		ASSERT(sarg->vap->va_mask & AT_CTIME);
2682 		error = nfs4_time_ntov(&na->time_metadata, &ctime);
2683 		if (error)
2684 			break;
2685 		if (bcmp(&ctime, &sarg->vap->va_ctime, sizeof (ctime)))
2686 			error = -1;	/* no match */
2687 		break;
2688 	case NFS4ATTR_FREEIT:
2689 		break;
2690 	}
2691 	return (error);
2692 }
2693 
2694 /* ARGSUSED */
2695 static int
2696 rfs4_fattr4_time_modify(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2697 	union nfs4_attr_u *na)
2698 {
2699 	int	error = 0;
2700 	timestruc_t mtime;
2701 
2702 	if (RFS4_MANDATTR_ONLY)
2703 		return (ENOTSUP);
2704 
2705 	switch (cmd) {
2706 	case NFS4ATTR_SUPPORTED:
2707 		if (sarg->op == NFS4ATTR_SETIT)
2708 			error = EINVAL;
2709 		break;		/* this attr is supported */
2710 	case NFS4ATTR_GETIT:
2711 		if (sarg->rdattr_error && !(sarg->vap->va_mask & AT_MTIME)) {
2712 			error = -1;	/* may be okay if rdattr_error */
2713 			break;
2714 		}
2715 		ASSERT(sarg->vap->va_mask & AT_MTIME);
2716 		error = nfs4_time_vton(&sarg->vap->va_mtime, &na->time_modify);
2717 		break;
2718 	case NFS4ATTR_SETIT:
2719 		/*
2720 		 * read-only attr
2721 		 */
2722 		error = EINVAL;
2723 		break;
2724 	case NFS4ATTR_VERIT:
2725 		ASSERT(sarg->vap->va_mask & AT_MTIME);
2726 		error = nfs4_time_ntov(&na->time_modify, &mtime);
2727 		if (error)
2728 			break;
2729 		if (bcmp(&mtime, &sarg->vap->va_mtime, sizeof (mtime)))
2730 			error = -1;	/* no match */
2731 		break;
2732 	case NFS4ATTR_FREEIT:
2733 		break;
2734 	}
2735 	return (error);
2736 }
2737 
2738 /*
2739  * XXX - need to add support for setting modify time
2740  */
2741 /* ARGSUSED */
2742 static int
2743 rfs4_fattr4_time_modify_set(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
2744 	union nfs4_attr_u *na)
2745 {
2746 	int	error = 0;
2747 	settime4 *tm;
2748 
2749 	if (RFS4_MANDATTR_ONLY)
2750 		return (ENOTSUP);
2751 
2752 	switch (cmd) {
2753 	case NFS4ATTR_SUPPORTED:
2754 		if ((sarg->op == NFS4ATTR_GETIT) ||
2755 		    (sarg->op == NFS4ATTR_VERIT))
2756 			error = EINVAL;
2757 		break;		/* this attr is supported */
2758 	case NFS4ATTR_GETIT:
2759 	case NFS4ATTR_VERIT:
2760 		/*
2761 		 * write only attr
2762 		 */
2763 		error = EINVAL;
2764 		break;
2765 	case NFS4ATTR_SETIT:
2766 		ASSERT(sarg->vap->va_mask & AT_MTIME);
2767 		/*
2768 		 * Set modify time (by server or by client)
2769 		 */
2770 		tm = &na->time_modify_set;
2771 		if (tm->set_it == SET_TO_CLIENT_TIME4) {
2772 			error = nfs4_time_ntov(&tm->time, &sarg->vap->va_mtime);
2773 			sarg->flag = ATTR_UTIME;
2774 		} else if (tm->set_it == SET_TO_SERVER_TIME4) {
2775 			gethrestime(&sarg->vap->va_mtime);
2776 		} else {
2777 			error = EINVAL;
2778 		}
2779 		break;
2780 	case NFS4ATTR_FREEIT:
2781 		break;
2782 	}
2783 	return (error);
2784 }
2785 
2786 
2787 static void
2788 rfs4_ntov_init(void)
2789 {
2790 	/* index must be same as corresponding FATTR4_* define */
2791 	nfs4_ntov_map[0].sv_getit = rfs4_fattr4_supported_attrs;
2792 	nfs4_ntov_map[1].sv_getit = rfs4_fattr4_type;
2793 	nfs4_ntov_map[2].sv_getit = rfs4_fattr4_fh_expire_type;
2794 	nfs4_ntov_map[3].sv_getit = rfs4_fattr4_change;
2795 	nfs4_ntov_map[4].sv_getit = rfs4_fattr4_size;
2796 	nfs4_ntov_map[5].sv_getit = rfs4_fattr4_link_support;
2797 	nfs4_ntov_map[6].sv_getit = rfs4_fattr4_symlink_support;
2798 	nfs4_ntov_map[7].sv_getit = rfs4_fattr4_named_attr;
2799 	nfs4_ntov_map[8].sv_getit = rfs4_fattr4_fsid;
2800 	nfs4_ntov_map[9].sv_getit = rfs4_fattr4_unique_handles;
2801 	nfs4_ntov_map[10].sv_getit = rfs4_fattr4_lease_time;
2802 	nfs4_ntov_map[11].sv_getit = rfs4_fattr4_rdattr_error;
2803 	nfs4_ntov_map[12].sv_getit = rfs4_fattr4_acl;
2804 	nfs4_ntov_map[13].sv_getit = rfs4_fattr4_aclsupport;
2805 	nfs4_ntov_map[14].sv_getit = rfs4_fattr4_archive;
2806 	nfs4_ntov_map[15].sv_getit = rfs4_fattr4_cansettime;
2807 	nfs4_ntov_map[16].sv_getit = rfs4_fattr4_case_insensitive;
2808 	nfs4_ntov_map[17].sv_getit = rfs4_fattr4_case_preserving;
2809 	nfs4_ntov_map[18].sv_getit = rfs4_fattr4_chown_restricted;
2810 	nfs4_ntov_map[19].sv_getit = rfs4_fattr4_filehandle;
2811 	nfs4_ntov_map[20].sv_getit = rfs4_fattr4_fileid;
2812 	nfs4_ntov_map[21].sv_getit = rfs4_fattr4_files_avail;
2813 	nfs4_ntov_map[22].sv_getit = rfs4_fattr4_files_free;
2814 	nfs4_ntov_map[23].sv_getit = rfs4_fattr4_files_total;
2815 	nfs4_ntov_map[24].sv_getit = rfs4_fattr4_fs_locations;
2816 	nfs4_ntov_map[25].sv_getit = rfs4_fattr4_hidden;
2817 	nfs4_ntov_map[26].sv_getit = rfs4_fattr4_homogeneous;
2818 	nfs4_ntov_map[27].sv_getit = rfs4_fattr4_maxfilesize;
2819 	nfs4_ntov_map[28].sv_getit = rfs4_fattr4_maxlink;
2820 	nfs4_ntov_map[29].sv_getit = rfs4_fattr4_maxname;
2821 	nfs4_ntov_map[30].sv_getit = rfs4_fattr4_maxread;
2822 	nfs4_ntov_map[31].sv_getit = rfs4_fattr4_maxwrite;
2823 	nfs4_ntov_map[32].sv_getit = rfs4_fattr4_mimetype;
2824 	nfs4_ntov_map[33].sv_getit = rfs4_fattr4_mode;
2825 	nfs4_ntov_map[34].sv_getit = rfs4_fattr4_no_trunc;
2826 	nfs4_ntov_map[35].sv_getit = rfs4_fattr4_numlinks;
2827 	nfs4_ntov_map[36].sv_getit = rfs4_fattr4_owner;
2828 	nfs4_ntov_map[37].sv_getit = rfs4_fattr4_owner_group;
2829 	nfs4_ntov_map[38].sv_getit = rfs4_fattr4_quota_avail_hard;
2830 	nfs4_ntov_map[39].sv_getit = rfs4_fattr4_quota_avail_soft;
2831 	nfs4_ntov_map[40].sv_getit = rfs4_fattr4_quota_used;
2832 	nfs4_ntov_map[41].sv_getit = rfs4_fattr4_rawdev;
2833 	nfs4_ntov_map[42].sv_getit = rfs4_fattr4_space_avail;
2834 	nfs4_ntov_map[43].sv_getit = rfs4_fattr4_space_free;
2835 	nfs4_ntov_map[44].sv_getit = rfs4_fattr4_space_total;
2836 	nfs4_ntov_map[45].sv_getit = rfs4_fattr4_space_used;
2837 	nfs4_ntov_map[46].sv_getit = rfs4_fattr4_system;
2838 	nfs4_ntov_map[47].sv_getit = rfs4_fattr4_time_access;
2839 	nfs4_ntov_map[48].sv_getit = rfs4_fattr4_time_access_set;
2840 	nfs4_ntov_map[49].sv_getit = rfs4_fattr4_time_backup;
2841 	nfs4_ntov_map[50].sv_getit = rfs4_fattr4_time_create;
2842 	nfs4_ntov_map[51].sv_getit = rfs4_fattr4_time_delta;
2843 	nfs4_ntov_map[52].sv_getit = rfs4_fattr4_time_metadata;
2844 	nfs4_ntov_map[53].sv_getit = rfs4_fattr4_time_modify;
2845 	nfs4_ntov_map[54].sv_getit = rfs4_fattr4_time_modify_set;
2846 	nfs4_ntov_map[55].sv_getit = rfs4_fattr4_mounted_on_fileid;
2847 }
2848