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