Print this page
    
Fix NFS design problems re. multiple zone keys
Make NFS server zone-specific data all have the same lifetime
Fix rfs4_clean_state_exi
Fix exi_cache_reclaim
Fix mistakes in zone keys work
More fixes re. exi_zoneid and exi_tree
(danmcd -> Keep some ASSERT()s around for readability.)
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/fs/nfs/nfs3_srv.c
          +++ new/usr/src/uts/common/fs/nfs/nfs3_srv.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright 2018 Nexenta Systems, Inc.
  24   24   * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
  25   25   * Copyright (c) 2013 by Delphix. All rights reserved.
  26   26   */
  27   27  
  28   28  /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
  29   29  /* All Rights Reserved */
  30   30  
  31   31  
  32   32  #include <sys/param.h>
  33   33  #include <sys/types.h>
  34   34  #include <sys/systm.h>
  35   35  #include <sys/cred.h>
  36   36  #include <sys/buf.h>
  37   37  #include <sys/vfs.h>
  38   38  #include <sys/vnode.h>
  39   39  #include <sys/uio.h>
  40   40  #include <sys/errno.h>
  41   41  #include <sys/sysmacros.h>
  42   42  #include <sys/statvfs.h>
  43   43  #include <sys/kmem.h>
  44   44  #include <sys/dirent.h>
  45   45  #include <sys/cmn_err.h>
  46   46  #include <sys/debug.h>
  47   47  #include <sys/systeminfo.h>
  48   48  #include <sys/flock.h>
  49   49  #include <sys/nbmlock.h>
  50   50  #include <sys/policy.h>
  51   51  #include <sys/sdt.h>
  52   52  
  53   53  #include <rpc/types.h>
  54   54  #include <rpc/auth.h>
  55   55  #include <rpc/svc.h>
  56   56  #include <rpc/rpc_rdma.h>
  57   57  
  58   58  #include <nfs/nfs.h>
  59   59  #include <nfs/export.h>
  60   60  #include <nfs/nfs_cmd.h>
  61   61  
  62   62  #include <sys/strsubr.h>
  63   63  #include <sys/tsol/label.h>
  64   64  #include <sys/tsol/tndb.h>
  65   65  
  66   66  #include <sys/zone.h>
  67   67  
  68   68  #include <inet/ip.h>
  69   69  #include <inet/ip6.h>
  70   70  
  71   71  /*
  72   72   * Zone global variables of NFSv3 server
  73   73   */
  74   74  typedef struct nfs3_srv {
  75   75          writeverf3      write3verf;
  76   76  } nfs3_srv_t;
  77   77  
  78   78  /*
  79   79   * These are the interface routines for the server side of the
  80   80   * Network File System.  See the NFS version 3 protocol specification
  81   81   * for a description of this interface.
  82   82   */
  83   83  
  
    | 
      ↓ open down ↓ | 
    83 lines elided | 
    
      ↑ open up ↑ | 
  
  84   84  static int      sattr3_to_vattr(sattr3 *, struct vattr *);
  85   85  static int      vattr_to_fattr3(struct vattr *, fattr3 *);
  86   86  static int      vattr_to_wcc_attr(struct vattr *, wcc_attr *);
  87   87  static void     vattr_to_pre_op_attr(struct vattr *, pre_op_attr *);
  88   88  static void     vattr_to_wcc_data(struct vattr *, struct vattr *, wcc_data *);
  89   89  static int      rdma_setup_read_data3(READ3args *, READ3resok *);
  90   90  
  91   91  extern int nfs_loaned_buffers;
  92   92  
  93   93  u_longlong_t nfs3_srv_caller_id;
  94      -static zone_key_t rfs3_zone_key;
  95   94  
       95 +static nfs3_srv_t *
       96 +nfs3_get_srv(void)
       97 +{
       98 +        nfs_globals_t *ng = zone_getspecific(nfssrv_zone_key, curzone);
       99 +        nfs3_srv_t *srv = ng->nfs3_srv;
      100 +        ASSERT(srv != NULL);
      101 +        return (srv);
      102 +}
      103 +
  96  104  /* ARGSUSED */
  97  105  void
  98  106  rfs3_getattr(GETATTR3args *args, GETATTR3res *resp, struct exportinfo *exi,
  99  107      struct svc_req *req, cred_t *cr, bool_t ro)
 100  108  {
 101  109          int error;
 102  110          vnode_t *vp;
 103  111          struct vattr va;
 104  112  
 105  113          vp = nfs3_fhtovp(&args->object, exi);
 106  114  
 107  115          DTRACE_NFSV3_5(op__getattr__start, struct svc_req *, req,
 108  116              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 109  117              GETATTR3args *, args);
 110  118  
 111  119          if (vp == NULL) {
 112  120                  error = ESTALE;
 113  121                  goto out;
 114  122          }
 115  123  
 116  124          va.va_mask = AT_ALL;
 117  125          error = rfs4_delegated_getattr(vp, &va, 0, cr);
 118  126  
 119  127          if (!error) {
 120  128                  /* Lie about the object type for a referral */
 121  129                  if (vn_is_nfs_reparse(vp, cr))
 122  130                          va.va_type = VLNK;
 123  131  
 124  132                  /* overflow error if time or size is out of range */
 125  133                  error = vattr_to_fattr3(&va, &resp->resok.obj_attributes);
 126  134                  if (error)
 127  135                          goto out;
 128  136                  resp->status = NFS3_OK;
 129  137  
 130  138                  DTRACE_NFSV3_5(op__getattr__done, struct svc_req *, req,
 131  139                      cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 132  140                      GETATTR3res *, resp);
 133  141  
 134  142                  VN_RELE(vp);
 135  143  
 136  144                  return;
 137  145          }
 138  146  
 139  147  out:
 140  148          if (curthread->t_flag & T_WOULDBLOCK) {
 141  149                  curthread->t_flag &= ~T_WOULDBLOCK;
 142  150                  resp->status = NFS3ERR_JUKEBOX;
 143  151          } else
 144  152                  resp->status = puterrno3(error);
 145  153  
 146  154          DTRACE_NFSV3_5(op__getattr__done, struct svc_req *, req,
 147  155              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 148  156              GETATTR3res *, resp);
 149  157  
 150  158          if (vp != NULL)
 151  159                  VN_RELE(vp);
 152  160  }
 153  161  
 154  162  void *
 155  163  rfs3_getattr_getfh(GETATTR3args *args)
 156  164  {
 157  165  
 158  166          return (&args->object);
 159  167  }
 160  168  
 161  169  void
 162  170  rfs3_setattr(SETATTR3args *args, SETATTR3res *resp, struct exportinfo *exi,
 163  171      struct svc_req *req, cred_t *cr, bool_t ro)
 164  172  {
 165  173          int error;
 166  174          vnode_t *vp;
 167  175          struct vattr *bvap;
 168  176          struct vattr bva;
 169  177          struct vattr *avap;
 170  178          struct vattr ava;
 171  179          int flag;
 172  180          int in_crit = 0;
 173  181          struct flock64 bf;
 174  182          caller_context_t ct;
 175  183  
 176  184          bvap = NULL;
 177  185          avap = NULL;
 178  186  
 179  187          vp = nfs3_fhtovp(&args->object, exi);
 180  188  
 181  189          DTRACE_NFSV3_5(op__setattr__start, struct svc_req *, req,
 182  190              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 183  191              SETATTR3args *, args);
 184  192  
 185  193          if (vp == NULL) {
 186  194                  error = ESTALE;
 187  195                  goto out;
 188  196          }
 189  197  
 190  198          error = sattr3_to_vattr(&args->new_attributes, &ava);
 191  199          if (error)
 192  200                  goto out;
 193  201  
 194  202          if (is_system_labeled()) {
 195  203                  bslabel_t *clabel = req->rq_label;
 196  204  
 197  205                  ASSERT(clabel != NULL);
 198  206                  DTRACE_PROBE2(tx__rfs3__log__info__opsetattr__clabel, char *,
 199  207                      "got client label from request(1)", struct svc_req *, req);
 200  208  
 201  209                  if (!blequal(&l_admin_low->tsl_label, clabel)) {
 202  210                          if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
 203  211                              exi)) {
 204  212                                  resp->status = NFS3ERR_ACCES;
 205  213                                  goto out1;
 206  214                          }
 207  215                  }
 208  216          }
 209  217  
 210  218          /*
 211  219           * We need to specially handle size changes because of
 212  220           * possible conflicting NBMAND locks. Get into critical
 213  221           * region before VOP_GETATTR, so the size attribute is
 214  222           * valid when checking conflicts.
 215  223           *
 216  224           * Also, check to see if the v4 side of the server has
 217  225           * delegated this file.  If so, then we return JUKEBOX to
 218  226           * allow the client to retrasmit its request.
 219  227           */
 220  228          if (vp->v_type == VREG && (ava.va_mask & AT_SIZE)) {
 221  229                  if (nbl_need_check(vp)) {
 222  230                          nbl_start_crit(vp, RW_READER);
 223  231                          in_crit = 1;
 224  232                  }
 225  233          }
 226  234  
 227  235          bva.va_mask = AT_ALL;
 228  236          error = rfs4_delegated_getattr(vp, &bva, 0, cr);
 229  237  
 230  238          /*
 231  239           * If we can't get the attributes, then we can't do the
 232  240           * right access checking.  So, we'll fail the request.
 233  241           */
 234  242          if (error)
 235  243                  goto out;
 236  244  
 237  245          bvap = &bva;
 238  246  
 239  247          if (rdonly(ro, vp)) {
 240  248                  resp->status = NFS3ERR_ROFS;
 241  249                  goto out1;
 242  250          }
 243  251  
 244  252          if (args->guard.check &&
 245  253              (args->guard.obj_ctime.seconds != bva.va_ctime.tv_sec ||
 246  254              args->guard.obj_ctime.nseconds != bva.va_ctime.tv_nsec)) {
 247  255                  resp->status = NFS3ERR_NOT_SYNC;
 248  256                  goto out1;
 249  257          }
 250  258  
 251  259          if (args->new_attributes.mtime.set_it == SET_TO_CLIENT_TIME)
 252  260                  flag = ATTR_UTIME;
 253  261          else
 254  262                  flag = 0;
 255  263  
 256  264          /*
 257  265           * If the filesystem is exported with nosuid, then mask off
 258  266           * the setuid and setgid bits.
 259  267           */
 260  268          if ((ava.va_mask & AT_MODE) && vp->v_type == VREG &&
 261  269              (exi->exi_export.ex_flags & EX_NOSUID))
 262  270                  ava.va_mode &= ~(VSUID | VSGID);
 263  271  
 264  272          ct.cc_sysid = 0;
 265  273          ct.cc_pid = 0;
 266  274          ct.cc_caller_id = nfs3_srv_caller_id;
 267  275          ct.cc_flags = CC_DONTBLOCK;
 268  276  
 269  277          /*
 270  278           * We need to specially handle size changes because it is
 271  279           * possible for the client to create a file with modes
 272  280           * which indicate read-only, but with the file opened for
 273  281           * writing.  If the client then tries to set the size of
 274  282           * the file, then the normal access checking done in
 275  283           * VOP_SETATTR would prevent the client from doing so,
 276  284           * although it should be legal for it to do so.  To get
 277  285           * around this, we do the access checking for ourselves
 278  286           * and then use VOP_SPACE which doesn't do the access
 279  287           * checking which VOP_SETATTR does. VOP_SPACE can only
 280  288           * operate on VREG files, let VOP_SETATTR handle the other
 281  289           * extremely rare cases.
 282  290           * Also the client should not be allowed to change the
 283  291           * size of the file if there is a conflicting non-blocking
 284  292           * mandatory lock in the region the change.
 285  293           */
 286  294          if (vp->v_type == VREG && (ava.va_mask & AT_SIZE)) {
 287  295                  if (in_crit) {
 288  296                          u_offset_t offset;
 289  297                          ssize_t length;
 290  298  
 291  299                          if (ava.va_size < bva.va_size) {
 292  300                                  offset = ava.va_size;
 293  301                                  length = bva.va_size - ava.va_size;
 294  302                          } else {
 295  303                                  offset = bva.va_size;
 296  304                                  length = ava.va_size - bva.va_size;
 297  305                          }
 298  306                          if (nbl_conflict(vp, NBL_WRITE, offset, length, 0,
 299  307                              NULL)) {
 300  308                                  error = EACCES;
 301  309                                  goto out;
 302  310                          }
 303  311                  }
 304  312  
 305  313                  if (crgetuid(cr) == bva.va_uid && ava.va_size != bva.va_size) {
 306  314                          ava.va_mask &= ~AT_SIZE;
 307  315                          bf.l_type = F_WRLCK;
 308  316                          bf.l_whence = 0;
 309  317                          bf.l_start = (off64_t)ava.va_size;
 310  318                          bf.l_len = 0;
 311  319                          bf.l_sysid = 0;
 312  320                          bf.l_pid = 0;
 313  321                          error = VOP_SPACE(vp, F_FREESP, &bf, FWRITE,
 314  322                              (offset_t)ava.va_size, cr, &ct);
 315  323                  }
 316  324          }
 317  325  
 318  326          if (!error && ava.va_mask)
 319  327                  error = VOP_SETATTR(vp, &ava, flag, cr, &ct);
 320  328  
 321  329          /* check if a monitor detected a delegation conflict */
 322  330          if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
 323  331                  resp->status = NFS3ERR_JUKEBOX;
 324  332                  goto out1;
 325  333          }
 326  334  
 327  335          ava.va_mask = AT_ALL;
 328  336          avap = rfs4_delegated_getattr(vp, &ava, 0, cr) ? NULL : &ava;
 329  337  
 330  338          /*
 331  339           * Force modified metadata out to stable storage.
 332  340           */
 333  341          (void) VOP_FSYNC(vp, FNODSYNC, cr, &ct);
 334  342  
 335  343          if (error)
 336  344                  goto out;
 337  345  
 338  346          if (in_crit)
 339  347                  nbl_end_crit(vp);
 340  348  
 341  349          resp->status = NFS3_OK;
 342  350          vattr_to_wcc_data(bvap, avap, &resp->resok.obj_wcc);
 343  351  
 344  352          DTRACE_NFSV3_5(op__setattr__done, struct svc_req *, req,
 345  353              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 346  354              SETATTR3res *, resp);
 347  355  
 348  356          VN_RELE(vp);
 349  357  
 350  358          return;
 351  359  
 352  360  out:
 353  361          if (curthread->t_flag & T_WOULDBLOCK) {
 354  362                  curthread->t_flag &= ~T_WOULDBLOCK;
 355  363                  resp->status = NFS3ERR_JUKEBOX;
 356  364          } else
 357  365                  resp->status = puterrno3(error);
 358  366  out1:
 359  367          DTRACE_NFSV3_5(op__setattr__done, struct svc_req *, req,
 360  368              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 361  369              SETATTR3res *, resp);
 362  370  
 363  371          if (vp != NULL) {
 364  372                  if (in_crit)
 365  373                          nbl_end_crit(vp);
 366  374                  VN_RELE(vp);
 367  375          }
 368  376          vattr_to_wcc_data(bvap, avap, &resp->resfail.obj_wcc);
 369  377  }
 370  378  
 371  379  void *
 372  380  rfs3_setattr_getfh(SETATTR3args *args)
 373  381  {
 374  382  
 375  383          return (&args->object);
 376  384  }
 377  385  
 378  386  /* ARGSUSED */
 379  387  void
 380  388  rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi,
 381  389      struct svc_req *req, cred_t *cr, bool_t ro)
 382  390  {
 383  391          int error;
 384  392          vnode_t *vp;
 385  393          vnode_t *dvp;
 386  394          struct vattr *vap;
 387  395          struct vattr va;
 388  396          struct vattr *dvap;
 389  397          struct vattr dva;
 390  398          nfs_fh3 *fhp;
 391  399          struct sec_ol sec = {0, 0};
 392  400          bool_t publicfh_flag = FALSE, auth_weak = FALSE;
 393  401          struct sockaddr *ca;
 394  402          char *name = NULL;
 395  403  
 396  404          dvap = NULL;
 397  405  
 398  406          if (exi != NULL)
 399  407                  exi_hold(exi);
 400  408  
 401  409          /*
 402  410           * Allow lookups from the root - the default
 403  411           * location of the public filehandle.
 404  412           */
 405  413          if (exi != NULL && (exi->exi_export.ex_flags & EX_PUBLIC)) {
 406  414                  dvp = ZONE_ROOTVP();
 407  415                  VN_HOLD(dvp);
 408  416  
 409  417                  DTRACE_NFSV3_5(op__lookup__start, struct svc_req *, req,
 410  418                      cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
 411  419                      LOOKUP3args *, args);
 412  420          } else {
 413  421                  dvp = nfs3_fhtovp(&args->what.dir, exi);
 414  422  
 415  423                  DTRACE_NFSV3_5(op__lookup__start, struct svc_req *, req,
 416  424                      cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
 417  425                      LOOKUP3args *, args);
 418  426  
 419  427                  if (dvp == NULL) {
 420  428                          error = ESTALE;
 421  429                          goto out;
 422  430                  }
 423  431          }
 424  432  
 425  433          dva.va_mask = AT_ALL;
 426  434          dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
 427  435  
 428  436          if (args->what.name == nfs3nametoolong) {
 429  437                  resp->status = NFS3ERR_NAMETOOLONG;
 430  438                  goto out1;
 431  439          }
 432  440  
 433  441          if (args->what.name == NULL || *(args->what.name) == '\0') {
 434  442                  resp->status = NFS3ERR_ACCES;
 435  443                  goto out1;
 436  444          }
 437  445  
 438  446          fhp = &args->what.dir;
 439  447          ASSERT3P(curzone, ==, exi->exi_zone); /* exi is guaranteed non-NULL. */
 440  448          if (strcmp(args->what.name, "..") == 0 &&
 441  449              EQFID(&exi->exi_fid, FH3TOFIDP(fhp))) {
 442  450                  if ((exi->exi_export.ex_flags & EX_NOHIDE) &&
 443  451                      ((dvp->v_flag & VROOT) || VN_IS_CURZONEROOT(dvp))) {
 444  452                          /*
 445  453                           * special case for ".." and 'nohide'exported root
 446  454                           */
 447  455                          if (rfs_climb_crossmnt(&dvp, &exi, cr) != 0) {
 448  456                                  resp->status = NFS3ERR_ACCES;
 449  457                                  goto out1;
 450  458                          }
 451  459                  } else {
 452  460                          resp->status = NFS3ERR_NOENT;
 453  461                          goto out1;
 454  462                  }
 455  463          }
 456  464  
 457  465          ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
 458  466          name = nfscmd_convname(ca, exi, args->what.name,
 459  467              NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
 460  468  
 461  469          if (name == NULL) {
 462  470                  resp->status = NFS3ERR_ACCES;
 463  471                  goto out1;
 464  472          }
 465  473  
 466  474          /*
 467  475           * If the public filehandle is used then allow
 468  476           * a multi-component lookup
 469  477           */
 470  478          if (PUBLIC_FH3(&args->what.dir)) {
 471  479                  publicfh_flag = TRUE;
 472  480  
 473  481                  exi_rele(exi);
 474  482  
 475  483                  error = rfs_publicfh_mclookup(name, dvp, cr, &vp,
 476  484                      &exi, &sec);
 477  485  
 478  486                  /*
 479  487                   * Since WebNFS may bypass MOUNT, we need to ensure this
 480  488                   * request didn't come from an unlabeled admin_low client.
 481  489                   */
 482  490                  if (is_system_labeled() && error == 0) {
 483  491                          int             addr_type;
 484  492                          void            *ipaddr;
 485  493                          tsol_tpc_t      *tp;
 486  494  
 487  495                          if (ca->sa_family == AF_INET) {
 488  496                                  addr_type = IPV4_VERSION;
 489  497                                  ipaddr = &((struct sockaddr_in *)ca)->sin_addr;
 490  498                          } else if (ca->sa_family == AF_INET6) {
 491  499                                  addr_type = IPV6_VERSION;
 492  500                                  ipaddr = &((struct sockaddr_in6 *)
 493  501                                      ca)->sin6_addr;
 494  502                          }
 495  503                          tp = find_tpc(ipaddr, addr_type, B_FALSE);
 496  504                          if (tp == NULL || tp->tpc_tp.tp_doi !=
 497  505                              l_admin_low->tsl_doi || tp->tpc_tp.host_type !=
 498  506                              SUN_CIPSO) {
 499  507                                  VN_RELE(vp);
 500  508                                  error = EACCES;
 501  509                          }
 502  510                          if (tp != NULL)
 503  511                                  TPC_RELE(tp);
 504  512                  }
 505  513          } else {
 506  514                  error = VOP_LOOKUP(dvp, name, &vp,
 507  515                      NULL, 0, NULL, cr, NULL, NULL, NULL);
 508  516          }
 509  517  
 510  518          if (name != args->what.name)
 511  519                  kmem_free(name, MAXPATHLEN + 1);
 512  520  
 513  521          if (error == 0 && vn_ismntpt(vp)) {
 514  522                  error = rfs_cross_mnt(&vp, &exi);
 515  523                  if (error)
 516  524                          VN_RELE(vp);
 517  525          }
 518  526  
 519  527          if (is_system_labeled() && error == 0) {
 520  528                  bslabel_t *clabel = req->rq_label;
 521  529  
 522  530                  ASSERT(clabel != NULL);
 523  531                  DTRACE_PROBE2(tx__rfs3__log__info__oplookup__clabel, char *,
 524  532                      "got client label from request(1)", struct svc_req *, req);
 525  533  
 526  534                  if (!blequal(&l_admin_low->tsl_label, clabel)) {
 527  535                          if (!do_rfs_label_check(clabel, dvp,
 528  536                              DOMINANCE_CHECK, exi)) {
 529  537                                  VN_RELE(vp);
 530  538                                  error = EACCES;
 531  539                          }
 532  540                  }
 533  541          }
 534  542  
 535  543          dva.va_mask = AT_ALL;
 536  544          dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
 537  545  
 538  546          if (error)
 539  547                  goto out;
 540  548  
 541  549          if (sec.sec_flags & SEC_QUERY) {
 542  550                  error = makefh3_ol(&resp->resok.object, exi, sec.sec_index);
 543  551          } else {
 544  552                  error = makefh3(&resp->resok.object, vp, exi);
 545  553                  if (!error && publicfh_flag && !chk_clnt_sec(exi, req))
 546  554                          auth_weak = TRUE;
 547  555          }
 548  556  
 549  557          if (error) {
 550  558                  VN_RELE(vp);
 551  559                  goto out;
 552  560          }
 553  561  
 554  562          va.va_mask = AT_ALL;
 555  563          vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
 556  564  
 557  565          exi_rele(exi);
 558  566          VN_RELE(vp);
 559  567  
 560  568          resp->status = NFS3_OK;
 561  569          vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
 562  570          vattr_to_post_op_attr(dvap, &resp->resok.dir_attributes);
 563  571  
 564  572          /*
 565  573           * If it's public fh, no 0x81, and client's flavor is
 566  574           * invalid, set WebNFS status to WNFSERR_CLNT_FLAVOR now.
 567  575           * Then set RPC status to AUTH_TOOWEAK in common_dispatch.
 568  576           */
 569  577          if (auth_weak)
 570  578                  resp->status = (enum nfsstat3)WNFSERR_CLNT_FLAVOR;
 571  579  
 572  580          DTRACE_NFSV3_5(op__lookup__done, struct svc_req *, req,
 573  581              cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
 574  582              LOOKUP3res *, resp);
 575  583          VN_RELE(dvp);
 576  584  
 577  585          return;
 578  586  
 579  587  out:
 580  588          if (curthread->t_flag & T_WOULDBLOCK) {
 581  589                  curthread->t_flag &= ~T_WOULDBLOCK;
 582  590                  resp->status = NFS3ERR_JUKEBOX;
 583  591          } else
 584  592                  resp->status = puterrno3(error);
 585  593  out1:
 586  594          DTRACE_NFSV3_5(op__lookup__done, struct svc_req *, req,
 587  595              cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
 588  596              LOOKUP3res *, resp);
 589  597  
 590  598          if (exi != NULL)
 591  599                  exi_rele(exi);
 592  600  
 593  601          if (dvp != NULL)
 594  602                  VN_RELE(dvp);
 595  603          vattr_to_post_op_attr(dvap, &resp->resfail.dir_attributes);
 596  604  
 597  605  }
 598  606  
 599  607  void *
 600  608  rfs3_lookup_getfh(LOOKUP3args *args)
 601  609  {
 602  610  
 603  611          return (&args->what.dir);
 604  612  }
 605  613  
 606  614  /* ARGSUSED */
 607  615  void
 608  616  rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi,
 609  617      struct svc_req *req, cred_t *cr, bool_t ro)
 610  618  {
 611  619          int error;
 612  620          vnode_t *vp;
 613  621          struct vattr *vap;
 614  622          struct vattr va;
 615  623          int checkwriteperm;
 616  624          boolean_t dominant_label = B_FALSE;
 617  625          boolean_t equal_label = B_FALSE;
 618  626          boolean_t admin_low_client;
 619  627  
 620  628          vap = NULL;
 621  629  
 622  630          vp = nfs3_fhtovp(&args->object, exi);
 623  631  
 624  632          DTRACE_NFSV3_5(op__access__start, struct svc_req *, req,
 625  633              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 626  634              ACCESS3args *, args);
 627  635  
 628  636          if (vp == NULL) {
 629  637                  error = ESTALE;
 630  638                  goto out;
 631  639          }
 632  640  
 633  641          /*
 634  642           * If the file system is exported read only, it is not appropriate
 635  643           * to check write permissions for regular files and directories.
 636  644           * Special files are interpreted by the client, so the underlying
 637  645           * permissions are sent back to the client for interpretation.
 638  646           */
 639  647          if (rdonly(ro, vp) && (vp->v_type == VREG || vp->v_type == VDIR))
 640  648                  checkwriteperm = 0;
 641  649          else
 642  650                  checkwriteperm = 1;
 643  651  
 644  652          /*
 645  653           * We need the mode so that we can correctly determine access
 646  654           * permissions relative to a mandatory lock file.  Access to
 647  655           * mandatory lock files is denied on the server, so it might
 648  656           * as well be reflected to the server during the open.
 649  657           */
 650  658          va.va_mask = AT_MODE;
 651  659          error = VOP_GETATTR(vp, &va, 0, cr, NULL);
 652  660          if (error)
 653  661                  goto out;
 654  662  
 655  663          vap = &va;
 656  664  
 657  665          resp->resok.access = 0;
 658  666  
 659  667          if (is_system_labeled()) {
 660  668                  bslabel_t *clabel = req->rq_label;
 661  669  
 662  670                  ASSERT(clabel != NULL);
 663  671                  DTRACE_PROBE2(tx__rfs3__log__info__opaccess__clabel, char *,
 664  672                      "got client label from request(1)", struct svc_req *, req);
 665  673  
 666  674                  if (!blequal(&l_admin_low->tsl_label, clabel)) {
 667  675                          if ((equal_label = do_rfs_label_check(clabel, vp,
 668  676                              EQUALITY_CHECK, exi)) == B_FALSE) {
 669  677                                  dominant_label = do_rfs_label_check(clabel,
 670  678                                      vp, DOMINANCE_CHECK, exi);
 671  679                          } else
 672  680                                  dominant_label = B_TRUE;
 673  681                          admin_low_client = B_FALSE;
 674  682                  } else
 675  683                          admin_low_client = B_TRUE;
 676  684          }
 677  685  
 678  686          if (args->access & ACCESS3_READ) {
 679  687                  error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
 680  688                  if (error) {
 681  689                          if (curthread->t_flag & T_WOULDBLOCK)
 682  690                                  goto out;
 683  691                  } else if (!MANDLOCK(vp, va.va_mode) &&
 684  692                      (!is_system_labeled() || admin_low_client ||
 685  693                      dominant_label))
 686  694                          resp->resok.access |= ACCESS3_READ;
 687  695          }
 688  696          if ((args->access & ACCESS3_LOOKUP) && vp->v_type == VDIR) {
 689  697                  error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
 690  698                  if (error) {
 691  699                          if (curthread->t_flag & T_WOULDBLOCK)
 692  700                                  goto out;
 693  701                  } else if (!is_system_labeled() || admin_low_client ||
 694  702                      dominant_label)
 695  703                          resp->resok.access |= ACCESS3_LOOKUP;
 696  704          }
 697  705          if (checkwriteperm &&
 698  706              (args->access & (ACCESS3_MODIFY|ACCESS3_EXTEND))) {
 699  707                  error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
 700  708                  if (error) {
 701  709                          if (curthread->t_flag & T_WOULDBLOCK)
 702  710                                  goto out;
 703  711                  } else if (!MANDLOCK(vp, va.va_mode) &&
 704  712                      (!is_system_labeled() || admin_low_client || equal_label)) {
 705  713                          resp->resok.access |=
 706  714                              (args->access & (ACCESS3_MODIFY|ACCESS3_EXTEND));
 707  715                  }
 708  716          }
 709  717          if (checkwriteperm &&
 710  718              (args->access & ACCESS3_DELETE) && vp->v_type == VDIR) {
 711  719                  error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
 712  720                  if (error) {
 713  721                          if (curthread->t_flag & T_WOULDBLOCK)
 714  722                                  goto out;
 715  723                  } else if (!is_system_labeled() || admin_low_client ||
 716  724                      equal_label)
 717  725                          resp->resok.access |= ACCESS3_DELETE;
 718  726          }
 719  727          if (args->access & ACCESS3_EXECUTE) {
 720  728                  error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
 721  729                  if (error) {
 722  730                          if (curthread->t_flag & T_WOULDBLOCK)
 723  731                                  goto out;
 724  732                  } else if (!MANDLOCK(vp, va.va_mode) &&
 725  733                      (!is_system_labeled() || admin_low_client ||
 726  734                      dominant_label))
 727  735                          resp->resok.access |= ACCESS3_EXECUTE;
 728  736          }
 729  737  
 730  738          va.va_mask = AT_ALL;
 731  739          vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
 732  740  
 733  741          resp->status = NFS3_OK;
 734  742          vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
 735  743  
 736  744          DTRACE_NFSV3_5(op__access__done, struct svc_req *, req,
 737  745              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 738  746              ACCESS3res *, resp);
 739  747  
 740  748          VN_RELE(vp);
 741  749  
 742  750          return;
 743  751  
 744  752  out:
 745  753          if (curthread->t_flag & T_WOULDBLOCK) {
 746  754                  curthread->t_flag &= ~T_WOULDBLOCK;
 747  755                  resp->status = NFS3ERR_JUKEBOX;
 748  756          } else
 749  757                  resp->status = puterrno3(error);
 750  758          DTRACE_NFSV3_5(op__access__done, struct svc_req *, req,
 751  759              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 752  760              ACCESS3res *, resp);
 753  761          if (vp != NULL)
 754  762                  VN_RELE(vp);
 755  763          vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
 756  764  }
 757  765  
 758  766  void *
 759  767  rfs3_access_getfh(ACCESS3args *args)
 760  768  {
 761  769  
 762  770          return (&args->object);
 763  771  }
 764  772  
 765  773  /* ARGSUSED */
 766  774  void
 767  775  rfs3_readlink(READLINK3args *args, READLINK3res *resp, struct exportinfo *exi,
 768  776      struct svc_req *req, cred_t *cr, bool_t ro)
 769  777  {
 770  778          int error;
 771  779          vnode_t *vp;
 772  780          struct vattr *vap;
 773  781          struct vattr va;
 774  782          struct iovec iov;
 775  783          struct uio uio;
 776  784          char *data;
 777  785          struct sockaddr *ca;
 778  786          char *name = NULL;
 779  787          int is_referral = 0;
 780  788  
 781  789          vap = NULL;
 782  790  
 783  791          vp = nfs3_fhtovp(&args->symlink, exi);
 784  792  
 785  793          DTRACE_NFSV3_5(op__readlink__start, struct svc_req *, req,
 786  794              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 787  795              READLINK3args *, args);
 788  796  
 789  797          if (vp == NULL) {
 790  798                  error = ESTALE;
 791  799                  goto out;
 792  800          }
 793  801  
 794  802          va.va_mask = AT_ALL;
 795  803          error = VOP_GETATTR(vp, &va, 0, cr, NULL);
 796  804          if (error)
 797  805                  goto out;
 798  806  
 799  807          vap = &va;
 800  808  
 801  809          /* We lied about the object type for a referral */
 802  810          if (vn_is_nfs_reparse(vp, cr))
 803  811                  is_referral = 1;
 804  812  
 805  813          if (vp->v_type != VLNK && !is_referral) {
 806  814                  resp->status = NFS3ERR_INVAL;
 807  815                  goto out1;
 808  816          }
 809  817  
 810  818          if (MANDLOCK(vp, va.va_mode)) {
 811  819                  resp->status = NFS3ERR_ACCES;
 812  820                  goto out1;
 813  821          }
 814  822  
 815  823          if (is_system_labeled()) {
 816  824                  bslabel_t *clabel = req->rq_label;
 817  825  
 818  826                  ASSERT(clabel != NULL);
 819  827                  DTRACE_PROBE2(tx__rfs3__log__info__opreadlink__clabel, char *,
 820  828                      "got client label from request(1)", struct svc_req *, req);
 821  829  
 822  830                  if (!blequal(&l_admin_low->tsl_label, clabel)) {
 823  831                          if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
 824  832                              exi)) {
 825  833                                  resp->status = NFS3ERR_ACCES;
 826  834                                  goto out1;
 827  835                          }
 828  836                  }
 829  837          }
 830  838  
 831  839          data = kmem_alloc(MAXPATHLEN + 1, KM_SLEEP);
 832  840  
 833  841          if (is_referral) {
 834  842                  char *s;
 835  843                  size_t strsz;
 836  844  
 837  845                  /* Get an artificial symlink based on a referral */
 838  846                  s = build_symlink(vp, cr, &strsz);
 839  847                  global_svstat_ptr[3][NFS_REFERLINKS].value.ui64++;
 840  848                  DTRACE_PROBE2(nfs3serv__func__referral__reflink,
 841  849                      vnode_t *, vp, char *, s);
 842  850                  if (s == NULL)
 843  851                          error = EINVAL;
 844  852                  else {
 845  853                          error = 0;
 846  854                          (void) strlcpy(data, s, MAXPATHLEN + 1);
 847  855                          kmem_free(s, strsz);
 848  856                  }
 849  857  
 850  858          } else {
 851  859  
 852  860                  iov.iov_base = data;
 853  861                  iov.iov_len = MAXPATHLEN;
 854  862                  uio.uio_iov = &iov;
 855  863                  uio.uio_iovcnt = 1;
 856  864                  uio.uio_segflg = UIO_SYSSPACE;
 857  865                  uio.uio_extflg = UIO_COPY_CACHED;
 858  866                  uio.uio_loffset = 0;
 859  867                  uio.uio_resid = MAXPATHLEN;
 860  868  
 861  869                  error = VOP_READLINK(vp, &uio, cr, NULL);
 862  870  
 863  871                  if (!error)
 864  872                          *(data + MAXPATHLEN - uio.uio_resid) = '\0';
 865  873          }
 866  874  
 867  875          va.va_mask = AT_ALL;
 868  876          vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
 869  877  
 870  878          /* Lie about object type again just to be consistent */
 871  879          if (is_referral && vap != NULL)
 872  880                  vap->va_type = VLNK;
 873  881  
 874  882  #if 0 /* notyet */
 875  883          /*
 876  884           * Don't do this.  It causes local disk writes when just
 877  885           * reading the file and the overhead is deemed larger
 878  886           * than the benefit.
 879  887           */
 880  888          /*
 881  889           * Force modified metadata out to stable storage.
 882  890           */
 883  891          (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
 884  892  #endif
 885  893  
 886  894          if (error) {
 887  895                  kmem_free(data, MAXPATHLEN + 1);
 888  896                  goto out;
 889  897          }
 890  898  
 891  899          ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
 892  900          name = nfscmd_convname(ca, exi, data, NFSCMD_CONV_OUTBOUND,
 893  901              MAXPATHLEN + 1);
 894  902  
 895  903          if (name == NULL) {
 896  904                  /*
 897  905                   * Even though the conversion failed, we return
 898  906                   * something. We just don't translate it.
 899  907                   */
 900  908                  name = data;
 901  909          }
 902  910  
 903  911          resp->status = NFS3_OK;
 904  912          vattr_to_post_op_attr(vap, &resp->resok.symlink_attributes);
 905  913          resp->resok.data = name;
 906  914  
 907  915          DTRACE_NFSV3_5(op__readlink__done, struct svc_req *, req,
 908  916              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 909  917              READLINK3res *, resp);
 910  918          VN_RELE(vp);
 911  919  
 912  920          if (name != data)
 913  921                  kmem_free(data, MAXPATHLEN + 1);
 914  922  
 915  923          return;
 916  924  
 917  925  out:
 918  926          if (curthread->t_flag & T_WOULDBLOCK) {
 919  927                  curthread->t_flag &= ~T_WOULDBLOCK;
 920  928                  resp->status = NFS3ERR_JUKEBOX;
 921  929          } else
 922  930                  resp->status = puterrno3(error);
 923  931  out1:
 924  932          DTRACE_NFSV3_5(op__readlink__done, struct svc_req *, req,
 925  933              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 926  934              READLINK3res *, resp);
 927  935          if (vp != NULL)
 928  936                  VN_RELE(vp);
 929  937          vattr_to_post_op_attr(vap, &resp->resfail.symlink_attributes);
 930  938  }
 931  939  
 932  940  void *
 933  941  rfs3_readlink_getfh(READLINK3args *args)
 934  942  {
 935  943  
 936  944          return (&args->symlink);
 937  945  }
 938  946  
 939  947  void
 940  948  rfs3_readlink_free(READLINK3res *resp)
 941  949  {
 942  950  
 943  951          if (resp->status == NFS3_OK)
 944  952                  kmem_free(resp->resok.data, MAXPATHLEN + 1);
 945  953  }
 946  954  
 947  955  /*
 948  956   * Server routine to handle read
 949  957   * May handle RDMA data as well as mblks
 950  958   */
 951  959  /* ARGSUSED */
 952  960  void
 953  961  rfs3_read(READ3args *args, READ3res *resp, struct exportinfo *exi,
 954  962      struct svc_req *req, cred_t *cr, bool_t ro)
 955  963  {
 956  964          int error;
 957  965          vnode_t *vp;
 958  966          struct vattr *vap;
 959  967          struct vattr va;
 960  968          struct iovec iov, *iovp = NULL;
 961  969          int iovcnt;
 962  970          struct uio uio;
 963  971          u_offset_t offset;
 964  972          mblk_t *mp = NULL;
 965  973          int in_crit = 0;
 966  974          int need_rwunlock = 0;
 967  975          caller_context_t ct;
 968  976          int rdma_used = 0;
 969  977          int loaned_buffers;
 970  978          struct uio *uiop;
 971  979  
 972  980          vap = NULL;
 973  981  
 974  982          vp = nfs3_fhtovp(&args->file, exi);
 975  983  
 976  984          DTRACE_NFSV3_5(op__read__start, struct svc_req *, req,
 977  985              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 978  986              READ3args *, args);
 979  987  
 980  988  
 981  989          if (vp == NULL) {
 982  990                  error = ESTALE;
 983  991                  goto out;
 984  992          }
 985  993  
 986  994          if (args->wlist) {
 987  995                  if (args->count > clist_len(args->wlist)) {
 988  996                          error = EINVAL;
 989  997                          goto out;
 990  998                  }
 991  999                  rdma_used = 1;
 992 1000          }
 993 1001  
 994 1002          /* use loaned buffers for TCP */
 995 1003          loaned_buffers = (nfs_loaned_buffers && !rdma_used) ? 1 : 0;
 996 1004  
 997 1005          if (is_system_labeled()) {
 998 1006                  bslabel_t *clabel = req->rq_label;
 999 1007  
1000 1008                  ASSERT(clabel != NULL);
1001 1009                  DTRACE_PROBE2(tx__rfs3__log__info__opread__clabel, char *,
1002 1010                      "got client label from request(1)", struct svc_req *, req);
1003 1011  
1004 1012                  if (!blequal(&l_admin_low->tsl_label, clabel)) {
1005 1013                          if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
1006 1014                              exi)) {
1007 1015                                  resp->status = NFS3ERR_ACCES;
1008 1016                                  goto out1;
1009 1017                          }
1010 1018                  }
1011 1019          }
1012 1020  
1013 1021          ct.cc_sysid = 0;
1014 1022          ct.cc_pid = 0;
1015 1023          ct.cc_caller_id = nfs3_srv_caller_id;
1016 1024          ct.cc_flags = CC_DONTBLOCK;
1017 1025  
1018 1026          /*
1019 1027           * Enter the critical region before calling VOP_RWLOCK
1020 1028           * to avoid a deadlock with write requests.
1021 1029           */
1022 1030          if (nbl_need_check(vp)) {
1023 1031                  nbl_start_crit(vp, RW_READER);
1024 1032                  in_crit = 1;
1025 1033                  if (nbl_conflict(vp, NBL_READ, args->offset, args->count, 0,
1026 1034                      NULL)) {
1027 1035                          error = EACCES;
1028 1036                          goto out;
1029 1037                  }
1030 1038          }
1031 1039  
1032 1040          error = VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &ct);
1033 1041  
1034 1042          /* check if a monitor detected a delegation conflict */
1035 1043          if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
1036 1044                  resp->status = NFS3ERR_JUKEBOX;
1037 1045                  goto out1;
1038 1046          }
1039 1047  
1040 1048          need_rwunlock = 1;
1041 1049  
1042 1050          va.va_mask = AT_ALL;
1043 1051          error = VOP_GETATTR(vp, &va, 0, cr, &ct);
1044 1052  
1045 1053          /*
1046 1054           * If we can't get the attributes, then we can't do the
1047 1055           * right access checking.  So, we'll fail the request.
1048 1056           */
1049 1057          if (error)
1050 1058                  goto out;
1051 1059  
1052 1060          vap = &va;
1053 1061  
1054 1062          if (vp->v_type != VREG) {
1055 1063                  resp->status = NFS3ERR_INVAL;
1056 1064                  goto out1;
1057 1065          }
1058 1066  
1059 1067          if (crgetuid(cr) != va.va_uid) {
1060 1068                  error = VOP_ACCESS(vp, VREAD, 0, cr, &ct);
1061 1069                  if (error) {
1062 1070                          if (curthread->t_flag & T_WOULDBLOCK)
1063 1071                                  goto out;
1064 1072                          error = VOP_ACCESS(vp, VEXEC, 0, cr, &ct);
1065 1073                          if (error)
1066 1074                                  goto out;
1067 1075                  }
1068 1076          }
1069 1077  
1070 1078          if (MANDLOCK(vp, va.va_mode)) {
1071 1079                  resp->status = NFS3ERR_ACCES;
1072 1080                  goto out1;
1073 1081          }
1074 1082  
1075 1083          offset = args->offset;
1076 1084          if (offset >= va.va_size) {
1077 1085                  VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
1078 1086                  if (in_crit)
1079 1087                          nbl_end_crit(vp);
1080 1088                  resp->status = NFS3_OK;
1081 1089                  vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
1082 1090                  resp->resok.count = 0;
1083 1091                  resp->resok.eof = TRUE;
1084 1092                  resp->resok.data.data_len = 0;
1085 1093                  resp->resok.data.data_val = NULL;
1086 1094                  resp->resok.data.mp = NULL;
1087 1095                  /* RDMA */
1088 1096                  resp->resok.wlist = args->wlist;
1089 1097                  resp->resok.wlist_len = resp->resok.count;
1090 1098                  if (resp->resok.wlist)
1091 1099                          clist_zero_len(resp->resok.wlist);
1092 1100                  goto done;
1093 1101          }
1094 1102  
1095 1103          if (args->count == 0) {
1096 1104                  VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
1097 1105                  if (in_crit)
1098 1106                          nbl_end_crit(vp);
1099 1107                  resp->status = NFS3_OK;
1100 1108                  vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
1101 1109                  resp->resok.count = 0;
1102 1110                  resp->resok.eof = FALSE;
1103 1111                  resp->resok.data.data_len = 0;
1104 1112                  resp->resok.data.data_val = NULL;
1105 1113                  resp->resok.data.mp = NULL;
1106 1114                  /* RDMA */
1107 1115                  resp->resok.wlist = args->wlist;
1108 1116                  resp->resok.wlist_len = resp->resok.count;
1109 1117                  if (resp->resok.wlist)
1110 1118                          clist_zero_len(resp->resok.wlist);
1111 1119                  goto done;
1112 1120          }
1113 1121  
1114 1122          /*
1115 1123           * do not allocate memory more the max. allowed
1116 1124           * transfer size
1117 1125           */
1118 1126          if (args->count > rfs3_tsize(req))
1119 1127                  args->count = rfs3_tsize(req);
1120 1128  
1121 1129          if (loaned_buffers) {
1122 1130                  uiop = (uio_t *)rfs_setup_xuio(vp);
1123 1131                  ASSERT(uiop != NULL);
1124 1132                  uiop->uio_segflg = UIO_SYSSPACE;
1125 1133                  uiop->uio_loffset = args->offset;
1126 1134                  uiop->uio_resid = args->count;
1127 1135  
1128 1136                  /* Jump to do the read if successful */
1129 1137                  if (VOP_REQZCBUF(vp, UIO_READ, (xuio_t *)uiop, cr, &ct) == 0) {
1130 1138                          /*
1131 1139                           * Need to hold the vnode until after VOP_RETZCBUF()
1132 1140                           * is called.
1133 1141                           */
1134 1142                          VN_HOLD(vp);
1135 1143                          goto doio_read;
1136 1144                  }
1137 1145  
1138 1146                  DTRACE_PROBE2(nfss__i__reqzcbuf_failed, int,
1139 1147                      uiop->uio_loffset, int, uiop->uio_resid);
1140 1148  
1141 1149                  uiop->uio_extflg = 0;
1142 1150                  /* failure to setup for zero copy */
1143 1151                  rfs_free_xuio((void *)uiop);
1144 1152                  loaned_buffers = 0;
1145 1153          }
1146 1154  
1147 1155          /*
1148 1156           * If returning data via RDMA Write, then grab the chunk list.
1149 1157           * If we aren't returning READ data w/RDMA_WRITE, then grab
1150 1158           * a mblk.
1151 1159           */
1152 1160          if (rdma_used) {
1153 1161                  (void) rdma_get_wchunk(req, &iov, args->wlist);
1154 1162                  uio.uio_iov = &iov;
1155 1163                  uio.uio_iovcnt = 1;
1156 1164          } else {
1157 1165                  /*
1158 1166                   * mp will contain the data to be sent out in the read reply.
1159 1167                   * For UDP, this will be freed after the reply has been sent
1160 1168                   * out by the driver.  For TCP, it will be freed after the last
1161 1169                   * segment associated with the reply has been ACKed by the
1162 1170                   * client.
1163 1171                   */
1164 1172                  mp = rfs_read_alloc(args->count, &iovp, &iovcnt);
1165 1173                  uio.uio_iov = iovp;
1166 1174                  uio.uio_iovcnt = iovcnt;
1167 1175          }
1168 1176  
1169 1177          uio.uio_segflg = UIO_SYSSPACE;
1170 1178          uio.uio_extflg = UIO_COPY_CACHED;
1171 1179          uio.uio_loffset = args->offset;
1172 1180          uio.uio_resid = args->count;
1173 1181          uiop = &uio;
1174 1182  
1175 1183  doio_read:
1176 1184          error = VOP_READ(vp, uiop, 0, cr, &ct);
1177 1185  
1178 1186          if (error) {
1179 1187                  if (mp)
1180 1188                          freemsg(mp);
1181 1189                  /* check if a monitor detected a delegation conflict */
1182 1190                  if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
1183 1191                          resp->status = NFS3ERR_JUKEBOX;
1184 1192                          goto out1;
1185 1193                  }
1186 1194                  goto out;
1187 1195          }
1188 1196  
1189 1197          /* make mblk using zc buffers */
1190 1198          if (loaned_buffers) {
1191 1199                  mp = uio_to_mblk(uiop);
1192 1200                  ASSERT(mp != NULL);
1193 1201          }
1194 1202  
1195 1203          va.va_mask = AT_ALL;
1196 1204          error = VOP_GETATTR(vp, &va, 0, cr, &ct);
1197 1205  
1198 1206          if (error)
1199 1207                  vap = NULL;
1200 1208          else
1201 1209                  vap = &va;
1202 1210  
1203 1211          VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
1204 1212  
1205 1213          if (in_crit)
1206 1214                  nbl_end_crit(vp);
1207 1215  
1208 1216          resp->status = NFS3_OK;
1209 1217          vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
1210 1218          resp->resok.count = args->count - uiop->uio_resid;
1211 1219          if (!error && offset + resp->resok.count == va.va_size)
1212 1220                  resp->resok.eof = TRUE;
1213 1221          else
1214 1222                  resp->resok.eof = FALSE;
1215 1223          resp->resok.data.data_len = resp->resok.count;
1216 1224  
1217 1225          if (mp)
1218 1226                  rfs_rndup_mblks(mp, resp->resok.count, loaned_buffers);
1219 1227  
1220 1228          resp->resok.data.mp = mp;
1221 1229          resp->resok.size = (uint_t)args->count;
1222 1230  
1223 1231          if (rdma_used) {
1224 1232                  resp->resok.data.data_val = (caddr_t)iov.iov_base;
1225 1233                  if (!rdma_setup_read_data3(args, &(resp->resok))) {
1226 1234                          resp->status = NFS3ERR_INVAL;
1227 1235                  }
1228 1236          } else {
1229 1237                  resp->resok.data.data_val = (caddr_t)mp->b_datap->db_base;
1230 1238                  (resp->resok).wlist = NULL;
1231 1239          }
1232 1240  
1233 1241  done:
1234 1242          DTRACE_NFSV3_5(op__read__done, struct svc_req *, req,
1235 1243              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
1236 1244              READ3res *, resp);
1237 1245  
1238 1246          VN_RELE(vp);
1239 1247  
1240 1248          if (iovp != NULL)
1241 1249                  kmem_free(iovp, iovcnt * sizeof (struct iovec));
1242 1250  
1243 1251          return;
1244 1252  
1245 1253  out:
1246 1254          if (curthread->t_flag & T_WOULDBLOCK) {
1247 1255                  curthread->t_flag &= ~T_WOULDBLOCK;
1248 1256                  resp->status = NFS3ERR_JUKEBOX;
1249 1257          } else
1250 1258                  resp->status = puterrno3(error);
1251 1259  out1:
1252 1260          DTRACE_NFSV3_5(op__read__done, struct svc_req *, req,
1253 1261              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
1254 1262              READ3res *, resp);
1255 1263  
1256 1264          if (vp != NULL) {
1257 1265                  if (need_rwunlock)
1258 1266                          VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
1259 1267                  if (in_crit)
1260 1268                          nbl_end_crit(vp);
1261 1269                  VN_RELE(vp);
1262 1270          }
1263 1271          vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
1264 1272  
1265 1273          if (iovp != NULL)
1266 1274                  kmem_free(iovp, iovcnt * sizeof (struct iovec));
1267 1275  }
1268 1276  
1269 1277  void
1270 1278  rfs3_read_free(READ3res *resp)
1271 1279  {
1272 1280          mblk_t *mp;
1273 1281  
1274 1282          if (resp->status == NFS3_OK) {
1275 1283                  mp = resp->resok.data.mp;
1276 1284                  if (mp != NULL)
1277 1285                          freemsg(mp);
1278 1286          }
1279 1287  }
1280 1288  
1281 1289  void *
1282 1290  rfs3_read_getfh(READ3args *args)
1283 1291  {
1284 1292  
1285 1293          return (&args->file);
1286 1294  }
1287 1295  
1288 1296  #define MAX_IOVECS      12
1289 1297  
1290 1298  #ifdef DEBUG
1291 1299  static int rfs3_write_hits = 0;
1292 1300  static int rfs3_write_misses = 0;
1293 1301  #endif
1294 1302  
1295 1303  void
1296 1304  rfs3_write(WRITE3args *args, WRITE3res *resp, struct exportinfo *exi,
1297 1305      struct svc_req *req, cred_t *cr, bool_t ro)
1298 1306  {
1299 1307          nfs3_srv_t *ns;
1300 1308          int error;
1301 1309          vnode_t *vp;
1302 1310          struct vattr *bvap = NULL;
1303 1311          struct vattr bva;
1304 1312          struct vattr *avap = NULL;
1305 1313          struct vattr ava;
1306 1314          u_offset_t rlimit;
1307 1315          struct uio uio;
1308 1316          struct iovec iov[MAX_IOVECS];
1309 1317          mblk_t *m;
1310 1318          struct iovec *iovp;
1311 1319          int iovcnt;
1312 1320          int ioflag;
1313 1321          cred_t *savecred;
1314 1322          int in_crit = 0;
1315 1323          int rwlock_ret = -1;
1316 1324          caller_context_t ct;
1317 1325  
1318 1326          vp = nfs3_fhtovp(&args->file, exi);
1319 1327  
  
    | 
      ↓ open down ↓ | 
    1214 lines elided | 
    
      ↑ open up ↑ | 
  
1320 1328          DTRACE_NFSV3_5(op__write__start, struct svc_req *, req,
1321 1329              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
1322 1330              WRITE3args *, args);
1323 1331  
1324 1332          if (vp == NULL) {
1325 1333                  error = ESTALE;
1326 1334                  goto err;
1327 1335          }
1328 1336  
1329 1337          ASSERT3P(curzone, ==, exi->exi_zone); /* exi is guaranteed non-NULL. */
1330      -        ns = zone_getspecific(rfs3_zone_key, curzone);
     1338 +        ns = nfs3_get_srv();
     1339 +
1331 1340          if (is_system_labeled()) {
1332 1341                  bslabel_t *clabel = req->rq_label;
1333 1342  
1334 1343                  ASSERT(clabel != NULL);
1335 1344                  DTRACE_PROBE2(tx__rfs3__log__info__opwrite__clabel, char *,
1336 1345                      "got client label from request(1)", struct svc_req *, req);
1337 1346  
1338 1347                  if (!blequal(&l_admin_low->tsl_label, clabel)) {
1339 1348                          if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
1340 1349                              exi)) {
1341 1350                                  resp->status = NFS3ERR_ACCES;
1342 1351                                  goto err1;
1343 1352                          }
1344 1353                  }
1345 1354          }
1346 1355  
1347 1356          ct.cc_sysid = 0;
1348 1357          ct.cc_pid = 0;
1349 1358          ct.cc_caller_id = nfs3_srv_caller_id;
1350 1359          ct.cc_flags = CC_DONTBLOCK;
1351 1360  
1352 1361          /*
1353 1362           * We have to enter the critical region before calling VOP_RWLOCK
1354 1363           * to avoid a deadlock with ufs.
1355 1364           */
1356 1365          if (nbl_need_check(vp)) {
1357 1366                  nbl_start_crit(vp, RW_READER);
1358 1367                  in_crit = 1;
1359 1368                  if (nbl_conflict(vp, NBL_WRITE, args->offset, args->count, 0,
1360 1369                      NULL)) {
1361 1370                          error = EACCES;
1362 1371                          goto err;
1363 1372                  }
1364 1373          }
1365 1374  
1366 1375          rwlock_ret = VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &ct);
1367 1376  
1368 1377          /* check if a monitor detected a delegation conflict */
1369 1378          if (rwlock_ret == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
1370 1379                  resp->status = NFS3ERR_JUKEBOX;
1371 1380                  rwlock_ret = -1;
1372 1381                  goto err1;
1373 1382          }
1374 1383  
1375 1384  
1376 1385          bva.va_mask = AT_ALL;
1377 1386          error = VOP_GETATTR(vp, &bva, 0, cr, &ct);
1378 1387  
1379 1388          /*
1380 1389           * If we can't get the attributes, then we can't do the
1381 1390           * right access checking.  So, we'll fail the request.
1382 1391           */
1383 1392          if (error)
1384 1393                  goto err;
1385 1394  
1386 1395          bvap = &bva;
1387 1396          avap = bvap;
1388 1397  
1389 1398          if (args->count != args->data.data_len) {
1390 1399                  resp->status = NFS3ERR_INVAL;
1391 1400                  goto err1;
1392 1401          }
1393 1402  
1394 1403          if (rdonly(ro, vp)) {
1395 1404                  resp->status = NFS3ERR_ROFS;
1396 1405                  goto err1;
1397 1406          }
1398 1407  
1399 1408          if (vp->v_type != VREG) {
1400 1409                  resp->status = NFS3ERR_INVAL;
1401 1410                  goto err1;
1402 1411          }
1403 1412  
1404 1413          if (crgetuid(cr) != bva.va_uid &&
1405 1414              (error = VOP_ACCESS(vp, VWRITE, 0, cr, &ct)))
1406 1415                  goto err;
1407 1416  
1408 1417          if (MANDLOCK(vp, bva.va_mode)) {
1409 1418                  resp->status = NFS3ERR_ACCES;
1410 1419                  goto err1;
1411 1420          }
1412 1421  
1413 1422          if (args->count == 0) {
1414 1423                  resp->status = NFS3_OK;
1415 1424                  vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
1416 1425                  resp->resok.count = 0;
1417 1426                  resp->resok.committed = args->stable;
1418 1427                  resp->resok.verf = ns->write3verf;
1419 1428                  goto out;
1420 1429          }
1421 1430  
1422 1431          if (args->mblk != NULL) {
1423 1432                  iovcnt = 0;
1424 1433                  for (m = args->mblk; m != NULL; m = m->b_cont)
1425 1434                          iovcnt++;
1426 1435                  if (iovcnt <= MAX_IOVECS) {
1427 1436  #ifdef DEBUG
1428 1437                          rfs3_write_hits++;
1429 1438  #endif
1430 1439                          iovp = iov;
1431 1440                  } else {
1432 1441  #ifdef DEBUG
1433 1442                          rfs3_write_misses++;
1434 1443  #endif
1435 1444                          iovp = kmem_alloc(sizeof (*iovp) * iovcnt, KM_SLEEP);
1436 1445                  }
1437 1446                  mblk_to_iov(args->mblk, iovcnt, iovp);
1438 1447  
1439 1448          } else if (args->rlist != NULL) {
1440 1449                  iovcnt = 1;
1441 1450                  iovp = iov;
1442 1451                  iovp->iov_base = (char *)((args->rlist)->u.c_daddr3);
1443 1452                  iovp->iov_len = args->count;
1444 1453          } else {
1445 1454                  iovcnt = 1;
1446 1455                  iovp = iov;
1447 1456                  iovp->iov_base = args->data.data_val;
1448 1457                  iovp->iov_len = args->count;
1449 1458          }
1450 1459  
1451 1460          uio.uio_iov = iovp;
1452 1461          uio.uio_iovcnt = iovcnt;
1453 1462  
1454 1463          uio.uio_segflg = UIO_SYSSPACE;
1455 1464          uio.uio_extflg = UIO_COPY_DEFAULT;
1456 1465          uio.uio_loffset = args->offset;
1457 1466          uio.uio_resid = args->count;
1458 1467          uio.uio_llimit = curproc->p_fsz_ctl;
1459 1468          rlimit = uio.uio_llimit - args->offset;
1460 1469          if (rlimit < (u_offset_t)uio.uio_resid)
1461 1470                  uio.uio_resid = (int)rlimit;
1462 1471  
1463 1472          if (args->stable == UNSTABLE)
1464 1473                  ioflag = 0;
1465 1474          else if (args->stable == FILE_SYNC)
1466 1475                  ioflag = FSYNC;
1467 1476          else if (args->stable == DATA_SYNC)
1468 1477                  ioflag = FDSYNC;
1469 1478          else {
1470 1479                  if (iovp != iov)
1471 1480                          kmem_free(iovp, sizeof (*iovp) * iovcnt);
1472 1481                  resp->status = NFS3ERR_INVAL;
1473 1482                  goto err1;
1474 1483          }
1475 1484  
1476 1485          /*
1477 1486           * We're changing creds because VM may fault and we need
1478 1487           * the cred of the current thread to be used if quota
1479 1488           * checking is enabled.
1480 1489           */
1481 1490          savecred = curthread->t_cred;
1482 1491          curthread->t_cred = cr;
1483 1492          error = VOP_WRITE(vp, &uio, ioflag, cr, &ct);
1484 1493          curthread->t_cred = savecred;
1485 1494  
1486 1495          if (iovp != iov)
1487 1496                  kmem_free(iovp, sizeof (*iovp) * iovcnt);
1488 1497  
1489 1498          /* check if a monitor detected a delegation conflict */
1490 1499          if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK)) {
1491 1500                  resp->status = NFS3ERR_JUKEBOX;
1492 1501                  goto err1;
1493 1502          }
1494 1503  
1495 1504          ava.va_mask = AT_ALL;
1496 1505          avap = VOP_GETATTR(vp, &ava, 0, cr, &ct) ? NULL : &ava;
1497 1506  
1498 1507          if (error)
1499 1508                  goto err;
1500 1509  
1501 1510          /*
1502 1511           * If we were unable to get the V_WRITELOCK_TRUE, then we
1503 1512           * may not have accurate after attrs, so check if
1504 1513           * we have both attributes, they have a non-zero va_seq, and
1505 1514           * va_seq has changed by exactly one,
1506 1515           * if not, turn off the before attr.
1507 1516           */
1508 1517          if (rwlock_ret != V_WRITELOCK_TRUE) {
1509 1518                  if (bvap == NULL || avap == NULL ||
1510 1519                      bvap->va_seq == 0 || avap->va_seq == 0 ||
1511 1520                      avap->va_seq != (bvap->va_seq + 1)) {
1512 1521                          bvap = NULL;
1513 1522                  }
1514 1523          }
1515 1524  
1516 1525          resp->status = NFS3_OK;
1517 1526          vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
1518 1527          resp->resok.count = args->count - uio.uio_resid;
1519 1528          resp->resok.committed = args->stable;
1520 1529          resp->resok.verf = ns->write3verf;
1521 1530          goto out;
1522 1531  
1523 1532  err:
1524 1533          if (curthread->t_flag & T_WOULDBLOCK) {
1525 1534                  curthread->t_flag &= ~T_WOULDBLOCK;
1526 1535                  resp->status = NFS3ERR_JUKEBOX;
1527 1536          } else
1528 1537                  resp->status = puterrno3(error);
1529 1538  err1:
1530 1539          vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
1531 1540  out:
1532 1541          DTRACE_NFSV3_5(op__write__done, struct svc_req *, req,
1533 1542              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
1534 1543              WRITE3res *, resp);
1535 1544  
1536 1545          if (vp != NULL) {
1537 1546                  if (rwlock_ret != -1)
1538 1547                          VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &ct);
1539 1548                  if (in_crit)
1540 1549                          nbl_end_crit(vp);
1541 1550                  VN_RELE(vp);
1542 1551          }
1543 1552  }
1544 1553  
1545 1554  void *
1546 1555  rfs3_write_getfh(WRITE3args *args)
1547 1556  {
1548 1557  
1549 1558          return (&args->file);
1550 1559  }
1551 1560  
1552 1561  void
1553 1562  rfs3_create(CREATE3args *args, CREATE3res *resp, struct exportinfo *exi,
1554 1563      struct svc_req *req, cred_t *cr, bool_t ro)
1555 1564  {
1556 1565          int error;
1557 1566          int in_crit = 0;
1558 1567          vnode_t *vp;
1559 1568          vnode_t *tvp = NULL;
1560 1569          vnode_t *dvp;
1561 1570          struct vattr *vap;
1562 1571          struct vattr va;
1563 1572          struct vattr *dbvap;
1564 1573          struct vattr dbva;
1565 1574          struct vattr *davap;
1566 1575          struct vattr dava;
1567 1576          enum vcexcl excl;
1568 1577          nfstime3 *mtime;
1569 1578          len_t reqsize;
1570 1579          bool_t trunc;
1571 1580          struct sockaddr *ca;
1572 1581          char *name = NULL;
1573 1582  
1574 1583          dbvap = NULL;
1575 1584          davap = NULL;
1576 1585  
1577 1586          dvp = nfs3_fhtovp(&args->where.dir, exi);
1578 1587  
1579 1588          DTRACE_NFSV3_5(op__create__start, struct svc_req *, req,
1580 1589              cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
1581 1590              CREATE3args *, args);
1582 1591  
1583 1592          if (dvp == NULL) {
1584 1593                  error = ESTALE;
1585 1594                  goto out;
1586 1595          }
1587 1596  
1588 1597          dbva.va_mask = AT_ALL;
1589 1598          dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1590 1599          davap = dbvap;
1591 1600  
1592 1601          if (args->where.name == nfs3nametoolong) {
1593 1602                  resp->status = NFS3ERR_NAMETOOLONG;
1594 1603                  goto out1;
1595 1604          }
1596 1605  
1597 1606          if (args->where.name == NULL || *(args->where.name) == '\0') {
1598 1607                  resp->status = NFS3ERR_ACCES;
1599 1608                  goto out1;
1600 1609          }
1601 1610  
1602 1611          if (rdonly(ro, dvp)) {
1603 1612                  resp->status = NFS3ERR_ROFS;
1604 1613                  goto out1;
1605 1614          }
1606 1615  
1607 1616          if (is_system_labeled()) {
1608 1617                  bslabel_t *clabel = req->rq_label;
1609 1618  
1610 1619                  ASSERT(clabel != NULL);
1611 1620                  DTRACE_PROBE2(tx__rfs3__log__info__opcreate__clabel, char *,
1612 1621                      "got client label from request(1)", struct svc_req *, req);
1613 1622  
1614 1623                  if (!blequal(&l_admin_low->tsl_label, clabel)) {
1615 1624                          if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
1616 1625                              exi)) {
1617 1626                                  resp->status = NFS3ERR_ACCES;
1618 1627                                  goto out1;
1619 1628                          }
1620 1629                  }
1621 1630          }
1622 1631  
1623 1632          ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
1624 1633          name = nfscmd_convname(ca, exi, args->where.name,
1625 1634              NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
1626 1635  
1627 1636          if (name == NULL) {
1628 1637                  /* This is really a Solaris EILSEQ */
1629 1638                  resp->status = NFS3ERR_INVAL;
1630 1639                  goto out1;
1631 1640          }
1632 1641  
1633 1642          if (args->how.mode == EXCLUSIVE) {
1634 1643                  va.va_mask = AT_TYPE | AT_MODE | AT_MTIME;
1635 1644                  va.va_type = VREG;
1636 1645                  va.va_mode = (mode_t)0;
1637 1646                  /*
1638 1647                   * Ensure no time overflows and that types match
1639 1648                   */
1640 1649                  mtime = (nfstime3 *)&args->how.createhow3_u.verf;
1641 1650                  va.va_mtime.tv_sec = mtime->seconds % INT32_MAX;
1642 1651                  va.va_mtime.tv_nsec = mtime->nseconds;
1643 1652                  excl = EXCL;
1644 1653          } else {
1645 1654                  error = sattr3_to_vattr(&args->how.createhow3_u.obj_attributes,
1646 1655                      &va);
1647 1656                  if (error)
1648 1657                          goto out;
1649 1658                  va.va_mask |= AT_TYPE;
1650 1659                  va.va_type = VREG;
1651 1660                  if (args->how.mode == GUARDED)
1652 1661                          excl = EXCL;
1653 1662                  else {
1654 1663                          excl = NONEXCL;
1655 1664  
1656 1665                          /*
1657 1666                           * During creation of file in non-exclusive mode
1658 1667                           * if size of file is being set then make sure
1659 1668                           * that if the file already exists that no conflicting
1660 1669                           * non-blocking mandatory locks exists in the region
1661 1670                           * being modified. If there are conflicting locks fail
1662 1671                           * the operation with EACCES.
1663 1672                           */
1664 1673                          if (va.va_mask & AT_SIZE) {
1665 1674                                  struct vattr tva;
1666 1675  
1667 1676                                  /*
1668 1677                                   * Does file already exist?
1669 1678                                   */
1670 1679                                  error = VOP_LOOKUP(dvp, name, &tvp,
1671 1680                                      NULL, 0, NULL, cr, NULL, NULL, NULL);
1672 1681  
1673 1682                                  /*
1674 1683                                   * Check to see if the file has been delegated
1675 1684                                   * to a v4 client.  If so, then begin recall of
1676 1685                                   * the delegation and return JUKEBOX to allow
1677 1686                                   * the client to retrasmit its request.
1678 1687                                   */
1679 1688  
1680 1689                                  trunc = va.va_size == 0;
1681 1690                                  if (!error &&
1682 1691                                      rfs4_check_delegated(FWRITE, tvp, trunc)) {
1683 1692                                          resp->status = NFS3ERR_JUKEBOX;
1684 1693                                          goto out1;
1685 1694                                  }
1686 1695  
1687 1696                                  /*
1688 1697                                   * Check for NBMAND lock conflicts
1689 1698                                   */
1690 1699                                  if (!error && nbl_need_check(tvp)) {
1691 1700                                          u_offset_t offset;
1692 1701                                          ssize_t len;
1693 1702  
1694 1703                                          nbl_start_crit(tvp, RW_READER);
1695 1704                                          in_crit = 1;
1696 1705  
1697 1706                                          tva.va_mask = AT_SIZE;
1698 1707                                          error = VOP_GETATTR(tvp, &tva, 0, cr,
1699 1708                                              NULL);
1700 1709                                          /*
1701 1710                                           * Can't check for conflicts, so return
1702 1711                                           * error.
1703 1712                                           */
1704 1713                                          if (error)
1705 1714                                                  goto out;
1706 1715  
1707 1716                                          offset = tva.va_size < va.va_size ?
1708 1717                                              tva.va_size : va.va_size;
1709 1718                                          len = tva.va_size < va.va_size ?
1710 1719                                              va.va_size - tva.va_size :
1711 1720                                              tva.va_size - va.va_size;
1712 1721                                          if (nbl_conflict(tvp, NBL_WRITE,
1713 1722                                              offset, len, 0, NULL)) {
1714 1723                                                  error = EACCES;
1715 1724                                                  goto out;
1716 1725                                          }
1717 1726                                  } else if (tvp) {
1718 1727                                          VN_RELE(tvp);
1719 1728                                          tvp = NULL;
1720 1729                                  }
1721 1730                          }
1722 1731                  }
1723 1732                  if (va.va_mask & AT_SIZE)
1724 1733                          reqsize = va.va_size;
1725 1734          }
1726 1735  
1727 1736          /*
1728 1737           * Must specify the mode.
1729 1738           */
1730 1739          if (!(va.va_mask & AT_MODE)) {
1731 1740                  resp->status = NFS3ERR_INVAL;
1732 1741                  goto out1;
1733 1742          }
1734 1743  
1735 1744          /*
1736 1745           * If the filesystem is exported with nosuid, then mask off
1737 1746           * the setuid and setgid bits.
1738 1747           */
1739 1748          if (va.va_type == VREG && (exi->exi_export.ex_flags & EX_NOSUID))
1740 1749                  va.va_mode &= ~(VSUID | VSGID);
1741 1750  
1742 1751  tryagain:
1743 1752          /*
1744 1753           * The file open mode used is VWRITE.  If the client needs
1745 1754           * some other semantic, then it should do the access checking
1746 1755           * itself.  It would have been nice to have the file open mode
1747 1756           * passed as part of the arguments.
1748 1757           */
1749 1758          error = VOP_CREATE(dvp, name, &va, excl, VWRITE,
1750 1759              &vp, cr, 0, NULL, NULL);
1751 1760  
1752 1761          dava.va_mask = AT_ALL;
1753 1762          davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
1754 1763  
1755 1764          if (error) {
1756 1765                  /*
1757 1766                   * If we got something other than file already exists
1758 1767                   * then just return this error.  Otherwise, we got
1759 1768                   * EEXIST.  If we were doing a GUARDED create, then
1760 1769                   * just return this error.  Otherwise, we need to
1761 1770                   * make sure that this wasn't a duplicate of an
1762 1771                   * exclusive create request.
1763 1772                   *
1764 1773                   * The assumption is made that a non-exclusive create
1765 1774                   * request will never return EEXIST.
1766 1775                   */
1767 1776                  if (error != EEXIST || args->how.mode == GUARDED)
1768 1777                          goto out;
1769 1778                  /*
1770 1779                   * Lookup the file so that we can get a vnode for it.
1771 1780                   */
1772 1781                  error = VOP_LOOKUP(dvp, name, &vp, NULL, 0,
1773 1782                      NULL, cr, NULL, NULL, NULL);
1774 1783                  if (error) {
1775 1784                          /*
1776 1785                           * We couldn't find the file that we thought that
1777 1786                           * we just created.  So, we'll just try creating
1778 1787                           * it again.
1779 1788                           */
1780 1789                          if (error == ENOENT)
1781 1790                                  goto tryagain;
1782 1791                          goto out;
1783 1792                  }
1784 1793  
1785 1794                  /*
1786 1795                   * If the file is delegated to a v4 client, go ahead
1787 1796                   * and initiate recall, this create is a hint that a
1788 1797                   * conflicting v3 open has occurred.
1789 1798                   */
1790 1799  
1791 1800                  if (rfs4_check_delegated(FWRITE, vp, FALSE)) {
1792 1801                          VN_RELE(vp);
1793 1802                          resp->status = NFS3ERR_JUKEBOX;
1794 1803                          goto out1;
1795 1804                  }
1796 1805  
1797 1806                  va.va_mask = AT_ALL;
1798 1807                  vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
1799 1808  
1800 1809                  mtime = (nfstime3 *)&args->how.createhow3_u.verf;
1801 1810                  /* % with INT32_MAX to prevent overflows */
1802 1811                  if (args->how.mode == EXCLUSIVE && (vap == NULL ||
1803 1812                      vap->va_mtime.tv_sec !=
1804 1813                      (mtime->seconds % INT32_MAX) ||
1805 1814                      vap->va_mtime.tv_nsec != mtime->nseconds)) {
1806 1815                          VN_RELE(vp);
1807 1816                          error = EEXIST;
1808 1817                          goto out;
1809 1818                  }
1810 1819          } else {
1811 1820  
1812 1821                  if ((args->how.mode == UNCHECKED ||
1813 1822                      args->how.mode == GUARDED) &&
1814 1823                      args->how.createhow3_u.obj_attributes.size.set_it &&
1815 1824                      va.va_size == 0)
1816 1825                          trunc = TRUE;
1817 1826                  else
1818 1827                          trunc = FALSE;
1819 1828  
1820 1829                  if (rfs4_check_delegated(FWRITE, vp, trunc)) {
1821 1830                          VN_RELE(vp);
1822 1831                          resp->status = NFS3ERR_JUKEBOX;
1823 1832                          goto out1;
1824 1833                  }
1825 1834  
1826 1835                  va.va_mask = AT_ALL;
1827 1836                  vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
1828 1837  
1829 1838                  /*
1830 1839                   * We need to check to make sure that the file got
1831 1840                   * created to the indicated size.  If not, we do a
1832 1841                   * setattr to try to change the size, but we don't
1833 1842                   * try too hard.  This shouldn't a problem as most
1834 1843                   * clients will only specifiy a size of zero which
1835 1844                   * local file systems handle.  However, even if
1836 1845                   * the client does specify a non-zero size, it can
1837 1846                   * still recover by checking the size of the file
1838 1847                   * after it has created it and then issue a setattr
1839 1848                   * request of its own to set the size of the file.
1840 1849                   */
1841 1850                  if (vap != NULL &&
1842 1851                      (args->how.mode == UNCHECKED ||
1843 1852                      args->how.mode == GUARDED) &&
1844 1853                      args->how.createhow3_u.obj_attributes.size.set_it &&
1845 1854                      vap->va_size != reqsize) {
1846 1855                          va.va_mask = AT_SIZE;
1847 1856                          va.va_size = reqsize;
1848 1857                          (void) VOP_SETATTR(vp, &va, 0, cr, NULL);
1849 1858                          va.va_mask = AT_ALL;
1850 1859                          vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
1851 1860                  }
1852 1861          }
1853 1862  
1854 1863          if (name != args->where.name)
1855 1864                  kmem_free(name, MAXPATHLEN + 1);
1856 1865  
1857 1866          error = makefh3(&resp->resok.obj.handle, vp, exi);
1858 1867          if (error)
1859 1868                  resp->resok.obj.handle_follows = FALSE;
1860 1869          else
1861 1870                  resp->resok.obj.handle_follows = TRUE;
1862 1871  
1863 1872          /*
1864 1873           * Force modified data and metadata out to stable storage.
1865 1874           */
1866 1875          (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
1867 1876          (void) VOP_FSYNC(dvp, 0, cr, NULL);
1868 1877  
1869 1878          VN_RELE(vp);
1870 1879          if (tvp != NULL) {
1871 1880                  if (in_crit)
1872 1881                          nbl_end_crit(tvp);
1873 1882                  VN_RELE(tvp);
1874 1883          }
1875 1884  
1876 1885          resp->status = NFS3_OK;
1877 1886          vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
1878 1887          vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
1879 1888  
1880 1889          DTRACE_NFSV3_5(op__create__done, struct svc_req *, req,
1881 1890              cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
1882 1891              CREATE3res *, resp);
1883 1892  
1884 1893          VN_RELE(dvp);
1885 1894          return;
1886 1895  
1887 1896  out:
1888 1897          if (curthread->t_flag & T_WOULDBLOCK) {
1889 1898                  curthread->t_flag &= ~T_WOULDBLOCK;
1890 1899                  resp->status = NFS3ERR_JUKEBOX;
1891 1900          } else
1892 1901                  resp->status = puterrno3(error);
1893 1902  out1:
1894 1903          DTRACE_NFSV3_5(op__create__done, struct svc_req *, req,
1895 1904              cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
1896 1905              CREATE3res *, resp);
1897 1906  
1898 1907          if (name != NULL && name != args->where.name)
1899 1908                  kmem_free(name, MAXPATHLEN + 1);
1900 1909  
1901 1910          if (tvp != NULL) {
1902 1911                  if (in_crit)
1903 1912                          nbl_end_crit(tvp);
1904 1913                  VN_RELE(tvp);
1905 1914          }
1906 1915          if (dvp != NULL)
1907 1916                  VN_RELE(dvp);
1908 1917          vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
1909 1918  }
1910 1919  
1911 1920  void *
1912 1921  rfs3_create_getfh(CREATE3args *args)
1913 1922  {
1914 1923  
1915 1924          return (&args->where.dir);
1916 1925  }
1917 1926  
1918 1927  void
1919 1928  rfs3_mkdir(MKDIR3args *args, MKDIR3res *resp, struct exportinfo *exi,
1920 1929      struct svc_req *req, cred_t *cr, bool_t ro)
1921 1930  {
1922 1931          int error;
1923 1932          vnode_t *vp = NULL;
1924 1933          vnode_t *dvp;
1925 1934          struct vattr *vap;
1926 1935          struct vattr va;
1927 1936          struct vattr *dbvap;
1928 1937          struct vattr dbva;
1929 1938          struct vattr *davap;
1930 1939          struct vattr dava;
1931 1940          struct sockaddr *ca;
1932 1941          char *name = NULL;
1933 1942  
1934 1943          dbvap = NULL;
1935 1944          davap = NULL;
1936 1945  
1937 1946          dvp = nfs3_fhtovp(&args->where.dir, exi);
1938 1947  
1939 1948          DTRACE_NFSV3_5(op__mkdir__start, struct svc_req *, req,
1940 1949              cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
1941 1950              MKDIR3args *, args);
1942 1951  
1943 1952          if (dvp == NULL) {
1944 1953                  error = ESTALE;
1945 1954                  goto out;
1946 1955          }
1947 1956  
1948 1957          dbva.va_mask = AT_ALL;
1949 1958          dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1950 1959          davap = dbvap;
1951 1960  
1952 1961          if (args->where.name == nfs3nametoolong) {
1953 1962                  resp->status = NFS3ERR_NAMETOOLONG;
1954 1963                  goto out1;
1955 1964          }
1956 1965  
1957 1966          if (args->where.name == NULL || *(args->where.name) == '\0') {
1958 1967                  resp->status = NFS3ERR_ACCES;
1959 1968                  goto out1;
1960 1969          }
1961 1970  
1962 1971          if (rdonly(ro, dvp)) {
1963 1972                  resp->status = NFS3ERR_ROFS;
1964 1973                  goto out1;
1965 1974          }
1966 1975  
1967 1976          if (is_system_labeled()) {
1968 1977                  bslabel_t *clabel = req->rq_label;
1969 1978  
1970 1979                  ASSERT(clabel != NULL);
1971 1980                  DTRACE_PROBE2(tx__rfs3__log__info__opmkdir__clabel, char *,
1972 1981                      "got client label from request(1)", struct svc_req *, req);
1973 1982  
1974 1983                  if (!blequal(&l_admin_low->tsl_label, clabel)) {
1975 1984                          if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
1976 1985                              exi)) {
1977 1986                                  resp->status = NFS3ERR_ACCES;
1978 1987                                  goto out1;
1979 1988                          }
1980 1989                  }
1981 1990          }
1982 1991  
1983 1992          error = sattr3_to_vattr(&args->attributes, &va);
1984 1993          if (error)
1985 1994                  goto out;
1986 1995  
1987 1996          if (!(va.va_mask & AT_MODE)) {
1988 1997                  resp->status = NFS3ERR_INVAL;
1989 1998                  goto out1;
1990 1999          }
1991 2000  
1992 2001          ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
1993 2002          name = nfscmd_convname(ca, exi, args->where.name,
1994 2003              NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
1995 2004  
1996 2005          if (name == NULL) {
1997 2006                  resp->status = NFS3ERR_INVAL;
1998 2007                  goto out1;
1999 2008          }
2000 2009  
2001 2010          va.va_mask |= AT_TYPE;
2002 2011          va.va_type = VDIR;
2003 2012  
2004 2013          error = VOP_MKDIR(dvp, name, &va, &vp, cr, NULL, 0, NULL);
2005 2014  
2006 2015          if (name != args->where.name)
2007 2016                  kmem_free(name, MAXPATHLEN + 1);
2008 2017  
2009 2018          dava.va_mask = AT_ALL;
2010 2019          davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
2011 2020  
2012 2021          /*
2013 2022           * Force modified data and metadata out to stable storage.
2014 2023           */
2015 2024          (void) VOP_FSYNC(dvp, 0, cr, NULL);
2016 2025  
2017 2026          if (error)
2018 2027                  goto out;
2019 2028  
2020 2029          error = makefh3(&resp->resok.obj.handle, vp, exi);
2021 2030          if (error)
2022 2031                  resp->resok.obj.handle_follows = FALSE;
2023 2032          else
2024 2033                  resp->resok.obj.handle_follows = TRUE;
2025 2034  
2026 2035          va.va_mask = AT_ALL;
2027 2036          vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2028 2037  
2029 2038          /*
2030 2039           * Force modified data and metadata out to stable storage.
2031 2040           */
2032 2041          (void) VOP_FSYNC(vp, 0, cr, NULL);
2033 2042  
2034 2043          VN_RELE(vp);
2035 2044  
2036 2045          resp->status = NFS3_OK;
2037 2046          vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2038 2047          vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2039 2048  
2040 2049          DTRACE_NFSV3_5(op__mkdir__done, struct svc_req *, req,
2041 2050              cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2042 2051              MKDIR3res *, resp);
2043 2052          VN_RELE(dvp);
2044 2053  
2045 2054          return;
2046 2055  
2047 2056  out:
2048 2057          if (curthread->t_flag & T_WOULDBLOCK) {
2049 2058                  curthread->t_flag &= ~T_WOULDBLOCK;
2050 2059                  resp->status = NFS3ERR_JUKEBOX;
2051 2060          } else
2052 2061                  resp->status = puterrno3(error);
2053 2062  out1:
2054 2063          DTRACE_NFSV3_5(op__mkdir__done, struct svc_req *, req,
2055 2064              cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2056 2065              MKDIR3res *, resp);
2057 2066          if (dvp != NULL)
2058 2067                  VN_RELE(dvp);
2059 2068          vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2060 2069  }
2061 2070  
2062 2071  void *
2063 2072  rfs3_mkdir_getfh(MKDIR3args *args)
2064 2073  {
2065 2074  
2066 2075          return (&args->where.dir);
2067 2076  }
2068 2077  
2069 2078  void
2070 2079  rfs3_symlink(SYMLINK3args *args, SYMLINK3res *resp, struct exportinfo *exi,
2071 2080      struct svc_req *req, cred_t *cr, bool_t ro)
2072 2081  {
2073 2082          int error;
2074 2083          vnode_t *vp;
2075 2084          vnode_t *dvp;
2076 2085          struct vattr *vap;
2077 2086          struct vattr va;
2078 2087          struct vattr *dbvap;
2079 2088          struct vattr dbva;
2080 2089          struct vattr *davap;
2081 2090          struct vattr dava;
2082 2091          struct sockaddr *ca;
2083 2092          char *name = NULL;
2084 2093          char *symdata = NULL;
2085 2094  
2086 2095          dbvap = NULL;
2087 2096          davap = NULL;
2088 2097  
2089 2098          dvp = nfs3_fhtovp(&args->where.dir, exi);
2090 2099  
2091 2100          DTRACE_NFSV3_5(op__symlink__start, struct svc_req *, req,
2092 2101              cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2093 2102              SYMLINK3args *, args);
2094 2103  
2095 2104          if (dvp == NULL) {
2096 2105                  error = ESTALE;
2097 2106                  goto err;
2098 2107          }
2099 2108  
2100 2109          dbva.va_mask = AT_ALL;
2101 2110          dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2102 2111          davap = dbvap;
2103 2112  
2104 2113          if (args->where.name == nfs3nametoolong) {
2105 2114                  resp->status = NFS3ERR_NAMETOOLONG;
2106 2115                  goto err1;
2107 2116          }
2108 2117  
2109 2118          if (args->where.name == NULL || *(args->where.name) == '\0') {
2110 2119                  resp->status = NFS3ERR_ACCES;
2111 2120                  goto err1;
2112 2121          }
2113 2122  
2114 2123          if (rdonly(ro, dvp)) {
2115 2124                  resp->status = NFS3ERR_ROFS;
2116 2125                  goto err1;
2117 2126          }
2118 2127  
2119 2128          if (is_system_labeled()) {
2120 2129                  bslabel_t *clabel = req->rq_label;
2121 2130  
2122 2131                  ASSERT(clabel != NULL);
2123 2132                  DTRACE_PROBE2(tx__rfs3__log__info__opsymlink__clabel, char *,
2124 2133                      "got client label from request(1)", struct svc_req *, req);
2125 2134  
2126 2135                  if (!blequal(&l_admin_low->tsl_label, clabel)) {
2127 2136                          if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
2128 2137                              exi)) {
2129 2138                                  resp->status = NFS3ERR_ACCES;
2130 2139                                  goto err1;
2131 2140                          }
2132 2141                  }
2133 2142          }
2134 2143  
2135 2144          error = sattr3_to_vattr(&args->symlink.symlink_attributes, &va);
2136 2145          if (error)
2137 2146                  goto err;
2138 2147  
2139 2148          if (!(va.va_mask & AT_MODE)) {
2140 2149                  resp->status = NFS3ERR_INVAL;
2141 2150                  goto err1;
2142 2151          }
2143 2152  
2144 2153          if (args->symlink.symlink_data == nfs3nametoolong) {
2145 2154                  resp->status = NFS3ERR_NAMETOOLONG;
2146 2155                  goto err1;
2147 2156          }
2148 2157  
2149 2158          ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2150 2159          name = nfscmd_convname(ca, exi, args->where.name,
2151 2160              NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2152 2161  
2153 2162          if (name == NULL) {
2154 2163                  /* This is really a Solaris EILSEQ */
2155 2164                  resp->status = NFS3ERR_INVAL;
2156 2165                  goto err1;
2157 2166          }
2158 2167  
2159 2168          symdata = nfscmd_convname(ca, exi, args->symlink.symlink_data,
2160 2169              NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2161 2170          if (symdata == NULL) {
2162 2171                  /* This is really a Solaris EILSEQ */
2163 2172                  resp->status = NFS3ERR_INVAL;
2164 2173                  goto err1;
2165 2174          }
2166 2175  
2167 2176  
2168 2177          va.va_mask |= AT_TYPE;
2169 2178          va.va_type = VLNK;
2170 2179  
2171 2180          error = VOP_SYMLINK(dvp, name, &va, symdata, cr, NULL, 0);
2172 2181  
2173 2182          dava.va_mask = AT_ALL;
2174 2183          davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
2175 2184  
2176 2185          if (error)
2177 2186                  goto err;
2178 2187  
2179 2188          error = VOP_LOOKUP(dvp, name, &vp, NULL, 0, NULL, cr,
2180 2189              NULL, NULL, NULL);
2181 2190  
2182 2191          /*
2183 2192           * Force modified data and metadata out to stable storage.
2184 2193           */
2185 2194          (void) VOP_FSYNC(dvp, 0, cr, NULL);
2186 2195  
2187 2196  
2188 2197          resp->status = NFS3_OK;
2189 2198          if (error) {
2190 2199                  resp->resok.obj.handle_follows = FALSE;
2191 2200                  vattr_to_post_op_attr(NULL, &resp->resok.obj_attributes);
2192 2201                  vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2193 2202                  goto out;
2194 2203          }
2195 2204  
2196 2205          error = makefh3(&resp->resok.obj.handle, vp, exi);
2197 2206          if (error)
2198 2207                  resp->resok.obj.handle_follows = FALSE;
2199 2208          else
2200 2209                  resp->resok.obj.handle_follows = TRUE;
2201 2210  
2202 2211          va.va_mask = AT_ALL;
2203 2212          vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2204 2213  
2205 2214          /*
2206 2215           * Force modified data and metadata out to stable storage.
2207 2216           */
2208 2217          (void) VOP_FSYNC(vp, 0, cr, NULL);
2209 2218  
2210 2219          VN_RELE(vp);
2211 2220  
2212 2221          vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2213 2222          vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2214 2223          goto out;
2215 2224  
2216 2225  err:
2217 2226          if (curthread->t_flag & T_WOULDBLOCK) {
2218 2227                  curthread->t_flag &= ~T_WOULDBLOCK;
2219 2228                  resp->status = NFS3ERR_JUKEBOX;
2220 2229          } else
2221 2230                  resp->status = puterrno3(error);
2222 2231  err1:
2223 2232          vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2224 2233  out:
2225 2234          if (name != NULL && name != args->where.name)
2226 2235                  kmem_free(name, MAXPATHLEN + 1);
2227 2236          if (symdata != NULL && symdata != args->symlink.symlink_data)
2228 2237                  kmem_free(symdata, MAXPATHLEN + 1);
2229 2238  
2230 2239          DTRACE_NFSV3_5(op__symlink__done, struct svc_req *, req,
2231 2240              cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2232 2241              SYMLINK3res *, resp);
2233 2242  
2234 2243          if (dvp != NULL)
2235 2244                  VN_RELE(dvp);
2236 2245  }
2237 2246  
2238 2247  void *
2239 2248  rfs3_symlink_getfh(SYMLINK3args *args)
2240 2249  {
2241 2250  
2242 2251          return (&args->where.dir);
2243 2252  }
2244 2253  
2245 2254  void
2246 2255  rfs3_mknod(MKNOD3args *args, MKNOD3res *resp, struct exportinfo *exi,
2247 2256      struct svc_req *req, cred_t *cr, bool_t ro)
2248 2257  {
2249 2258          int error;
2250 2259          vnode_t *vp;
2251 2260          vnode_t *realvp;
2252 2261          vnode_t *dvp;
2253 2262          struct vattr *vap;
2254 2263          struct vattr va;
2255 2264          struct vattr *dbvap;
2256 2265          struct vattr dbva;
2257 2266          struct vattr *davap;
2258 2267          struct vattr dava;
2259 2268          int mode;
2260 2269          enum vcexcl excl;
2261 2270          struct sockaddr *ca;
2262 2271          char *name = NULL;
2263 2272  
2264 2273          dbvap = NULL;
2265 2274          davap = NULL;
2266 2275  
2267 2276          dvp = nfs3_fhtovp(&args->where.dir, exi);
2268 2277  
2269 2278          DTRACE_NFSV3_5(op__mknod__start, struct svc_req *, req,
2270 2279              cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2271 2280              MKNOD3args *, args);
2272 2281  
2273 2282          if (dvp == NULL) {
2274 2283                  error = ESTALE;
2275 2284                  goto out;
2276 2285          }
2277 2286  
2278 2287          dbva.va_mask = AT_ALL;
2279 2288          dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2280 2289          davap = dbvap;
2281 2290  
2282 2291          if (args->where.name == nfs3nametoolong) {
2283 2292                  resp->status = NFS3ERR_NAMETOOLONG;
2284 2293                  goto out1;
2285 2294          }
2286 2295  
2287 2296          if (args->where.name == NULL || *(args->where.name) == '\0') {
2288 2297                  resp->status = NFS3ERR_ACCES;
2289 2298                  goto out1;
2290 2299          }
2291 2300  
2292 2301          if (rdonly(ro, dvp)) {
2293 2302                  resp->status = NFS3ERR_ROFS;
2294 2303                  goto out1;
2295 2304          }
2296 2305  
2297 2306          if (is_system_labeled()) {
2298 2307                  bslabel_t *clabel = req->rq_label;
2299 2308  
2300 2309                  ASSERT(clabel != NULL);
2301 2310                  DTRACE_PROBE2(tx__rfs3__log__info__opmknod__clabel, char *,
2302 2311                      "got client label from request(1)", struct svc_req *, req);
2303 2312  
2304 2313                  if (!blequal(&l_admin_low->tsl_label, clabel)) {
2305 2314                          if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
2306 2315                              exi)) {
2307 2316                                  resp->status = NFS3ERR_ACCES;
2308 2317                                  goto out1;
2309 2318                          }
2310 2319                  }
2311 2320          }
2312 2321  
2313 2322          switch (args->what.type) {
2314 2323          case NF3CHR:
2315 2324          case NF3BLK:
2316 2325                  error = sattr3_to_vattr(
2317 2326                      &args->what.mknoddata3_u.device.dev_attributes, &va);
2318 2327                  if (error)
2319 2328                          goto out;
2320 2329                  if (secpolicy_sys_devices(cr) != 0) {
2321 2330                          resp->status = NFS3ERR_PERM;
2322 2331                          goto out1;
2323 2332                  }
2324 2333                  if (args->what.type == NF3CHR)
2325 2334                          va.va_type = VCHR;
2326 2335                  else
2327 2336                          va.va_type = VBLK;
2328 2337                  va.va_rdev = makedevice(
2329 2338                      args->what.mknoddata3_u.device.spec.specdata1,
2330 2339                      args->what.mknoddata3_u.device.spec.specdata2);
2331 2340                  va.va_mask |= AT_TYPE | AT_RDEV;
2332 2341                  break;
2333 2342          case NF3SOCK:
2334 2343                  error = sattr3_to_vattr(
2335 2344                      &args->what.mknoddata3_u.pipe_attributes, &va);
2336 2345                  if (error)
2337 2346                          goto out;
2338 2347                  va.va_type = VSOCK;
2339 2348                  va.va_mask |= AT_TYPE;
2340 2349                  break;
2341 2350          case NF3FIFO:
2342 2351                  error = sattr3_to_vattr(
2343 2352                      &args->what.mknoddata3_u.pipe_attributes, &va);
2344 2353                  if (error)
2345 2354                          goto out;
2346 2355                  va.va_type = VFIFO;
2347 2356                  va.va_mask |= AT_TYPE;
2348 2357                  break;
2349 2358          default:
2350 2359                  resp->status = NFS3ERR_BADTYPE;
2351 2360                  goto out1;
2352 2361          }
2353 2362  
2354 2363          /*
2355 2364           * Must specify the mode.
2356 2365           */
2357 2366          if (!(va.va_mask & AT_MODE)) {
2358 2367                  resp->status = NFS3ERR_INVAL;
2359 2368                  goto out1;
2360 2369          }
2361 2370  
2362 2371          ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2363 2372          name = nfscmd_convname(ca, exi, args->where.name,
2364 2373              NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2365 2374  
2366 2375          if (name == NULL) {
2367 2376                  resp->status = NFS3ERR_INVAL;
2368 2377                  goto out1;
2369 2378          }
2370 2379  
2371 2380          excl = EXCL;
2372 2381  
2373 2382          mode = 0;
2374 2383  
2375 2384          error = VOP_CREATE(dvp, name, &va, excl, mode,
2376 2385              &vp, cr, 0, NULL, NULL);
2377 2386  
2378 2387          if (name != args->where.name)
2379 2388                  kmem_free(name, MAXPATHLEN + 1);
2380 2389  
2381 2390          dava.va_mask = AT_ALL;
2382 2391          davap = VOP_GETATTR(dvp, &dava, 0, cr, NULL) ? NULL : &dava;
2383 2392  
2384 2393          /*
2385 2394           * Force modified data and metadata out to stable storage.
2386 2395           */
2387 2396          (void) VOP_FSYNC(dvp, 0, cr, NULL);
2388 2397  
2389 2398          if (error)
2390 2399                  goto out;
2391 2400  
2392 2401          resp->status = NFS3_OK;
2393 2402  
2394 2403          error = makefh3(&resp->resok.obj.handle, vp, exi);
2395 2404          if (error)
2396 2405                  resp->resok.obj.handle_follows = FALSE;
2397 2406          else
2398 2407                  resp->resok.obj.handle_follows = TRUE;
2399 2408  
2400 2409          va.va_mask = AT_ALL;
2401 2410          vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2402 2411  
2403 2412          /*
2404 2413           * Force modified metadata out to stable storage.
2405 2414           *
2406 2415           * if a underlying vp exists, pass it to VOP_FSYNC
2407 2416           */
2408 2417          if (VOP_REALVP(vp, &realvp, NULL) == 0)
2409 2418                  (void) VOP_FSYNC(realvp, FNODSYNC, cr, NULL);
2410 2419          else
2411 2420                  (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
2412 2421  
2413 2422          VN_RELE(vp);
2414 2423  
2415 2424          vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2416 2425          vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2417 2426          DTRACE_NFSV3_5(op__mknod__done, struct svc_req *, req,
2418 2427              cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2419 2428              MKNOD3res *, resp);
2420 2429          VN_RELE(dvp);
2421 2430          return;
2422 2431  
2423 2432  out:
2424 2433          if (curthread->t_flag & T_WOULDBLOCK) {
2425 2434                  curthread->t_flag &= ~T_WOULDBLOCK;
2426 2435                  resp->status = NFS3ERR_JUKEBOX;
2427 2436          } else
2428 2437                  resp->status = puterrno3(error);
2429 2438  out1:
2430 2439          DTRACE_NFSV3_5(op__mknod__done, struct svc_req *, req,
2431 2440              cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2432 2441              MKNOD3res *, resp);
2433 2442          if (dvp != NULL)
2434 2443                  VN_RELE(dvp);
2435 2444          vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2436 2445  }
2437 2446  
2438 2447  void *
2439 2448  rfs3_mknod_getfh(MKNOD3args *args)
2440 2449  {
2441 2450  
2442 2451          return (&args->where.dir);
2443 2452  }
2444 2453  
2445 2454  void
2446 2455  rfs3_remove(REMOVE3args *args, REMOVE3res *resp, struct exportinfo *exi,
2447 2456      struct svc_req *req, cred_t *cr, bool_t ro)
2448 2457  {
2449 2458          int error = 0;
2450 2459          vnode_t *vp;
2451 2460          struct vattr *bvap;
2452 2461          struct vattr bva;
2453 2462          struct vattr *avap;
2454 2463          struct vattr ava;
2455 2464          vnode_t *targvp = NULL;
2456 2465          struct sockaddr *ca;
2457 2466          char *name = NULL;
2458 2467  
2459 2468          bvap = NULL;
2460 2469          avap = NULL;
2461 2470  
2462 2471          vp = nfs3_fhtovp(&args->object.dir, exi);
2463 2472  
2464 2473          DTRACE_NFSV3_5(op__remove__start, struct svc_req *, req,
2465 2474              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
2466 2475              REMOVE3args *, args);
2467 2476  
2468 2477          if (vp == NULL) {
2469 2478                  error = ESTALE;
2470 2479                  goto err;
2471 2480          }
2472 2481  
2473 2482          bva.va_mask = AT_ALL;
2474 2483          bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2475 2484          avap = bvap;
2476 2485  
2477 2486          if (vp->v_type != VDIR) {
2478 2487                  resp->status = NFS3ERR_NOTDIR;
2479 2488                  goto err1;
2480 2489          }
2481 2490  
2482 2491          if (args->object.name == nfs3nametoolong) {
2483 2492                  resp->status = NFS3ERR_NAMETOOLONG;
2484 2493                  goto err1;
2485 2494          }
2486 2495  
2487 2496          if (args->object.name == NULL || *(args->object.name) == '\0') {
2488 2497                  resp->status = NFS3ERR_ACCES;
2489 2498                  goto err1;
2490 2499          }
2491 2500  
2492 2501          if (rdonly(ro, vp)) {
2493 2502                  resp->status = NFS3ERR_ROFS;
2494 2503                  goto err1;
2495 2504          }
2496 2505  
2497 2506          if (is_system_labeled()) {
2498 2507                  bslabel_t *clabel = req->rq_label;
2499 2508  
2500 2509                  ASSERT(clabel != NULL);
2501 2510                  DTRACE_PROBE2(tx__rfs3__log__info__opremove__clabel, char *,
2502 2511                      "got client label from request(1)", struct svc_req *, req);
2503 2512  
2504 2513                  if (!blequal(&l_admin_low->tsl_label, clabel)) {
2505 2514                          if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
2506 2515                              exi)) {
2507 2516                                  resp->status = NFS3ERR_ACCES;
2508 2517                                  goto err1;
2509 2518                          }
2510 2519                  }
2511 2520          }
2512 2521  
2513 2522          ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2514 2523          name = nfscmd_convname(ca, exi, args->object.name,
2515 2524              NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2516 2525  
2517 2526          if (name == NULL) {
2518 2527                  resp->status = NFS3ERR_INVAL;
2519 2528                  goto err1;
2520 2529          }
2521 2530  
2522 2531          /*
2523 2532           * Check for a conflict with a non-blocking mandatory share
2524 2533           * reservation and V4 delegations
2525 2534           */
2526 2535          error = VOP_LOOKUP(vp, name, &targvp, NULL, 0,
2527 2536              NULL, cr, NULL, NULL, NULL);
2528 2537          if (error != 0)
2529 2538                  goto err;
2530 2539  
2531 2540          if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
2532 2541                  resp->status = NFS3ERR_JUKEBOX;
2533 2542                  goto err1;
2534 2543          }
2535 2544  
2536 2545          if (!nbl_need_check(targvp)) {
2537 2546                  error = VOP_REMOVE(vp, name, cr, NULL, 0);
2538 2547          } else {
2539 2548                  nbl_start_crit(targvp, RW_READER);
2540 2549                  if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0, NULL)) {
2541 2550                          error = EACCES;
2542 2551                  } else {
2543 2552                          error = VOP_REMOVE(vp, name, cr, NULL, 0);
2544 2553                  }
2545 2554                  nbl_end_crit(targvp);
2546 2555          }
2547 2556          VN_RELE(targvp);
2548 2557          targvp = NULL;
2549 2558  
2550 2559          ava.va_mask = AT_ALL;
2551 2560          avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
2552 2561  
2553 2562          /*
2554 2563           * Force modified data and metadata out to stable storage.
2555 2564           */
2556 2565          (void) VOP_FSYNC(vp, 0, cr, NULL);
2557 2566  
2558 2567          if (error)
2559 2568                  goto err;
2560 2569  
2561 2570          resp->status = NFS3_OK;
2562 2571          vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
2563 2572          goto out;
2564 2573  
2565 2574  err:
2566 2575          if (curthread->t_flag & T_WOULDBLOCK) {
2567 2576                  curthread->t_flag &= ~T_WOULDBLOCK;
2568 2577                  resp->status = NFS3ERR_JUKEBOX;
2569 2578          } else
2570 2579                  resp->status = puterrno3(error);
2571 2580  err1:
2572 2581          vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
2573 2582  out:
2574 2583          DTRACE_NFSV3_5(op__remove__done, struct svc_req *, req,
2575 2584              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
2576 2585              REMOVE3res *, resp);
2577 2586  
2578 2587          if (name != NULL && name != args->object.name)
2579 2588                  kmem_free(name, MAXPATHLEN + 1);
2580 2589  
2581 2590          if (vp != NULL)
2582 2591                  VN_RELE(vp);
2583 2592  }
2584 2593  
2585 2594  void *
2586 2595  rfs3_remove_getfh(REMOVE3args *args)
2587 2596  {
2588 2597  
2589 2598          return (&args->object.dir);
2590 2599  }
2591 2600  
2592 2601  void
2593 2602  rfs3_rmdir(RMDIR3args *args, RMDIR3res *resp, struct exportinfo *exi,
2594 2603      struct svc_req *req, cred_t *cr, bool_t ro)
2595 2604  {
2596 2605          int error;
2597 2606          vnode_t *vp;
2598 2607          struct vattr *bvap;
2599 2608          struct vattr bva;
2600 2609          struct vattr *avap;
2601 2610          struct vattr ava;
2602 2611          struct sockaddr *ca;
2603 2612          char *name = NULL;
2604 2613  
2605 2614          bvap = NULL;
2606 2615          avap = NULL;
2607 2616  
2608 2617          vp = nfs3_fhtovp(&args->object.dir, exi);
2609 2618  
2610 2619          DTRACE_NFSV3_5(op__rmdir__start, struct svc_req *, req,
2611 2620              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
2612 2621              RMDIR3args *, args);
2613 2622  
2614 2623          if (vp == NULL) {
2615 2624                  error = ESTALE;
2616 2625                  goto err;
2617 2626          }
2618 2627  
2619 2628          bva.va_mask = AT_ALL;
2620 2629          bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2621 2630          avap = bvap;
2622 2631  
2623 2632          if (vp->v_type != VDIR) {
2624 2633                  resp->status = NFS3ERR_NOTDIR;
2625 2634                  goto err1;
2626 2635          }
2627 2636  
2628 2637          if (args->object.name == nfs3nametoolong) {
2629 2638                  resp->status = NFS3ERR_NAMETOOLONG;
2630 2639                  goto err1;
2631 2640          }
2632 2641  
2633 2642          if (args->object.name == NULL || *(args->object.name) == '\0') {
2634 2643                  resp->status = NFS3ERR_ACCES;
2635 2644                  goto err1;
2636 2645          }
2637 2646  
2638 2647          if (rdonly(ro, vp)) {
2639 2648                  resp->status = NFS3ERR_ROFS;
2640 2649                  goto err1;
2641 2650          }
2642 2651  
2643 2652          if (is_system_labeled()) {
2644 2653                  bslabel_t *clabel = req->rq_label;
2645 2654  
2646 2655                  ASSERT(clabel != NULL);
2647 2656                  DTRACE_PROBE2(tx__rfs3__log__info__opremovedir__clabel, char *,
2648 2657                      "got client label from request(1)", struct svc_req *, req);
2649 2658  
2650 2659                  if (!blequal(&l_admin_low->tsl_label, clabel)) {
2651 2660                          if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
2652 2661                              exi)) {
2653 2662                                  resp->status = NFS3ERR_ACCES;
2654 2663                                  goto err1;
2655 2664                          }
2656 2665                  }
2657 2666          }
2658 2667  
2659 2668          ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2660 2669          name = nfscmd_convname(ca, exi, args->object.name,
2661 2670              NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2662 2671  
2663 2672          if (name == NULL) {
2664 2673                  resp->status = NFS3ERR_INVAL;
2665 2674                  goto err1;
2666 2675          }
2667 2676  
2668 2677          error = VOP_RMDIR(vp, name, ZONE_ROOTVP(), cr, NULL, 0);
2669 2678  
2670 2679          if (name != args->object.name)
2671 2680                  kmem_free(name, MAXPATHLEN + 1);
2672 2681  
2673 2682          ava.va_mask = AT_ALL;
2674 2683          avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
2675 2684  
2676 2685          /*
2677 2686           * Force modified data and metadata out to stable storage.
2678 2687           */
2679 2688          (void) VOP_FSYNC(vp, 0, cr, NULL);
2680 2689  
2681 2690          if (error) {
2682 2691                  /*
2683 2692                   * System V defines rmdir to return EEXIST, not ENOTEMPTY,
2684 2693                   * if the directory is not empty.  A System V NFS server
2685 2694                   * needs to map NFS3ERR_EXIST to NFS3ERR_NOTEMPTY to transmit
2686 2695                   * over the wire.
2687 2696                   */
2688 2697                  if (error == EEXIST)
2689 2698                          error = ENOTEMPTY;
2690 2699                  goto err;
2691 2700          }
2692 2701  
2693 2702          resp->status = NFS3_OK;
2694 2703          vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
2695 2704          goto out;
2696 2705  
2697 2706  err:
2698 2707          if (curthread->t_flag & T_WOULDBLOCK) {
2699 2708                  curthread->t_flag &= ~T_WOULDBLOCK;
2700 2709                  resp->status = NFS3ERR_JUKEBOX;
2701 2710          } else
2702 2711                  resp->status = puterrno3(error);
2703 2712  err1:
2704 2713          vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
2705 2714  out:
2706 2715          DTRACE_NFSV3_5(op__rmdir__done, struct svc_req *, req,
2707 2716              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
2708 2717              RMDIR3res *, resp);
2709 2718          if (vp != NULL)
2710 2719                  VN_RELE(vp);
2711 2720  
2712 2721  }
2713 2722  
2714 2723  void *
2715 2724  rfs3_rmdir_getfh(RMDIR3args *args)
2716 2725  {
2717 2726  
2718 2727          return (&args->object.dir);
2719 2728  }
2720 2729  
2721 2730  void
2722 2731  rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi,
2723 2732      struct svc_req *req, cred_t *cr, bool_t ro)
2724 2733  {
2725 2734          int error = 0;
2726 2735          vnode_t *fvp;
2727 2736          vnode_t *tvp;
2728 2737          vnode_t *targvp;
2729 2738          struct vattr *fbvap;
2730 2739          struct vattr fbva;
2731 2740          struct vattr *favap;
2732 2741          struct vattr fava;
2733 2742          struct vattr *tbvap;
2734 2743          struct vattr tbva;
2735 2744          struct vattr *tavap;
2736 2745          struct vattr tava;
2737 2746          nfs_fh3 *fh3;
2738 2747          struct exportinfo *to_exi;
2739 2748          vnode_t *srcvp = NULL;
2740 2749          bslabel_t *clabel;
2741 2750          struct sockaddr *ca;
2742 2751          char *name = NULL;
2743 2752          char *toname = NULL;
2744 2753  
2745 2754          fbvap = NULL;
2746 2755          favap = NULL;
2747 2756          tbvap = NULL;
2748 2757          tavap = NULL;
2749 2758          tvp = NULL;
2750 2759  
2751 2760          fvp = nfs3_fhtovp(&args->from.dir, exi);
2752 2761  
2753 2762          DTRACE_NFSV3_5(op__rename__start, struct svc_req *, req,
2754 2763              cred_t *, cr, vnode_t *, fvp, struct exportinfo *, exi,
2755 2764              RENAME3args *, args);
2756 2765  
2757 2766          if (fvp == NULL) {
2758 2767                  error = ESTALE;
2759 2768                  goto err;
2760 2769          }
2761 2770  
2762 2771          if (is_system_labeled()) {
2763 2772                  clabel = req->rq_label;
2764 2773                  ASSERT(clabel != NULL);
2765 2774                  DTRACE_PROBE2(tx__rfs3__log__info__oprename__clabel, char *,
2766 2775                      "got client label from request(1)", struct svc_req *, req);
2767 2776  
2768 2777                  if (!blequal(&l_admin_low->tsl_label, clabel)) {
2769 2778                          if (!do_rfs_label_check(clabel, fvp, EQUALITY_CHECK,
2770 2779                              exi)) {
2771 2780                                  resp->status = NFS3ERR_ACCES;
2772 2781                                  goto err1;
2773 2782                          }
2774 2783                  }
2775 2784          }
2776 2785  
2777 2786          fbva.va_mask = AT_ALL;
2778 2787          fbvap = VOP_GETATTR(fvp, &fbva, 0, cr, NULL) ? NULL : &fbva;
2779 2788          favap = fbvap;
2780 2789  
2781 2790          fh3 = &args->to.dir;
2782 2791          to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
2783 2792          if (to_exi == NULL) {
2784 2793                  resp->status = NFS3ERR_ACCES;
2785 2794                  goto err1;
2786 2795          }
2787 2796          exi_rele(to_exi);
2788 2797  
2789 2798          if (to_exi != exi) {
2790 2799                  resp->status = NFS3ERR_XDEV;
2791 2800                  goto err1;
2792 2801          }
2793 2802  
2794 2803          tvp = nfs3_fhtovp(&args->to.dir, exi);
2795 2804          if (tvp == NULL) {
2796 2805                  error = ESTALE;
2797 2806                  goto err;
2798 2807          }
2799 2808  
2800 2809          tbva.va_mask = AT_ALL;
2801 2810          tbvap = VOP_GETATTR(tvp, &tbva, 0, cr, NULL) ? NULL : &tbva;
2802 2811          tavap = tbvap;
2803 2812  
2804 2813          if (fvp->v_type != VDIR || tvp->v_type != VDIR) {
2805 2814                  resp->status = NFS3ERR_NOTDIR;
2806 2815                  goto err1;
2807 2816          }
2808 2817  
2809 2818          if (args->from.name == nfs3nametoolong ||
2810 2819              args->to.name == nfs3nametoolong) {
2811 2820                  resp->status = NFS3ERR_NAMETOOLONG;
2812 2821                  goto err1;
2813 2822          }
2814 2823          if (args->from.name == NULL || *(args->from.name) == '\0' ||
2815 2824              args->to.name == NULL || *(args->to.name) == '\0') {
2816 2825                  resp->status = NFS3ERR_ACCES;
2817 2826                  goto err1;
2818 2827          }
2819 2828  
2820 2829          if (rdonly(ro, tvp)) {
2821 2830                  resp->status = NFS3ERR_ROFS;
2822 2831                  goto err1;
2823 2832          }
2824 2833  
2825 2834          if (is_system_labeled()) {
2826 2835                  if (!blequal(&l_admin_low->tsl_label, clabel)) {
2827 2836                          if (!do_rfs_label_check(clabel, tvp, EQUALITY_CHECK,
2828 2837                              exi)) {
2829 2838                                  resp->status = NFS3ERR_ACCES;
2830 2839                                  goto err1;
2831 2840                          }
2832 2841                  }
2833 2842          }
2834 2843  
2835 2844          ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2836 2845          name = nfscmd_convname(ca, exi, args->from.name,
2837 2846              NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2838 2847  
2839 2848          if (name == NULL) {
2840 2849                  resp->status = NFS3ERR_INVAL;
2841 2850                  goto err1;
2842 2851          }
2843 2852  
2844 2853          toname = nfscmd_convname(ca, exi, args->to.name,
2845 2854              NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2846 2855  
2847 2856          if (toname == NULL) {
2848 2857                  resp->status = NFS3ERR_INVAL;
2849 2858                  goto err1;
2850 2859          }
2851 2860  
2852 2861          /*
2853 2862           * Check for a conflict with a non-blocking mandatory share
2854 2863           * reservation or V4 delegations.
2855 2864           */
2856 2865          error = VOP_LOOKUP(fvp, name, &srcvp, NULL, 0,
2857 2866              NULL, cr, NULL, NULL, NULL);
2858 2867          if (error != 0)
2859 2868                  goto err;
2860 2869  
2861 2870          /*
2862 2871           * If we rename a delegated file we should recall the
2863 2872           * delegation, since future opens should fail or would
2864 2873           * refer to a new file.
2865 2874           */
2866 2875          if (rfs4_check_delegated(FWRITE, srcvp, FALSE)) {
2867 2876                  resp->status = NFS3ERR_JUKEBOX;
2868 2877                  goto err1;
2869 2878          }
2870 2879  
2871 2880          /*
2872 2881           * Check for renaming over a delegated file.  Check nfs4_deleg_policy
2873 2882           * first to avoid VOP_LOOKUP if possible.
2874 2883           */
2875 2884          if (nfs4_get_deleg_policy() != SRV_NEVER_DELEGATE &&
2876 2885              VOP_LOOKUP(tvp, toname, &targvp, NULL, 0, NULL, cr,
2877 2886              NULL, NULL, NULL) == 0) {
2878 2887  
2879 2888                  if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
2880 2889                          VN_RELE(targvp);
2881 2890                          resp->status = NFS3ERR_JUKEBOX;
2882 2891                          goto err1;
2883 2892                  }
2884 2893                  VN_RELE(targvp);
2885 2894          }
2886 2895  
2887 2896          if (!nbl_need_check(srcvp)) {
2888 2897                  error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
2889 2898          } else {
2890 2899                  nbl_start_crit(srcvp, RW_READER);
2891 2900                  if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0, NULL))
2892 2901                          error = EACCES;
2893 2902                  else
2894 2903                          error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
2895 2904                  nbl_end_crit(srcvp);
2896 2905          }
2897 2906          if (error == 0)
2898 2907                  vn_renamepath(tvp, srcvp, args->to.name,
2899 2908                      strlen(args->to.name));
2900 2909          VN_RELE(srcvp);
2901 2910          srcvp = NULL;
2902 2911  
2903 2912          fava.va_mask = AT_ALL;
2904 2913          favap = VOP_GETATTR(fvp, &fava, 0, cr, NULL) ? NULL : &fava;
2905 2914          tava.va_mask = AT_ALL;
2906 2915          tavap = VOP_GETATTR(tvp, &tava, 0, cr, NULL) ? NULL : &tava;
2907 2916  
2908 2917          /*
2909 2918           * Force modified data and metadata out to stable storage.
2910 2919           */
2911 2920          (void) VOP_FSYNC(fvp, 0, cr, NULL);
2912 2921          (void) VOP_FSYNC(tvp, 0, cr, NULL);
2913 2922  
2914 2923          if (error)
2915 2924                  goto err;
2916 2925  
2917 2926          resp->status = NFS3_OK;
2918 2927          vattr_to_wcc_data(fbvap, favap, &resp->resok.fromdir_wcc);
2919 2928          vattr_to_wcc_data(tbvap, tavap, &resp->resok.todir_wcc);
2920 2929          goto out;
2921 2930  
2922 2931  err:
2923 2932          if (curthread->t_flag & T_WOULDBLOCK) {
2924 2933                  curthread->t_flag &= ~T_WOULDBLOCK;
2925 2934                  resp->status = NFS3ERR_JUKEBOX;
2926 2935          } else {
2927 2936                  resp->status = puterrno3(error);
2928 2937          }
2929 2938  err1:
2930 2939          vattr_to_wcc_data(fbvap, favap, &resp->resfail.fromdir_wcc);
2931 2940          vattr_to_wcc_data(tbvap, tavap, &resp->resfail.todir_wcc);
2932 2941  
2933 2942  out:
2934 2943          if (name != NULL && name != args->from.name)
2935 2944                  kmem_free(name, MAXPATHLEN + 1);
2936 2945          if (toname != NULL && toname != args->to.name)
2937 2946                  kmem_free(toname, MAXPATHLEN + 1);
2938 2947  
2939 2948          DTRACE_NFSV3_5(op__rename__done, struct svc_req *, req,
2940 2949              cred_t *, cr, vnode_t *, fvp, struct exportinfo *, exi,
2941 2950              RENAME3res *, resp);
2942 2951          if (fvp != NULL)
2943 2952                  VN_RELE(fvp);
2944 2953          if (tvp != NULL)
2945 2954                  VN_RELE(tvp);
2946 2955  }
2947 2956  
2948 2957  void *
2949 2958  rfs3_rename_getfh(RENAME3args *args)
2950 2959  {
2951 2960  
2952 2961          return (&args->from.dir);
2953 2962  }
2954 2963  
2955 2964  void
2956 2965  rfs3_link(LINK3args *args, LINK3res *resp, struct exportinfo *exi,
2957 2966      struct svc_req *req, cred_t *cr, bool_t ro)
2958 2967  {
2959 2968          int error;
2960 2969          vnode_t *vp;
2961 2970          vnode_t *dvp;
2962 2971          struct vattr *vap;
2963 2972          struct vattr va;
2964 2973          struct vattr *bvap;
2965 2974          struct vattr bva;
2966 2975          struct vattr *avap;
2967 2976          struct vattr ava;
2968 2977          nfs_fh3 *fh3;
2969 2978          struct exportinfo *to_exi;
2970 2979          bslabel_t *clabel;
2971 2980          struct sockaddr *ca;
2972 2981          char *name = NULL;
2973 2982  
2974 2983          vap = NULL;
2975 2984          bvap = NULL;
2976 2985          avap = NULL;
2977 2986          dvp = NULL;
2978 2987  
2979 2988          vp = nfs3_fhtovp(&args->file, exi);
2980 2989  
2981 2990          DTRACE_NFSV3_5(op__link__start, struct svc_req *, req,
2982 2991              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
2983 2992              LINK3args *, args);
2984 2993  
2985 2994          if (vp == NULL) {
2986 2995                  error = ESTALE;
2987 2996                  goto out;
2988 2997          }
2989 2998  
2990 2999          va.va_mask = AT_ALL;
2991 3000          vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2992 3001  
2993 3002          fh3 = &args->link.dir;
2994 3003          to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
2995 3004          if (to_exi == NULL) {
2996 3005                  resp->status = NFS3ERR_ACCES;
2997 3006                  goto out1;
2998 3007          }
2999 3008          exi_rele(to_exi);
3000 3009  
3001 3010          if (to_exi != exi) {
3002 3011                  resp->status = NFS3ERR_XDEV;
3003 3012                  goto out1;
3004 3013          }
3005 3014  
3006 3015          if (is_system_labeled()) {
3007 3016                  clabel = req->rq_label;
3008 3017  
3009 3018                  ASSERT(clabel != NULL);
3010 3019                  DTRACE_PROBE2(tx__rfs3__log__info__oplink__clabel, char *,
3011 3020                      "got client label from request(1)", struct svc_req *, req);
3012 3021  
3013 3022                  if (!blequal(&l_admin_low->tsl_label, clabel)) {
3014 3023                          if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3015 3024                              exi)) {
3016 3025                                  resp->status = NFS3ERR_ACCES;
3017 3026                                  goto out1;
3018 3027                          }
3019 3028                  }
3020 3029          }
3021 3030  
3022 3031          dvp = nfs3_fhtovp(&args->link.dir, exi);
3023 3032          if (dvp == NULL) {
3024 3033                  error = ESTALE;
3025 3034                  goto out;
3026 3035          }
3027 3036  
3028 3037          bva.va_mask = AT_ALL;
3029 3038          bvap = VOP_GETATTR(dvp, &bva, 0, cr, NULL) ? NULL : &bva;
3030 3039  
3031 3040          if (dvp->v_type != VDIR) {
3032 3041                  resp->status = NFS3ERR_NOTDIR;
3033 3042                  goto out1;
3034 3043          }
3035 3044  
3036 3045          if (args->link.name == nfs3nametoolong) {
3037 3046                  resp->status = NFS3ERR_NAMETOOLONG;
3038 3047                  goto out1;
3039 3048          }
3040 3049  
3041 3050          if (args->link.name == NULL || *(args->link.name) == '\0') {
3042 3051                  resp->status = NFS3ERR_ACCES;
3043 3052                  goto out1;
3044 3053          }
3045 3054  
3046 3055          if (rdonly(ro, dvp)) {
3047 3056                  resp->status = NFS3ERR_ROFS;
3048 3057                  goto out1;
3049 3058          }
3050 3059  
3051 3060          if (is_system_labeled()) {
3052 3061                  DTRACE_PROBE2(tx__rfs3__log__info__oplinkdir__clabel, char *,
3053 3062                      "got client label from request(1)", struct svc_req *, req);
3054 3063  
3055 3064                  if (!blequal(&l_admin_low->tsl_label, clabel)) {
3056 3065                          if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
3057 3066                              exi)) {
3058 3067                                  resp->status = NFS3ERR_ACCES;
3059 3068                                  goto out1;
3060 3069                          }
3061 3070                  }
3062 3071          }
3063 3072  
3064 3073          ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3065 3074          name = nfscmd_convname(ca, exi, args->link.name,
3066 3075              NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
3067 3076  
3068 3077          if (name == NULL) {
3069 3078                  resp->status = NFS3ERR_SERVERFAULT;
3070 3079                  goto out1;
3071 3080          }
3072 3081  
3073 3082          error = VOP_LINK(dvp, vp, name, cr, NULL, 0);
3074 3083  
3075 3084          va.va_mask = AT_ALL;
3076 3085          vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3077 3086          ava.va_mask = AT_ALL;
3078 3087          avap = VOP_GETATTR(dvp, &ava, 0, cr, NULL) ? NULL : &ava;
3079 3088  
3080 3089          /*
3081 3090           * Force modified data and metadata out to stable storage.
3082 3091           */
3083 3092          (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3084 3093          (void) VOP_FSYNC(dvp, 0, cr, NULL);
3085 3094  
3086 3095          if (error)
3087 3096                  goto out;
3088 3097  
3089 3098          VN_RELE(dvp);
3090 3099  
3091 3100          resp->status = NFS3_OK;
3092 3101          vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
3093 3102          vattr_to_wcc_data(bvap, avap, &resp->resok.linkdir_wcc);
3094 3103  
3095 3104          DTRACE_NFSV3_5(op__link__done, struct svc_req *, req,
3096 3105              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3097 3106              LINK3res *, resp);
3098 3107  
3099 3108          VN_RELE(vp);
3100 3109  
3101 3110          return;
3102 3111  
3103 3112  out:
3104 3113          if (curthread->t_flag & T_WOULDBLOCK) {
3105 3114                  curthread->t_flag &= ~T_WOULDBLOCK;
3106 3115                  resp->status = NFS3ERR_JUKEBOX;
3107 3116          } else
3108 3117                  resp->status = puterrno3(error);
3109 3118  out1:
3110 3119          if (name != NULL && name != args->link.name)
3111 3120                  kmem_free(name, MAXPATHLEN + 1);
3112 3121  
3113 3122          DTRACE_NFSV3_5(op__link__done, struct svc_req *, req,
3114 3123              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3115 3124              LINK3res *, resp);
3116 3125  
3117 3126          if (vp != NULL)
3118 3127                  VN_RELE(vp);
3119 3128          if (dvp != NULL)
3120 3129                  VN_RELE(dvp);
3121 3130          vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
3122 3131          vattr_to_wcc_data(bvap, avap, &resp->resfail.linkdir_wcc);
3123 3132  }
3124 3133  
3125 3134  void *
3126 3135  rfs3_link_getfh(LINK3args *args)
3127 3136  {
3128 3137  
3129 3138          return (&args->file);
3130 3139  }
3131 3140  
3132 3141  /*
3133 3142   * This macro defines the size of a response which contains attribute
3134 3143   * information and one directory entry (whose length is specified by
3135 3144   * the macro parameter).  If the incoming request is larger than this,
3136 3145   * then we are guaranteed to be able to return at one directory entry
3137 3146   * if one exists.  Therefore, we do not need to check for
3138 3147   * NFS3ERR_TOOSMALL if the requested size is larger then this.  If it
3139 3148   * is not, then we need to check to make sure that this error does not
3140 3149   * need to be returned.
3141 3150   *
3142 3151   * NFS3_READDIR_MIN_COUNT is comprised of following :
3143 3152   *
3144 3153   * status - 1 * BYTES_PER_XDR_UNIT
3145 3154   * attr. flag - 1 * BYTES_PER_XDR_UNIT
3146 3155   * cookie verifier - 2 * BYTES_PER_XDR_UNIT
3147 3156   * attributes  - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT
3148 3157   * boolean - 1 * BYTES_PER_XDR_UNIT
3149 3158   * file id - 2 * BYTES_PER_XDR_UNIT
3150 3159   * directory name length - 1 * BYTES_PER_XDR_UNIT
3151 3160   * cookie - 2 * BYTES_PER_XDR_UNIT
3152 3161   * end of list - 1 * BYTES_PER_XDR_UNIT
3153 3162   * end of file - 1 * BYTES_PER_XDR_UNIT
3154 3163   * Name length of directory to the nearest byte
3155 3164   */
3156 3165  
3157 3166  #define NFS3_READDIR_MIN_COUNT(length)  \
3158 3167          ((1 + 1 + 2 + NFS3_SIZEOF_FATTR3 + 1 + 2 + 1 + 2 + 1 + 1) * \
3159 3168                  BYTES_PER_XDR_UNIT + roundup((length), BYTES_PER_XDR_UNIT))
3160 3169  
3161 3170  /* ARGSUSED */
3162 3171  void
3163 3172  rfs3_readdir(READDIR3args *args, READDIR3res *resp, struct exportinfo *exi,
3164 3173      struct svc_req *req, cred_t *cr, bool_t ro)
3165 3174  {
3166 3175          int error;
3167 3176          vnode_t *vp;
3168 3177          struct vattr *vap;
3169 3178          struct vattr va;
3170 3179          struct iovec iov;
3171 3180          struct uio uio;
3172 3181          char *data;
3173 3182          int iseof;
3174 3183          int bufsize;
3175 3184          int namlen;
3176 3185          uint_t count;
3177 3186          struct sockaddr *ca;
3178 3187  
3179 3188          vap = NULL;
3180 3189  
3181 3190          vp = nfs3_fhtovp(&args->dir, exi);
3182 3191  
3183 3192          DTRACE_NFSV3_5(op__readdir__start, struct svc_req *, req,
3184 3193              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3185 3194              READDIR3args *, args);
3186 3195  
3187 3196          if (vp == NULL) {
3188 3197                  error = ESTALE;
3189 3198                  goto out;
3190 3199          }
3191 3200  
3192 3201          if (is_system_labeled()) {
3193 3202                  bslabel_t *clabel = req->rq_label;
3194 3203  
3195 3204                  ASSERT(clabel != NULL);
3196 3205                  DTRACE_PROBE2(tx__rfs3__log__info__opreaddir__clabel, char *,
3197 3206                      "got client label from request(1)", struct svc_req *, req);
3198 3207  
3199 3208                  if (!blequal(&l_admin_low->tsl_label, clabel)) {
3200 3209                          if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3201 3210                              exi)) {
3202 3211                                  resp->status = NFS3ERR_ACCES;
3203 3212                                  goto out1;
3204 3213                          }
3205 3214                  }
3206 3215          }
3207 3216  
3208 3217          (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
3209 3218  
3210 3219          va.va_mask = AT_ALL;
3211 3220          vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3212 3221  
3213 3222          if (vp->v_type != VDIR) {
3214 3223                  resp->status = NFS3ERR_NOTDIR;
3215 3224                  goto out1;
3216 3225          }
3217 3226  
3218 3227          error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
3219 3228          if (error)
3220 3229                  goto out;
3221 3230  
3222 3231          /*
3223 3232           * Now don't allow arbitrary count to alloc;
3224 3233           * allow the maximum not to exceed rfs3_tsize()
3225 3234           */
3226 3235          if (args->count > rfs3_tsize(req))
3227 3236                  args->count = rfs3_tsize(req);
3228 3237  
3229 3238          /*
3230 3239           * Make sure that there is room to read at least one entry
3231 3240           * if any are available.
3232 3241           */
3233 3242          if (args->count < DIRENT64_RECLEN(MAXNAMELEN))
3234 3243                  count = DIRENT64_RECLEN(MAXNAMELEN);
3235 3244          else
3236 3245                  count = args->count;
3237 3246  
3238 3247          data = kmem_alloc(count, KM_SLEEP);
3239 3248  
3240 3249          iov.iov_base = data;
3241 3250          iov.iov_len = count;
3242 3251          uio.uio_iov = &iov;
3243 3252          uio.uio_iovcnt = 1;
3244 3253          uio.uio_segflg = UIO_SYSSPACE;
3245 3254          uio.uio_extflg = UIO_COPY_CACHED;
3246 3255          uio.uio_loffset = (offset_t)args->cookie;
3247 3256          uio.uio_resid = count;
3248 3257  
3249 3258          error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
3250 3259  
3251 3260          va.va_mask = AT_ALL;
3252 3261          vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3253 3262  
3254 3263          if (error) {
3255 3264                  kmem_free(data, count);
3256 3265                  goto out;
3257 3266          }
3258 3267  
3259 3268          /*
3260 3269           * If the count was not large enough to be able to guarantee
3261 3270           * to be able to return at least one entry, then need to
3262 3271           * check to see if NFS3ERR_TOOSMALL should be returned.
3263 3272           */
3264 3273          if (args->count < NFS3_READDIR_MIN_COUNT(MAXNAMELEN)) {
3265 3274                  /*
3266 3275                   * bufsize is used to keep track of the size of the response.
3267 3276                   * It is primed with:
3268 3277                   *      1 for the status +
3269 3278                   *      1 for the dir_attributes.attributes boolean +
3270 3279                   *      2 for the cookie verifier
3271 3280                   * all times BYTES_PER_XDR_UNIT to convert from XDR units
3272 3281                   * to bytes.  If there are directory attributes to be
3273 3282                   * returned, then:
3274 3283                   *      NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3
3275 3284                   * time BYTES_PER_XDR_UNIT is added to account for them.
3276 3285                   */
3277 3286                  bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT;
3278 3287                  if (vap != NULL)
3279 3288                          bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT;
3280 3289                  /*
3281 3290                   * An entry is composed of:
3282 3291                   *      1 for the true/false list indicator +
3283 3292                   *      2 for the fileid +
3284 3293                   *      1 for the length of the name +
3285 3294                   *      2 for the cookie +
3286 3295                   * all times BYTES_PER_XDR_UNIT to convert from
3287 3296                   * XDR units to bytes, plus the length of the name
3288 3297                   * rounded up to the nearest BYTES_PER_XDR_UNIT.
3289 3298                   */
3290 3299                  if (count != uio.uio_resid) {
3291 3300                          namlen = strlen(((struct dirent64 *)data)->d_name);
3292 3301                          bufsize += (1 + 2 + 1 + 2) * BYTES_PER_XDR_UNIT +
3293 3302                              roundup(namlen, BYTES_PER_XDR_UNIT);
3294 3303                  }
3295 3304                  /*
3296 3305                   * We need to check to see if the number of bytes left
3297 3306                   * to go into the buffer will actually fit into the
3298 3307                   * buffer.  This is calculated as the size of this
3299 3308                   * entry plus:
3300 3309                   *      1 for the true/false list indicator +
3301 3310                   *      1 for the eof indicator
3302 3311                   * times BYTES_PER_XDR_UNIT to convert from from
3303 3312                   * XDR units to bytes.
3304 3313                   */
3305 3314                  bufsize += (1 + 1) * BYTES_PER_XDR_UNIT;
3306 3315                  if (bufsize > args->count) {
3307 3316                          kmem_free(data, count);
3308 3317                          resp->status = NFS3ERR_TOOSMALL;
3309 3318                          goto out1;
3310 3319                  }
3311 3320          }
3312 3321  
3313 3322          /*
3314 3323           * Have a valid readir buffer for the native character
3315 3324           * set. Need to check if a conversion is necessary and
3316 3325           * potentially rewrite the whole buffer. Note that if the
3317 3326           * conversion expands names enough, the structure may not
3318 3327           * fit. In this case, we need to drop entries until if fits
3319 3328           * and patch the counts in order that the next readdir will
3320 3329           * get the correct entries.
3321 3330           */
3322 3331          ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3323 3332          data = nfscmd_convdirent(ca, exi, data, count, &resp->status);
3324 3333  
3325 3334  
3326 3335          VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3327 3336  
3328 3337  #if 0 /* notyet */
3329 3338          /*
3330 3339           * Don't do this.  It causes local disk writes when just
3331 3340           * reading the file and the overhead is deemed larger
3332 3341           * than the benefit.
3333 3342           */
3334 3343          /*
3335 3344           * Force modified metadata out to stable storage.
3336 3345           */
3337 3346          (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3338 3347  #endif
3339 3348  
3340 3349          resp->status = NFS3_OK;
3341 3350          vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
3342 3351          resp->resok.cookieverf = 0;
3343 3352          resp->resok.reply.entries = (entry3 *)data;
3344 3353          resp->resok.reply.eof = iseof;
3345 3354          resp->resok.size = count - uio.uio_resid;
3346 3355          resp->resok.count = args->count;
3347 3356          resp->resok.freecount = count;
3348 3357  
3349 3358          DTRACE_NFSV3_5(op__readdir__done, struct svc_req *, req,
3350 3359              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3351 3360              READDIR3res *, resp);
3352 3361  
3353 3362          VN_RELE(vp);
3354 3363  
3355 3364          return;
3356 3365  
3357 3366  out:
3358 3367          if (curthread->t_flag & T_WOULDBLOCK) {
3359 3368                  curthread->t_flag &= ~T_WOULDBLOCK;
3360 3369                  resp->status = NFS3ERR_JUKEBOX;
3361 3370          } else
3362 3371                  resp->status = puterrno3(error);
3363 3372  out1:
3364 3373          vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3365 3374  
3366 3375          DTRACE_NFSV3_5(op__readdir__done, struct svc_req *, req,
3367 3376              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3368 3377              READDIR3res *, resp);
3369 3378  
3370 3379          if (vp != NULL) {
3371 3380                  VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3372 3381                  VN_RELE(vp);
3373 3382          }
3374 3383          vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3375 3384  }
3376 3385  
3377 3386  void *
3378 3387  rfs3_readdir_getfh(READDIR3args *args)
3379 3388  {
3380 3389  
3381 3390          return (&args->dir);
3382 3391  }
3383 3392  
3384 3393  void
3385 3394  rfs3_readdir_free(READDIR3res *resp)
3386 3395  {
3387 3396  
3388 3397          if (resp->status == NFS3_OK)
3389 3398                  kmem_free(resp->resok.reply.entries, resp->resok.freecount);
3390 3399  }
3391 3400  
3392 3401  #ifdef nextdp
3393 3402  #undef nextdp
3394 3403  #endif
3395 3404  #define nextdp(dp)      ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
3396 3405  
3397 3406  /*
3398 3407   * This macro computes the size of a response which contains
3399 3408   * one directory entry including the attributes as well as file handle.
3400 3409   * If the incoming request is larger than this, then we are guaranteed to be
3401 3410   * able to return at least one more directory entry if one exists.
3402 3411   *
3403 3412   * NFS3_READDIRPLUS_ENTRY is made up of the following:
3404 3413   *
3405 3414   * boolean - 1 * BYTES_PER_XDR_UNIT
3406 3415   * file id - 2 * BYTES_PER_XDR_UNIT
3407 3416   * directory name length - 1 * BYTES_PER_XDR_UNIT
3408 3417   * cookie - 2 * BYTES_PER_XDR_UNIT
3409 3418   * attribute flag - 1 * BYTES_PER_XDR_UNIT
3410 3419   * attributes - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT
3411 3420   * status byte for file handle - 1 *  BYTES_PER_XDR_UNIT
3412 3421   * length of a file handle - 1 * BYTES_PER_XDR_UNIT
3413 3422   * Maximum length of a file handle (NFS3_MAXFHSIZE)
3414 3423   * name length of the entry to the nearest bytes
3415 3424   */
3416 3425  #define NFS3_READDIRPLUS_ENTRY(namelen) \
3417 3426          ((1 + 2 + 1 + 2 + 1 + NFS3_SIZEOF_FATTR3 + 1 + 1) * \
3418 3427                  BYTES_PER_XDR_UNIT + \
3419 3428          NFS3_MAXFHSIZE + roundup(namelen, BYTES_PER_XDR_UNIT))
3420 3429  
3421 3430  static int rfs3_readdir_unit = MAXBSIZE;
3422 3431  
3423 3432  /* ARGSUSED */
3424 3433  void
3425 3434  rfs3_readdirplus(READDIRPLUS3args *args, READDIRPLUS3res *resp,
3426 3435      struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro)
3427 3436  {
3428 3437          int error;
3429 3438          vnode_t *vp;
3430 3439          struct vattr *vap;
3431 3440          struct vattr va;
3432 3441          struct iovec iov;
3433 3442          struct uio uio;
3434 3443          char *data;
3435 3444          int iseof;
3436 3445          struct dirent64 *dp;
3437 3446          vnode_t *nvp;
3438 3447          struct vattr *nvap;
3439 3448          struct vattr nva;
3440 3449          entryplus3_info *infop = NULL;
3441 3450          int size = 0;
3442 3451          int nents = 0;
3443 3452          int bufsize = 0;
3444 3453          int entrysize = 0;
3445 3454          int tofit = 0;
3446 3455          int rd_unit = rfs3_readdir_unit;
3447 3456          int prev_len;
3448 3457          int space_left;
3449 3458          int i;
3450 3459          uint_t *namlen = NULL;
3451 3460          char *ndata = NULL;
3452 3461          struct sockaddr *ca;
3453 3462          size_t ret;
3454 3463  
3455 3464          vap = NULL;
3456 3465  
3457 3466          vp = nfs3_fhtovp(&args->dir, exi);
3458 3467  
3459 3468          DTRACE_NFSV3_5(op__readdirplus__start, struct svc_req *, req,
3460 3469              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3461 3470              READDIRPLUS3args *, args);
3462 3471  
3463 3472          if (vp == NULL) {
3464 3473                  error = ESTALE;
3465 3474                  goto out;
3466 3475          }
3467 3476  
3468 3477          if (is_system_labeled()) {
3469 3478                  bslabel_t *clabel = req->rq_label;
3470 3479  
3471 3480                  ASSERT(clabel != NULL);
3472 3481                  DTRACE_PROBE2(tx__rfs3__log__info__opreaddirplus__clabel,
3473 3482                      char *, "got client label from request(1)",
3474 3483                      struct svc_req *, req);
3475 3484  
3476 3485                  if (!blequal(&l_admin_low->tsl_label, clabel)) {
3477 3486                          if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3478 3487                              exi)) {
3479 3488                                  resp->status = NFS3ERR_ACCES;
3480 3489                                  goto out1;
3481 3490                          }
3482 3491                  }
3483 3492          }
3484 3493  
3485 3494          (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
3486 3495  
3487 3496          va.va_mask = AT_ALL;
3488 3497          vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3489 3498  
3490 3499          if (vp->v_type != VDIR) {
3491 3500                  error = ENOTDIR;
3492 3501                  goto out;
3493 3502          }
3494 3503  
3495 3504          error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
3496 3505          if (error)
3497 3506                  goto out;
3498 3507  
3499 3508          /*
3500 3509           * Don't allow arbitrary counts for allocation
3501 3510           */
3502 3511          if (args->maxcount > rfs3_tsize(req))
3503 3512                  args->maxcount = rfs3_tsize(req);
3504 3513  
3505 3514          /*
3506 3515           * Make sure that there is room to read at least one entry
3507 3516           * if any are available
3508 3517           */
3509 3518          args->dircount = MIN(args->dircount, args->maxcount);
3510 3519  
3511 3520          if (args->dircount < DIRENT64_RECLEN(MAXNAMELEN))
3512 3521                  args->dircount = DIRENT64_RECLEN(MAXNAMELEN);
3513 3522  
3514 3523          /*
3515 3524           * This allocation relies on a minimum directory entry
3516 3525           * being roughly 24 bytes.  Therefore, the namlen array
3517 3526           * will have enough space based on the maximum number of
3518 3527           * entries to read.
3519 3528           */
3520 3529          namlen = kmem_alloc(args->dircount, KM_SLEEP);
3521 3530  
3522 3531          space_left = args->dircount;
3523 3532          data = kmem_alloc(args->dircount, KM_SLEEP);
3524 3533          dp = (struct dirent64 *)data;
3525 3534          uio.uio_iov = &iov;
3526 3535          uio.uio_iovcnt = 1;
3527 3536          uio.uio_segflg = UIO_SYSSPACE;
3528 3537          uio.uio_extflg = UIO_COPY_CACHED;
3529 3538          uio.uio_loffset = (offset_t)args->cookie;
3530 3539  
3531 3540          /*
3532 3541           * bufsize is used to keep track of the size of the response as we
3533 3542           * get post op attributes and filehandles for each entry.  This is
3534 3543           * an optimization as the server may have read more entries than will
3535 3544           * fit in the buffer specified by maxcount.  We stop calculating
3536 3545           * post op attributes and filehandles once we have exceeded maxcount.
3537 3546           * This will minimize the effect of truncation.
3538 3547           *
3539 3548           * It is primed with:
3540 3549           *      1 for the status +
3541 3550           *      1 for the dir_attributes.attributes boolean +
3542 3551           *      2 for the cookie verifier
3543 3552           * all times BYTES_PER_XDR_UNIT to convert from XDR units
3544 3553           * to bytes.  If there are directory attributes to be
3545 3554           * returned, then:
3546 3555           *      NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3
3547 3556           * time BYTES_PER_XDR_UNIT is added to account for them.
3548 3557           */
3549 3558          bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT;
3550 3559          if (vap != NULL)
3551 3560                  bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT;
3552 3561  
3553 3562  getmoredents:
3554 3563          /*
3555 3564           * Here we make a check so that our read unit is not larger than
3556 3565           * the space left in the buffer.
3557 3566           */
3558 3567          rd_unit = MIN(rd_unit, space_left);
3559 3568          iov.iov_base = (char *)dp;
3560 3569          iov.iov_len = rd_unit;
3561 3570          uio.uio_resid = rd_unit;
3562 3571          prev_len = rd_unit;
3563 3572  
3564 3573          error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
3565 3574  
3566 3575          if (error) {
3567 3576                  kmem_free(data, args->dircount);
3568 3577                  goto out;
3569 3578          }
3570 3579  
3571 3580          if (uio.uio_resid == prev_len && !iseof) {
3572 3581                  if (nents == 0) {
3573 3582                          kmem_free(data, args->dircount);
3574 3583                          resp->status = NFS3ERR_TOOSMALL;
3575 3584                          goto out1;
3576 3585                  }
3577 3586  
3578 3587                  /*
3579 3588                   * We could not get any more entries, so get the attributes
3580 3589                   * and filehandle for the entries already obtained.
3581 3590                   */
3582 3591                  goto good;
3583 3592          }
3584 3593  
3585 3594          /*
3586 3595           * We estimate the size of the response by assuming the
3587 3596           * entry exists and attributes and filehandle are also valid
3588 3597           */
3589 3598          for (size = prev_len - uio.uio_resid;
3590 3599              size > 0;
3591 3600              size -= dp->d_reclen, dp = nextdp(dp)) {
3592 3601  
3593 3602                  if (dp->d_ino == 0) {
3594 3603                          nents++;
3595 3604                          continue;
3596 3605                  }
3597 3606  
3598 3607                  namlen[nents] = strlen(dp->d_name);
3599 3608                  entrysize = NFS3_READDIRPLUS_ENTRY(namlen[nents]);
3600 3609  
3601 3610                  /*
3602 3611                   * We need to check to see if the number of bytes left
3603 3612                   * to go into the buffer will actually fit into the
3604 3613                   * buffer.  This is calculated as the size of this
3605 3614                   * entry plus:
3606 3615                   *      1 for the true/false list indicator +
3607 3616                   *      1 for the eof indicator
3608 3617                   * times BYTES_PER_XDR_UNIT to convert from XDR units
3609 3618                   * to bytes.
3610 3619                   *
3611 3620                   * Also check the dircount limit against the first entry read
3612 3621                   *
3613 3622                   */
3614 3623                  tofit = entrysize + (1 + 1) * BYTES_PER_XDR_UNIT;
3615 3624                  if (bufsize + tofit > args->maxcount) {
3616 3625                          /*
3617 3626                           * We make a check here to see if this was the
3618 3627                           * first entry being measured.  If so, then maxcount
3619 3628                           * was too small to begin with and so we need to
3620 3629                           * return with NFS3ERR_TOOSMALL.
3621 3630                           */
3622 3631                          if (nents == 0) {
3623 3632                                  kmem_free(data, args->dircount);
3624 3633                                  resp->status = NFS3ERR_TOOSMALL;
3625 3634                                  goto out1;
3626 3635                          }
3627 3636                          iseof = FALSE;
3628 3637                          goto good;
3629 3638                  }
3630 3639                  bufsize += entrysize;
3631 3640                  nents++;
3632 3641          }
3633 3642  
3634 3643          /*
3635 3644           * If there is enough room to fit at least 1 more entry including
3636 3645           * post op attributes and filehandle in the buffer AND that we haven't
3637 3646           * exceeded dircount then go back and get some more.
3638 3647           */
3639 3648          if (!iseof &&
3640 3649              (args->maxcount - bufsize) >= NFS3_READDIRPLUS_ENTRY(MAXNAMELEN)) {
3641 3650                  space_left -= (prev_len - uio.uio_resid);
3642 3651                  if (space_left >= DIRENT64_RECLEN(MAXNAMELEN))
3643 3652                          goto getmoredents;
3644 3653  
3645 3654                  /* else, fall through */
3646 3655          }
3647 3656  good:
3648 3657          va.va_mask = AT_ALL;
3649 3658          vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3650 3659  
3651 3660          VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3652 3661  
3653 3662          infop = kmem_alloc(nents * sizeof (struct entryplus3_info), KM_SLEEP);
3654 3663          resp->resok.infop = infop;
3655 3664  
3656 3665          dp = (struct dirent64 *)data;
3657 3666          for (i = 0; i < nents; i++) {
3658 3667  
3659 3668                  if (dp->d_ino == 0) {
3660 3669                          infop[i].attr.attributes = FALSE;
3661 3670                          infop[i].fh.handle_follows = FALSE;
3662 3671                          dp = nextdp(dp);
3663 3672                          continue;
3664 3673                  }
3665 3674  
3666 3675                  infop[i].namelen = namlen[i];
3667 3676  
3668 3677                  error = VOP_LOOKUP(vp, dp->d_name, &nvp, NULL, 0, NULL, cr,
3669 3678                      NULL, NULL, NULL);
3670 3679                  if (error) {
3671 3680                          infop[i].attr.attributes = FALSE;
3672 3681                          infop[i].fh.handle_follows = FALSE;
3673 3682                          dp = nextdp(dp);
3674 3683                          continue;
3675 3684                  }
3676 3685  
3677 3686                  nva.va_mask = AT_ALL;
3678 3687                  nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ? NULL : &nva;
3679 3688  
3680 3689                  /* Lie about the object type for a referral */
3681 3690                  if (vn_is_nfs_reparse(nvp, cr))
3682 3691                          nvap->va_type = VLNK;
3683 3692  
3684 3693                  if (vn_ismntpt(nvp)) {
3685 3694                          infop[i].attr.attributes = FALSE;
3686 3695                          infop[i].fh.handle_follows = FALSE;
3687 3696                  } else {
3688 3697                          vattr_to_post_op_attr(nvap, &infop[i].attr);
3689 3698  
3690 3699                          error = makefh3(&infop[i].fh.handle, nvp, exi);
3691 3700                          if (!error)
3692 3701                                  infop[i].fh.handle_follows = TRUE;
3693 3702                          else
3694 3703                                  infop[i].fh.handle_follows = FALSE;
3695 3704                  }
3696 3705  
3697 3706                  VN_RELE(nvp);
3698 3707                  dp = nextdp(dp);
3699 3708          }
3700 3709  
3701 3710          ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3702 3711          ret = nfscmd_convdirplus(ca, exi, data, nents, args->dircount, &ndata);
3703 3712          if (ndata == NULL)
3704 3713                  ndata = data;
3705 3714  
3706 3715          if (ret > 0) {
3707 3716                  /*
3708 3717                   * We had to drop one or more entries in order to fit
3709 3718                   * during the character conversion.  We need to patch
3710 3719                   * up the size and eof info.
3711 3720                   */
3712 3721                  if (iseof)
3713 3722                          iseof = FALSE;
3714 3723  
3715 3724                  ret = nfscmd_dropped_entrysize((struct dirent64 *)data,
3716 3725                      nents, ret);
3717 3726          }
3718 3727  
3719 3728  
3720 3729  #if 0 /* notyet */
3721 3730          /*
3722 3731           * Don't do this.  It causes local disk writes when just
3723 3732           * reading the file and the overhead is deemed larger
3724 3733           * than the benefit.
3725 3734           */
3726 3735          /*
3727 3736           * Force modified metadata out to stable storage.
3728 3737           */
3729 3738          (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3730 3739  #endif
3731 3740  
3732 3741          kmem_free(namlen, args->dircount);
3733 3742  
3734 3743          resp->status = NFS3_OK;
3735 3744          vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
3736 3745          resp->resok.cookieverf = 0;
3737 3746          resp->resok.reply.entries = (entryplus3 *)ndata;
3738 3747          resp->resok.reply.eof = iseof;
3739 3748          resp->resok.size = nents;
3740 3749          resp->resok.count = args->dircount - ret;
3741 3750          resp->resok.maxcount = args->maxcount;
3742 3751  
3743 3752          DTRACE_NFSV3_5(op__readdirplus__done, struct svc_req *, req,
3744 3753              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3745 3754              READDIRPLUS3res *, resp);
3746 3755  
3747 3756          VN_RELE(vp);
3748 3757  
3749 3758          return;
3750 3759  
3751 3760  out:
3752 3761          if (curthread->t_flag & T_WOULDBLOCK) {
3753 3762                  curthread->t_flag &= ~T_WOULDBLOCK;
3754 3763                  resp->status = NFS3ERR_JUKEBOX;
3755 3764          } else {
3756 3765                  resp->status = puterrno3(error);
3757 3766          }
3758 3767  out1:
3759 3768          vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3760 3769  
3761 3770          DTRACE_NFSV3_5(op__readdirplus__done, struct svc_req *, req,
3762 3771              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3763 3772              READDIRPLUS3res *, resp);
3764 3773  
3765 3774          if (vp != NULL) {
3766 3775                  VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3767 3776                  VN_RELE(vp);
3768 3777          }
3769 3778  
3770 3779          if (namlen != NULL)
3771 3780                  kmem_free(namlen, args->dircount);
3772 3781  
3773 3782          vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3774 3783  }
3775 3784  
3776 3785  void *
3777 3786  rfs3_readdirplus_getfh(READDIRPLUS3args *args)
3778 3787  {
3779 3788  
3780 3789          return (&args->dir);
3781 3790  }
3782 3791  
3783 3792  void
3784 3793  rfs3_readdirplus_free(READDIRPLUS3res *resp)
3785 3794  {
3786 3795  
3787 3796          if (resp->status == NFS3_OK) {
3788 3797                  kmem_free(resp->resok.reply.entries, resp->resok.count);
3789 3798                  kmem_free(resp->resok.infop,
3790 3799                      resp->resok.size * sizeof (struct entryplus3_info));
3791 3800          }
3792 3801  }
3793 3802  
3794 3803  /* ARGSUSED */
3795 3804  void
3796 3805  rfs3_fsstat(FSSTAT3args *args, FSSTAT3res *resp, struct exportinfo *exi,
3797 3806      struct svc_req *req, cred_t *cr, bool_t ro)
3798 3807  {
3799 3808          int error;
3800 3809          vnode_t *vp;
3801 3810          struct vattr *vap;
3802 3811          struct vattr va;
3803 3812          struct statvfs64 sb;
3804 3813  
3805 3814          vap = NULL;
3806 3815  
3807 3816          vp = nfs3_fhtovp(&args->fsroot, exi);
3808 3817  
3809 3818          DTRACE_NFSV3_5(op__fsstat__start, struct svc_req *, req,
3810 3819              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3811 3820              FSSTAT3args *, args);
3812 3821  
3813 3822          if (vp == NULL) {
3814 3823                  error = ESTALE;
3815 3824                  goto out;
3816 3825          }
3817 3826  
3818 3827          if (is_system_labeled()) {
3819 3828                  bslabel_t *clabel = req->rq_label;
3820 3829  
3821 3830                  ASSERT(clabel != NULL);
3822 3831                  DTRACE_PROBE2(tx__rfs3__log__info__opfsstat__clabel, char *,
3823 3832                      "got client label from request(1)", struct svc_req *, req);
3824 3833  
3825 3834                  if (!blequal(&l_admin_low->tsl_label, clabel)) {
3826 3835                          if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3827 3836                              exi)) {
3828 3837                                  resp->status = NFS3ERR_ACCES;
3829 3838                                  goto out1;
3830 3839                          }
3831 3840                  }
3832 3841          }
3833 3842  
3834 3843          error = VFS_STATVFS(vp->v_vfsp, &sb);
3835 3844  
3836 3845          va.va_mask = AT_ALL;
3837 3846          vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3838 3847  
3839 3848          if (error)
3840 3849                  goto out;
3841 3850  
3842 3851          resp->status = NFS3_OK;
3843 3852          vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
3844 3853          if (sb.f_blocks != (fsblkcnt64_t)-1)
3845 3854                  resp->resok.tbytes = (size3)sb.f_frsize * (size3)sb.f_blocks;
3846 3855          else
3847 3856                  resp->resok.tbytes = (size3)sb.f_blocks;
3848 3857          if (sb.f_bfree != (fsblkcnt64_t)-1)
3849 3858                  resp->resok.fbytes = (size3)sb.f_frsize * (size3)sb.f_bfree;
3850 3859          else
3851 3860                  resp->resok.fbytes = (size3)sb.f_bfree;
3852 3861          if (sb.f_bavail != (fsblkcnt64_t)-1)
3853 3862                  resp->resok.abytes = (size3)sb.f_frsize * (size3)sb.f_bavail;
3854 3863          else
3855 3864                  resp->resok.abytes = (size3)sb.f_bavail;
3856 3865          resp->resok.tfiles = (size3)sb.f_files;
3857 3866          resp->resok.ffiles = (size3)sb.f_ffree;
3858 3867          resp->resok.afiles = (size3)sb.f_favail;
3859 3868          resp->resok.invarsec = 0;
3860 3869  
3861 3870          DTRACE_NFSV3_5(op__fsstat__done, struct svc_req *, req,
3862 3871              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3863 3872              FSSTAT3res *, resp);
3864 3873          VN_RELE(vp);
3865 3874  
3866 3875          return;
3867 3876  
3868 3877  out:
3869 3878          if (curthread->t_flag & T_WOULDBLOCK) {
3870 3879                  curthread->t_flag &= ~T_WOULDBLOCK;
3871 3880                  resp->status = NFS3ERR_JUKEBOX;
3872 3881          } else
3873 3882                  resp->status = puterrno3(error);
3874 3883  out1:
3875 3884          DTRACE_NFSV3_5(op__fsstat__done, struct svc_req *, req,
3876 3885              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3877 3886              FSSTAT3res *, resp);
3878 3887  
3879 3888          if (vp != NULL)
3880 3889                  VN_RELE(vp);
3881 3890          vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
3882 3891  }
3883 3892  
3884 3893  void *
3885 3894  rfs3_fsstat_getfh(FSSTAT3args *args)
3886 3895  {
3887 3896  
3888 3897          return (&args->fsroot);
3889 3898  }
3890 3899  
3891 3900  /* ARGSUSED */
3892 3901  void
3893 3902  rfs3_fsinfo(FSINFO3args *args, FSINFO3res *resp, struct exportinfo *exi,
3894 3903      struct svc_req *req, cred_t *cr, bool_t ro)
3895 3904  {
3896 3905          vnode_t *vp;
3897 3906          struct vattr *vap;
3898 3907          struct vattr va;
3899 3908          uint32_t xfer_size;
3900 3909          ulong_t l = 0;
3901 3910          int error;
3902 3911  
3903 3912          vp = nfs3_fhtovp(&args->fsroot, exi);
3904 3913  
3905 3914          DTRACE_NFSV3_5(op__fsinfo__start, struct svc_req *, req,
3906 3915              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3907 3916              FSINFO3args *, args);
3908 3917  
3909 3918          if (vp == NULL) {
3910 3919                  if (curthread->t_flag & T_WOULDBLOCK) {
3911 3920                          curthread->t_flag &= ~T_WOULDBLOCK;
3912 3921                          resp->status = NFS3ERR_JUKEBOX;
3913 3922                  } else
3914 3923                          resp->status = NFS3ERR_STALE;
3915 3924                  vattr_to_post_op_attr(NULL, &resp->resfail.obj_attributes);
3916 3925                  goto out;
3917 3926          }
3918 3927  
3919 3928          if (is_system_labeled()) {
3920 3929                  bslabel_t *clabel = req->rq_label;
3921 3930  
3922 3931                  ASSERT(clabel != NULL);
3923 3932                  DTRACE_PROBE2(tx__rfs3__log__info__opfsinfo__clabel, char *,
3924 3933                      "got client label from request(1)", struct svc_req *, req);
3925 3934  
3926 3935                  if (!blequal(&l_admin_low->tsl_label, clabel)) {
3927 3936                          if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3928 3937                              exi)) {
3929 3938                                  resp->status = NFS3ERR_STALE;
3930 3939                                  vattr_to_post_op_attr(NULL,
3931 3940                                      &resp->resfail.obj_attributes);
3932 3941                                  goto out;
3933 3942                          }
3934 3943                  }
3935 3944          }
3936 3945  
3937 3946          va.va_mask = AT_ALL;
3938 3947          vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3939 3948  
3940 3949          resp->status = NFS3_OK;
3941 3950          vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
3942 3951          xfer_size = rfs3_tsize(req);
3943 3952          resp->resok.rtmax = xfer_size;
3944 3953          resp->resok.rtpref = xfer_size;
3945 3954          resp->resok.rtmult = DEV_BSIZE;
3946 3955          resp->resok.wtmax = xfer_size;
3947 3956          resp->resok.wtpref = xfer_size;
3948 3957          resp->resok.wtmult = DEV_BSIZE;
3949 3958          resp->resok.dtpref = MAXBSIZE;
3950 3959  
3951 3960          /*
3952 3961           * Large file spec: want maxfilesize based on limit of
3953 3962           * underlying filesystem.  We can guess 2^31-1 if need be.
3954 3963           */
3955 3964          error = VOP_PATHCONF(vp, _PC_FILESIZEBITS, &l, cr, NULL);
3956 3965          if (error) {
3957 3966                  resp->status = puterrno3(error);
3958 3967                  goto out;
3959 3968          }
3960 3969  
3961 3970          /*
3962 3971           * If the underlying file system does not support _PC_FILESIZEBITS,
3963 3972           * return a reasonable default. Note that error code on VOP_PATHCONF
3964 3973           * will be 0, even if the underlying file system does not support
3965 3974           * _PC_FILESIZEBITS.
3966 3975           */
3967 3976          if (l == (ulong_t)-1) {
3968 3977                  resp->resok.maxfilesize = MAXOFF32_T;
3969 3978          } else {
3970 3979                  if (l >= (sizeof (uint64_t) * 8))
3971 3980                          resp->resok.maxfilesize = INT64_MAX;
3972 3981                  else
3973 3982                          resp->resok.maxfilesize = (1LL << (l-1)) - 1;
3974 3983          }
3975 3984  
3976 3985          resp->resok.time_delta.seconds = 0;
3977 3986          resp->resok.time_delta.nseconds = 1000;
3978 3987          resp->resok.properties = FSF3_LINK | FSF3_SYMLINK |
3979 3988              FSF3_HOMOGENEOUS | FSF3_CANSETTIME;
3980 3989  
3981 3990          DTRACE_NFSV3_5(op__fsinfo__done, struct svc_req *, req,
3982 3991              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3983 3992              FSINFO3res *, resp);
3984 3993  
3985 3994          VN_RELE(vp);
3986 3995  
3987 3996          return;
3988 3997  
3989 3998  out:
3990 3999          DTRACE_NFSV3_5(op__fsinfo__done, struct svc_req *, req,
3991 4000              cred_t *, cr, vnode_t *, NULL, struct exportinfo *, exi,
3992 4001              FSINFO3res *, resp);
3993 4002          if (vp != NULL)
3994 4003                  VN_RELE(vp);
3995 4004  }
3996 4005  
3997 4006  void *
3998 4007  rfs3_fsinfo_getfh(FSINFO3args *args)
3999 4008  {
4000 4009          return (&args->fsroot);
4001 4010  }
4002 4011  
4003 4012  /* ARGSUSED */
4004 4013  void
4005 4014  rfs3_pathconf(PATHCONF3args *args, PATHCONF3res *resp, struct exportinfo *exi,
4006 4015      struct svc_req *req, cred_t *cr, bool_t ro)
4007 4016  {
4008 4017          int error;
4009 4018          vnode_t *vp;
4010 4019          struct vattr *vap;
4011 4020          struct vattr va;
4012 4021          ulong_t val;
4013 4022  
4014 4023          vap = NULL;
4015 4024  
4016 4025          vp = nfs3_fhtovp(&args->object, exi);
4017 4026  
4018 4027          DTRACE_NFSV3_5(op__pathconf__start, struct svc_req *, req,
4019 4028              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4020 4029              PATHCONF3args *, args);
4021 4030  
4022 4031          if (vp == NULL) {
4023 4032                  error = ESTALE;
4024 4033                  goto out;
4025 4034          }
4026 4035  
4027 4036          if (is_system_labeled()) {
4028 4037                  bslabel_t *clabel = req->rq_label;
4029 4038  
4030 4039                  ASSERT(clabel != NULL);
4031 4040                  DTRACE_PROBE2(tx__rfs3__log__info__oppathconf__clabel, char *,
4032 4041                      "got client label from request(1)", struct svc_req *, req);
4033 4042  
4034 4043                  if (!blequal(&l_admin_low->tsl_label, clabel)) {
4035 4044                          if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
4036 4045                              exi)) {
4037 4046                                  resp->status = NFS3ERR_ACCES;
4038 4047                                  goto out1;
4039 4048                          }
4040 4049                  }
4041 4050          }
4042 4051  
4043 4052          va.va_mask = AT_ALL;
4044 4053          vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
4045 4054  
4046 4055          error = VOP_PATHCONF(vp, _PC_LINK_MAX, &val, cr, NULL);
4047 4056          if (error)
4048 4057                  goto out;
4049 4058          resp->resok.info.link_max = (uint32)val;
4050 4059  
4051 4060          error = VOP_PATHCONF(vp, _PC_NAME_MAX, &val, cr, NULL);
4052 4061          if (error)
4053 4062                  goto out;
4054 4063          resp->resok.info.name_max = (uint32)val;
4055 4064  
4056 4065          error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &val, cr, NULL);
4057 4066          if (error)
4058 4067                  goto out;
4059 4068          if (val == 1)
4060 4069                  resp->resok.info.no_trunc = TRUE;
4061 4070          else
4062 4071                  resp->resok.info.no_trunc = FALSE;
4063 4072  
4064 4073          error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &val, cr, NULL);
4065 4074          if (error)
4066 4075                  goto out;
4067 4076          if (val == 1)
4068 4077                  resp->resok.info.chown_restricted = TRUE;
4069 4078          else
4070 4079                  resp->resok.info.chown_restricted = FALSE;
4071 4080  
4072 4081          resp->status = NFS3_OK;
4073 4082          vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
4074 4083          resp->resok.info.case_insensitive = FALSE;
4075 4084          resp->resok.info.case_preserving = TRUE;
4076 4085          DTRACE_NFSV3_5(op__pathconf__done, struct svc_req *, req,
4077 4086              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4078 4087              PATHCONF3res *, resp);
4079 4088          VN_RELE(vp);
4080 4089          return;
4081 4090  
4082 4091  out:
4083 4092          if (curthread->t_flag & T_WOULDBLOCK) {
4084 4093                  curthread->t_flag &= ~T_WOULDBLOCK;
4085 4094                  resp->status = NFS3ERR_JUKEBOX;
4086 4095          } else
4087 4096                  resp->status = puterrno3(error);
4088 4097  out1:
4089 4098          DTRACE_NFSV3_5(op__pathconf__done, struct svc_req *, req,
4090 4099              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4091 4100              PATHCONF3res *, resp);
4092 4101          if (vp != NULL)
4093 4102                  VN_RELE(vp);
4094 4103          vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
4095 4104  }
4096 4105  
4097 4106  void *
4098 4107  rfs3_pathconf_getfh(PATHCONF3args *args)
4099 4108  {
4100 4109  
4101 4110          return (&args->object);
4102 4111  }
4103 4112  
4104 4113  void
4105 4114  rfs3_commit(COMMIT3args *args, COMMIT3res *resp, struct exportinfo *exi,
4106 4115      struct svc_req *req, cred_t *cr, bool_t ro)
4107 4116  {
4108 4117          nfs3_srv_t *ns;
4109 4118          int error;
4110 4119          vnode_t *vp;
4111 4120          struct vattr *bvap;
4112 4121          struct vattr bva;
4113 4122          struct vattr *avap;
4114 4123          struct vattr ava;
4115 4124  
4116 4125          bvap = NULL;
4117 4126          avap = NULL;
4118 4127  
4119 4128          vp = nfs3_fhtovp(&args->file, exi);
4120 4129  
  
    | 
      ↓ open down ↓ | 
    2780 lines elided | 
    
      ↑ open up ↑ | 
  
4121 4130          DTRACE_NFSV3_5(op__commit__start, struct svc_req *, req,
4122 4131              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4123 4132              COMMIT3args *, args);
4124 4133  
4125 4134          if (vp == NULL) {
4126 4135                  error = ESTALE;
4127 4136                  goto out;
4128 4137          }
4129 4138  
4130 4139          ASSERT3P(curzone, ==, exi->exi_zone); /* exi is guaranteed non-NULL. */
4131      -        ns = zone_getspecific(rfs3_zone_key, curzone);
     4140 +        ns = nfs3_get_srv();
4132 4141          bva.va_mask = AT_ALL;
4133 4142          error = VOP_GETATTR(vp, &bva, 0, cr, NULL);
4134 4143  
4135 4144          /*
4136 4145           * If we can't get the attributes, then we can't do the
4137 4146           * right access checking.  So, we'll fail the request.
4138 4147           */
4139 4148          if (error)
4140 4149                  goto out;
4141 4150  
4142 4151          bvap = &bva;
4143 4152  
4144 4153          if (rdonly(ro, vp)) {
4145 4154                  resp->status = NFS3ERR_ROFS;
4146 4155                  goto out1;
4147 4156          }
4148 4157  
4149 4158          if (vp->v_type != VREG) {
4150 4159                  resp->status = NFS3ERR_INVAL;
4151 4160                  goto out1;
4152 4161          }
4153 4162  
4154 4163          if (is_system_labeled()) {
4155 4164                  bslabel_t *clabel = req->rq_label;
4156 4165  
4157 4166                  ASSERT(clabel != NULL);
4158 4167                  DTRACE_PROBE2(tx__rfs3__log__info__opcommit__clabel, char *,
4159 4168                      "got client label from request(1)", struct svc_req *, req);
4160 4169  
4161 4170                  if (!blequal(&l_admin_low->tsl_label, clabel)) {
4162 4171                          if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
4163 4172                              exi)) {
4164 4173                                  resp->status = NFS3ERR_ACCES;
4165 4174                                  goto out1;
4166 4175                          }
4167 4176                  }
4168 4177          }
4169 4178  
4170 4179          if (crgetuid(cr) != bva.va_uid &&
4171 4180              (error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL)))
4172 4181                  goto out;
4173 4182  
4174 4183          error = VOP_FSYNC(vp, FSYNC, cr, NULL);
4175 4184  
4176 4185          ava.va_mask = AT_ALL;
4177 4186          avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
4178 4187  
4179 4188          if (error)
4180 4189                  goto out;
4181 4190  
4182 4191          resp->status = NFS3_OK;
4183 4192          vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
4184 4193          resp->resok.verf = ns->write3verf;
4185 4194  
4186 4195          DTRACE_NFSV3_5(op__commit__done, struct svc_req *, req,
4187 4196              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4188 4197              COMMIT3res *, resp);
4189 4198  
4190 4199          VN_RELE(vp);
4191 4200  
4192 4201          return;
4193 4202  
4194 4203  out:
4195 4204          if (curthread->t_flag & T_WOULDBLOCK) {
4196 4205                  curthread->t_flag &= ~T_WOULDBLOCK;
4197 4206                  resp->status = NFS3ERR_JUKEBOX;
4198 4207          } else
4199 4208                  resp->status = puterrno3(error);
4200 4209  out1:
4201 4210          DTRACE_NFSV3_5(op__commit__done, struct svc_req *, req,
4202 4211              cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4203 4212              COMMIT3res *, resp);
4204 4213  
4205 4214          if (vp != NULL)
4206 4215                  VN_RELE(vp);
4207 4216          vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
4208 4217  }
4209 4218  
4210 4219  void *
4211 4220  rfs3_commit_getfh(COMMIT3args *args)
4212 4221  {
4213 4222  
4214 4223          return (&args->file);
4215 4224  }
4216 4225  
4217 4226  static int
4218 4227  sattr3_to_vattr(sattr3 *sap, struct vattr *vap)
4219 4228  {
4220 4229  
4221 4230          vap->va_mask = 0;
4222 4231  
4223 4232          if (sap->mode.set_it) {
4224 4233                  vap->va_mode = (mode_t)sap->mode.mode;
4225 4234                  vap->va_mask |= AT_MODE;
4226 4235          }
4227 4236          if (sap->uid.set_it) {
4228 4237                  vap->va_uid = (uid_t)sap->uid.uid;
4229 4238                  vap->va_mask |= AT_UID;
4230 4239          }
4231 4240          if (sap->gid.set_it) {
4232 4241                  vap->va_gid = (gid_t)sap->gid.gid;
4233 4242                  vap->va_mask |= AT_GID;
4234 4243          }
4235 4244          if (sap->size.set_it) {
4236 4245                  if (sap->size.size > (size3)((u_longlong_t)-1))
4237 4246                          return (EINVAL);
4238 4247                  vap->va_size = sap->size.size;
4239 4248                  vap->va_mask |= AT_SIZE;
4240 4249          }
4241 4250          if (sap->atime.set_it == SET_TO_CLIENT_TIME) {
4242 4251  #ifndef _LP64
4243 4252                  /* check time validity */
4244 4253                  if (!NFS3_TIME_OK(sap->atime.atime.seconds))
4245 4254                          return (EOVERFLOW);
4246 4255  #endif
4247 4256                  /*
4248 4257                   * nfs protocol defines times as unsigned so don't extend sign,
4249 4258                   * unless sysadmin set nfs_allow_preepoch_time.
4250 4259                   */
4251 4260                  NFS_TIME_T_CONVERT(vap->va_atime.tv_sec,
4252 4261                      sap->atime.atime.seconds);
4253 4262                  vap->va_atime.tv_nsec = (uint32_t)sap->atime.atime.nseconds;
4254 4263                  vap->va_mask |= AT_ATIME;
4255 4264          } else if (sap->atime.set_it == SET_TO_SERVER_TIME) {
4256 4265                  gethrestime(&vap->va_atime);
4257 4266                  vap->va_mask |= AT_ATIME;
4258 4267          }
4259 4268          if (sap->mtime.set_it == SET_TO_CLIENT_TIME) {
4260 4269  #ifndef _LP64
4261 4270                  /* check time validity */
4262 4271                  if (!NFS3_TIME_OK(sap->mtime.mtime.seconds))
4263 4272                          return (EOVERFLOW);
4264 4273  #endif
4265 4274                  /*
4266 4275                   * nfs protocol defines times as unsigned so don't extend sign,
4267 4276                   * unless sysadmin set nfs_allow_preepoch_time.
4268 4277                   */
4269 4278                  NFS_TIME_T_CONVERT(vap->va_mtime.tv_sec,
4270 4279                      sap->mtime.mtime.seconds);
4271 4280                  vap->va_mtime.tv_nsec = (uint32_t)sap->mtime.mtime.nseconds;
4272 4281                  vap->va_mask |= AT_MTIME;
4273 4282          } else if (sap->mtime.set_it == SET_TO_SERVER_TIME) {
4274 4283                  gethrestime(&vap->va_mtime);
4275 4284                  vap->va_mask |= AT_MTIME;
4276 4285          }
4277 4286  
4278 4287          return (0);
4279 4288  }
4280 4289  
4281 4290  static const ftype3 vt_to_nf3[] = {
4282 4291          0, NF3REG, NF3DIR, NF3BLK, NF3CHR, NF3LNK, NF3FIFO, 0, 0, NF3SOCK, 0
4283 4292  };
4284 4293  
4285 4294  static int
4286 4295  vattr_to_fattr3(struct vattr *vap, fattr3 *fap)
4287 4296  {
4288 4297  
4289 4298          ASSERT(vap->va_type >= VNON && vap->va_type <= VBAD);
4290 4299          /* Return error if time or size overflow */
4291 4300          if (! (NFS_VAP_TIME_OK(vap) && NFS3_SIZE_OK(vap->va_size))) {
4292 4301                  return (EOVERFLOW);
4293 4302          }
4294 4303          fap->type = vt_to_nf3[vap->va_type];
4295 4304          fap->mode = (mode3)(vap->va_mode & MODEMASK);
4296 4305          fap->nlink = (uint32)vap->va_nlink;
4297 4306          if (vap->va_uid == UID_NOBODY)
4298 4307                  fap->uid = (uid3)NFS_UID_NOBODY;
4299 4308          else
4300 4309                  fap->uid = (uid3)vap->va_uid;
4301 4310          if (vap->va_gid == GID_NOBODY)
4302 4311                  fap->gid = (gid3)NFS_GID_NOBODY;
4303 4312          else
4304 4313                  fap->gid = (gid3)vap->va_gid;
4305 4314          fap->size = (size3)vap->va_size;
4306 4315          fap->used = (size3)DEV_BSIZE * (size3)vap->va_nblocks;
4307 4316          fap->rdev.specdata1 = (uint32)getmajor(vap->va_rdev);
4308 4317          fap->rdev.specdata2 = (uint32)getminor(vap->va_rdev);
4309 4318          fap->fsid = (uint64)vap->va_fsid;
4310 4319          fap->fileid = (fileid3)vap->va_nodeid;
4311 4320          fap->atime.seconds = vap->va_atime.tv_sec;
4312 4321          fap->atime.nseconds = vap->va_atime.tv_nsec;
4313 4322          fap->mtime.seconds = vap->va_mtime.tv_sec;
4314 4323          fap->mtime.nseconds = vap->va_mtime.tv_nsec;
4315 4324          fap->ctime.seconds = vap->va_ctime.tv_sec;
4316 4325          fap->ctime.nseconds = vap->va_ctime.tv_nsec;
4317 4326          return (0);
4318 4327  }
4319 4328  
4320 4329  static int
4321 4330  vattr_to_wcc_attr(struct vattr *vap, wcc_attr *wccap)
4322 4331  {
4323 4332  
4324 4333          /* Return error if time or size overflow */
4325 4334          if (!(NFS_TIME_T_OK(vap->va_mtime.tv_sec) &&
4326 4335              NFS_TIME_T_OK(vap->va_ctime.tv_sec) &&
4327 4336              NFS3_SIZE_OK(vap->va_size))) {
4328 4337                  return (EOVERFLOW);
4329 4338          }
4330 4339          wccap->size = (size3)vap->va_size;
4331 4340          wccap->mtime.seconds = vap->va_mtime.tv_sec;
4332 4341          wccap->mtime.nseconds = vap->va_mtime.tv_nsec;
4333 4342          wccap->ctime.seconds = vap->va_ctime.tv_sec;
4334 4343          wccap->ctime.nseconds = vap->va_ctime.tv_nsec;
4335 4344          return (0);
4336 4345  }
4337 4346  
4338 4347  static void
4339 4348  vattr_to_pre_op_attr(struct vattr *vap, pre_op_attr *poap)
4340 4349  {
4341 4350  
4342 4351          /* don't return attrs if time overflow */
4343 4352          if ((vap != NULL) && !vattr_to_wcc_attr(vap, &poap->attr)) {
4344 4353                  poap->attributes = TRUE;
4345 4354          } else
4346 4355                  poap->attributes = FALSE;
4347 4356  }
4348 4357  
4349 4358  void
4350 4359  vattr_to_post_op_attr(struct vattr *vap, post_op_attr *poap)
4351 4360  {
4352 4361  
4353 4362          /* don't return attrs if time overflow */
4354 4363          if ((vap != NULL) && !vattr_to_fattr3(vap, &poap->attr)) {
4355 4364                  poap->attributes = TRUE;
4356 4365          } else
4357 4366                  poap->attributes = FALSE;
4358 4367  }
4359 4368  
4360 4369  static void
4361 4370  vattr_to_wcc_data(struct vattr *bvap, struct vattr *avap, wcc_data *wccp)
4362 4371  {
4363 4372          vattr_to_pre_op_attr(bvap, &wccp->before);
4364 4373          vattr_to_post_op_attr(avap, &wccp->after);
4365 4374  }
4366 4375  
4367 4376  static int
4368 4377  rdma_setup_read_data3(READ3args *args, READ3resok *rok)
4369 4378  {
4370 4379          struct clist    *wcl;
4371 4380          int             wlist_len;
4372 4381          count3          count = rok->count;
4373 4382  
  
    | 
      ↓ open down ↓ | 
    232 lines elided | 
    
      ↑ open up ↑ | 
  
4374 4383          wcl = args->wlist;
4375 4384          if (rdma_setup_read_chunks(wcl, count, &wlist_len) == FALSE)
4376 4385                  return (FALSE);
4377 4386  
4378 4387          wcl = args->wlist;
4379 4388          rok->wlist_len = wlist_len;
4380 4389          rok->wlist = wcl;
4381 4390          return (TRUE);
4382 4391  }
4383 4392  
4384      -/* ARGSUSED */
4385      -static void *
4386      -rfs3_zone_init(zoneid_t zoneid)
     4393 +void
     4394 +rfs3_srv_zone_init(nfs_globals_t *ng)
