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