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