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