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 }