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