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