4387 4395  {
4388 4396          nfs3_srv_t *ns;
4389 4397          struct rfs3_verf_overlay {
4390 4398                  uint_t id; /* a "unique" identifier */
4391 4399                  int ts; /* a unique timestamp */
4392 4400          } *verfp;
4393 4401          timestruc_t now;
4394 4402  
4395 4403          ns = kmem_zalloc(sizeof (*ns), KM_SLEEP);
4396 4404  
4397 4405          /*
4398 4406           * The following algorithm attempts to find a unique verifier
4399 4407           * to be used as the write verifier returned from the server
4400 4408           * to the client.  It is important that this verifier change
4401 4409           * whenever the server reboots.  Of secondary importance, it
4402 4410           * is important for the verifier to be unique between two
4403 4411           * different servers.
4404 4412           *
4405 4413           * Thus, an attempt is made to use the system hostid and the
4406 4414           * current time in seconds when the nfssrv kernel module is
4407 4415           * loaded.  It is assumed that an NFS server will not be able
4408 4416           * to boot and then to reboot in less than a second.  If the
4409 4417           * hostid has not been set, then the current high resolution
4410 4418           * time is used.  This will ensure different verifiers each
4411 4419           * time the server reboots and minimize the chances that two
4412 4420           * different servers will have the same verifier.
4413 4421           */
4414 4422  
4415 4423  #ifndef lint
4416 4424          /*
4417 4425           * We ASSERT that this constant logic expression is
4418 4426           * always true because in the past, it wasn't.
4419 4427           */
4420 4428          ASSERT(sizeof (*verfp) <= sizeof (ns->write3verf));
  
    | 
      ↓ open down ↓ | 
    24 lines elided | 
    
      ↑ open up ↑ | 
  
4421 4429  #endif
4422 4430  
4423 4431          gethrestime(&now);
4424 4432          verfp = (struct rfs3_verf_overlay *)&ns->write3verf;
4425 4433          verfp->ts = (int)now.tv_sec;
4426 4434          verfp->id = zone_get_hostid(NULL);
4427 4435  
4428 4436          if (verfp->id == 0)
4429 4437                  verfp->id = (uint_t)now.tv_nsec;
4430 4438  
4431      -        return (ns);
     4439 +        ng->nfs3_srv = ns;
4432 4440  }
4433 4441  
4434      -/* ARGSUSED */
4435      -static void
4436      -rfs3_zone_fini(zoneid_t zoneid, void *data)
     4442 +void
     4443 +rfs3_srv_zone_fini(nfs_globals_t *ng)
4437 4444  {
4438      -        nfs3_srv_t *ns = data;
     4445 +        nfs3_srv_t *ns = ng->nfs3_srv;
4439 4446  
     4447 +        ng->nfs3_srv = NULL;
     4448 +
4440 4449          kmem_free(ns, sizeof (*ns));
4441 4450  }
4442 4451  
4443 4452  void
4444 4453  rfs3_srvrinit(void)
4445 4454  {
4446 4455          nfs3_srv_caller_id = fs_new_caller_id();
4447      -        zone_key_create(&rfs3_zone_key, rfs3_zone_init, NULL, rfs3_zone_fini);
4448 4456  }
4449 4457  
4450 4458  void
4451 4459  rfs3_srvrfini(void)
4452 4460  {
4453 4461          /* Nothing to do */
4454 4462  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX