Print this page
NEX-16712 NFS dtrace providers do not support per-share filtering
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Yuri Pankon <yuri.pankov@nexenta.com>
NEX-15279 support NFS server in zone
NEX-15520 online NFS shares cause zoneadm halt to hang in nfs_export_zone_fini
Portions contributed by: Dan Kruchinin dan.kruchinin@nexenta.com
Portions contributed by: Stepan Zastupov stepan.zastupov@gmail.com
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
NEX-9275 Got "bad mutex" panic when run IO to nfs share from clients
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
NEX-3524 CLONE - Port NEX-3505 "wrong authentication" messages with root=@0.0.0.0/0 set, result in loss of client access
Reviewed by: Marcel Telka <marcel.telka@nexenta.com>
NEX-3533 CLONE - Port NEX-3019 NFSv3 writes underneath mounted filesystem to directory
Reviewed by: Dan Fields <dan.fields@nexenta.com>
NEX-3095 Issues related to NFS nohide
Reviewed by: Dan Fields <dan.fields@nexenta.com>
NEX-1128 NFS server: Generic uid and gid remapping for AUTH_SYS
Reviewed by: Jan Kryl <jan.kryl@nexenta.com>
OS-20 share_nfs(1m) charset handling is unreliable
OS-22 Page fault at nfscmd_dropped_entrysize+0x1e()
OS-23 NFSv2/3/4: READDIR responses are inconsistent when charset conversion fails
OS-24 rfs3_readdir(): Issues related to nfscmd_convdirent()
Reviewed by: Jan Kryl <jan.kryl@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
closes #12112 rb3823 - nfs-nohide: lookup("..") for submount should be correct
re #3541 rb11254 - nfs nohide - "nfssrv: need ability to go to submounts for v3 and v2 protocols"

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
↓ 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>
↓ 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;
       94 +static zone_key_t rfs3_zone_key;
  88   95  
  89   96  /* ARGSUSED */
  90   97  void
  91   98  rfs3_getattr(GETATTR3args *args, GETATTR3res *resp, struct exportinfo *exi,
  92   99      struct svc_req *req, cred_t *cr, bool_t ro)
  93  100  {
  94  101          int error;
  95  102          vnode_t *vp;
  96  103          struct vattr va;
  97  104  
  98  105          vp = nfs3_fhtovp(&args->object, exi);
  99  106  
 100      -        DTRACE_NFSV3_4(op__getattr__start, struct svc_req *, req,
 101      -            cred_t *, cr, vnode_t *, vp, GETATTR3args *, args);
      107 +        DTRACE_NFSV3_5(op__getattr__start, struct svc_req *, req,
      108 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
      109 +            GETATTR3args *, args);
 102  110  
 103  111          if (vp == NULL) {
 104  112                  error = ESTALE;
 105  113                  goto out;
 106  114          }
 107  115  
 108  116          va.va_mask = AT_ALL;
 109  117          error = rfs4_delegated_getattr(vp, &va, 0, cr);
 110  118  
 111  119          if (!error) {
 112  120                  /* Lie about the object type for a referral */
 113  121                  if (vn_is_nfs_reparse(vp, cr))
 114  122                          va.va_type = VLNK;
 115  123  
 116  124                  /* overflow error if time or size is out of range */
 117  125                  error = vattr_to_fattr3(&va, &resp->resok.obj_attributes);
 118  126                  if (error)
 119  127                          goto out;
 120  128                  resp->status = NFS3_OK;
 121  129  
 122      -                DTRACE_NFSV3_4(op__getattr__done, struct svc_req *, req,
 123      -                    cred_t *, cr, vnode_t *, vp, GETATTR3res *, resp);
      130 +                DTRACE_NFSV3_5(op__getattr__done, struct svc_req *, req,
      131 +                    cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
      132 +                    GETATTR3res *, resp);
 124  133  
 125  134                  VN_RELE(vp);
 126  135  
 127  136                  return;
 128  137          }
 129  138  
 130  139  out:
 131  140          if (curthread->t_flag & T_WOULDBLOCK) {
 132  141                  curthread->t_flag &= ~T_WOULDBLOCK;
 133  142                  resp->status = NFS3ERR_JUKEBOX;
 134  143          } else
 135  144                  resp->status = puterrno3(error);
 136  145  
 137      -        DTRACE_NFSV3_4(op__getattr__done, struct svc_req *, req,
 138      -            cred_t *, cr, vnode_t *, vp, GETATTR3res *, resp);
      146 +        DTRACE_NFSV3_5(op__getattr__done, struct svc_req *, req,
      147 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
      148 +            GETATTR3res *, resp);
 139  149  
 140  150          if (vp != NULL)
 141  151                  VN_RELE(vp);
 142  152  }
 143  153  
 144  154  void *
 145  155  rfs3_getattr_getfh(GETATTR3args *args)
 146  156  {
 147      -
 148  157          return (&args->object);
 149  158  }
 150  159  
 151  160  void
 152  161  rfs3_setattr(SETATTR3args *args, SETATTR3res *resp, struct exportinfo *exi,
 153  162      struct svc_req *req, cred_t *cr, bool_t ro)
 154  163  {
 155  164          int error;
 156  165          vnode_t *vp;
 157  166          struct vattr *bvap;
↓ open down ↓ 3 lines elided ↑ open up ↑
 161  170          int flag;
 162  171          int in_crit = 0;
 163  172          struct flock64 bf;
 164  173          caller_context_t ct;
 165  174  
 166  175          bvap = NULL;
 167  176          avap = NULL;
 168  177  
 169  178          vp = nfs3_fhtovp(&args->object, exi);
 170  179  
 171      -        DTRACE_NFSV3_4(op__setattr__start, struct svc_req *, req,
 172      -            cred_t *, cr, vnode_t *, vp, SETATTR3args *, args);
      180 +        DTRACE_NFSV3_5(op__setattr__start, struct svc_req *, req,
      181 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
      182 +            SETATTR3args *, args);
 173  183  
 174  184          if (vp == NULL) {
 175  185                  error = ESTALE;
 176  186                  goto out;
 177  187          }
 178  188  
 179  189          error = sattr3_to_vattr(&args->new_attributes, &ava);
 180  190          if (error)
 181  191                  goto out;
 182  192  
↓ open down ↓ 140 lines elided ↑ open up ↑
 323  333  
 324  334          if (error)
 325  335                  goto out;
 326  336  
 327  337          if (in_crit)
 328  338                  nbl_end_crit(vp);
 329  339  
 330  340          resp->status = NFS3_OK;
 331  341          vattr_to_wcc_data(bvap, avap, &resp->resok.obj_wcc);
 332  342  
 333      -        DTRACE_NFSV3_4(op__setattr__done, struct svc_req *, req,
 334      -            cred_t *, cr, vnode_t *, vp, SETATTR3res *, resp);
      343 +        DTRACE_NFSV3_5(op__setattr__done, struct svc_req *, req,
      344 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
      345 +            SETATTR3res *, resp);
 335  346  
 336  347          VN_RELE(vp);
 337  348  
 338  349          return;
 339  350  
 340  351  out:
 341  352          if (curthread->t_flag & T_WOULDBLOCK) {
 342  353                  curthread->t_flag &= ~T_WOULDBLOCK;
 343  354                  resp->status = NFS3ERR_JUKEBOX;
 344  355          } else
 345  356                  resp->status = puterrno3(error);
 346  357  out1:
 347      -        DTRACE_NFSV3_4(op__setattr__done, struct svc_req *, req,
 348      -            cred_t *, cr, vnode_t *, vp, SETATTR3res *, resp);
      358 +        DTRACE_NFSV3_5(op__setattr__done, struct svc_req *, req,
      359 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
      360 +            SETATTR3res *, resp);
 349  361  
 350  362          if (vp != NULL) {
 351  363                  if (in_crit)
 352  364                          nbl_end_crit(vp);
 353  365                  VN_RELE(vp);
 354  366          }
 355  367          vattr_to_wcc_data(bvap, avap, &resp->resfail.obj_wcc);
 356  368  }
 357  369  
 358  370  void *
 359  371  rfs3_setattr_getfh(SETATTR3args *args)
 360  372  {
 361      -
 362  373          return (&args->object);
 363  374  }
 364  375  
 365  376  /* ARGSUSED */
 366  377  void
 367  378  rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi,
 368  379      struct svc_req *req, cred_t *cr, bool_t ro)
 369  380  {
 370  381          int error;
 371  382          vnode_t *vp;
↓ open down ↓ 3 lines elided ↑ open up ↑
 375  386          struct vattr *dvap;
 376  387          struct vattr dva;
 377  388          nfs_fh3 *fhp;
 378  389          struct sec_ol sec = {0, 0};
 379  390          bool_t publicfh_flag = FALSE, auth_weak = FALSE;
 380  391          struct sockaddr *ca;
 381  392          char *name = NULL;
 382  393  
 383  394          dvap = NULL;
 384  395  
      396 +        if (exi != NULL)
      397 +                exi_hold(exi);
      398 +
 385  399          /*
 386  400           * Allow lookups from the root - the default
 387  401           * location of the public filehandle.
 388  402           */
 389  403          if (exi != NULL && (exi->exi_export.ex_flags & EX_PUBLIC)) {
 390      -                dvp = rootdir;
      404 +                dvp = ZONE_ROOTVP();
 391  405                  VN_HOLD(dvp);
 392  406  
 393      -                DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req,
 394      -                    cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args);
      407 +                DTRACE_NFSV3_5(op__lookup__start, struct svc_req *, req,
      408 +                    cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
      409 +                    LOOKUP3args *, args);
 395  410          } else {
 396  411                  dvp = nfs3_fhtovp(&args->what.dir, exi);
 397  412  
 398      -                DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req,
 399      -                    cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args);
      413 +                DTRACE_NFSV3_5(op__lookup__start, struct svc_req *, req,
      414 +                    cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
      415 +                    LOOKUP3args *, args);
 400  416  
 401  417                  if (dvp == NULL) {
 402  418                          error = ESTALE;
 403  419                          goto out;
 404  420                  }
 405  421          }
 406  422  
 407  423          dva.va_mask = AT_ALL;
 408  424          dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
 409  425  
↓ open down ↓ 3 lines elided ↑ open up ↑
 413  429          }
 414  430  
 415  431          if (args->what.name == NULL || *(args->what.name) == '\0') {
 416  432                  resp->status = NFS3ERR_ACCES;
 417  433                  goto out1;
 418  434          }
 419  435  
 420  436          fhp = &args->what.dir;
 421  437          if (strcmp(args->what.name, "..") == 0 &&
 422  438              EQFID(&exi->exi_fid, FH3TOFIDP(fhp))) {
 423      -                resp->status = NFS3ERR_NOENT;
 424      -                goto out1;
      439 +                if ((exi->exi_export.ex_flags & EX_NOHIDE) &&
      440 +                    (dvp->v_flag & VROOT)) {
      441 +                        /*
      442 +                         * special case for ".." and 'nohide'exported root
      443 +                         */
      444 +                        if (rfs_climb_crossmnt(&dvp, &exi, cr) != 0) {
      445 +                                resp->status = NFS3ERR_ACCES;
      446 +                                goto out1;
      447 +                        }
      448 +                } else {
      449 +                        resp->status = NFS3ERR_NOENT;
      450 +                        goto out1;
      451 +                }
 425  452          }
 426  453  
 427  454          ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
 428  455          name = nfscmd_convname(ca, exi, args->what.name,
 429  456              NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
 430  457  
 431  458          if (name == NULL) {
 432  459                  resp->status = NFS3ERR_ACCES;
 433  460                  goto out1;
 434  461          }
 435  462  
 436  463          /*
 437  464           * If the public filehandle is used then allow
 438  465           * a multi-component lookup
 439  466           */
 440  467          if (PUBLIC_FH3(&args->what.dir)) {
 441  468                  publicfh_flag = TRUE;
      469 +
      470 +                exi_rele(&exi);
      471 +
 442  472                  error = rfs_publicfh_mclookup(name, dvp, cr, &vp,
 443  473                      &exi, &sec);
 444      -                if (error && exi != NULL)
 445      -                        exi_rele(exi); /* See comment below Re: publicfh_flag */
      474 +
 446  475                  /*
 447  476                   * Since WebNFS may bypass MOUNT, we need to ensure this
 448  477                   * request didn't come from an unlabeled admin_low client.
 449  478                   */
 450  479                  if (is_system_labeled() && error == 0) {
 451  480                          int             addr_type;
 452  481                          void            *ipaddr;
 453  482                          tsol_tpc_t      *tp;
 454  483  
 455  484                          if (ca->sa_family == AF_INET) {
↓ open down ↓ 1 lines elided ↑ open up ↑
 457  486                                  ipaddr = &((struct sockaddr_in *)ca)->sin_addr;
 458  487                          } else if (ca->sa_family == AF_INET6) {
 459  488                                  addr_type = IPV6_VERSION;
 460  489                                  ipaddr = &((struct sockaddr_in6 *)
 461  490                                      ca)->sin6_addr;
 462  491                          }
 463  492                          tp = find_tpc(ipaddr, addr_type, B_FALSE);
 464  493                          if (tp == NULL || tp->tpc_tp.tp_doi !=
 465  494                              l_admin_low->tsl_doi || tp->tpc_tp.host_type !=
 466  495                              SUN_CIPSO) {
 467      -                                if (exi != NULL)
 468      -                                        exi_rele(exi);
 469  496                                  VN_RELE(vp);
 470  497                                  error = EACCES;
 471  498                          }
 472  499                          if (tp != NULL)
 473  500                                  TPC_RELE(tp);
 474  501                  }
 475  502          } else {
 476  503                  error = VOP_LOOKUP(dvp, name, &vp,
 477  504                      NULL, 0, NULL, cr, NULL, NULL, NULL);
 478  505          }
 479  506  
 480  507          if (name != args->what.name)
 481  508                  kmem_free(name, MAXPATHLEN + 1);
 482  509  
      510 +        if (error == 0 && vn_ismntpt(vp)) {
      511 +                error = rfs_cross_mnt(&vp, &exi);
      512 +                if (error)
      513 +                        VN_RELE(vp);
      514 +        }
      515 +
 483  516          if (is_system_labeled() && error == 0) {
 484  517                  bslabel_t *clabel = req->rq_label;
 485  518  
 486  519                  ASSERT(clabel != NULL);
 487  520                  DTRACE_PROBE2(tx__rfs3__log__info__oplookup__clabel, char *,
 488  521                      "got client label from request(1)", struct svc_req *, req);
 489  522  
 490  523                  if (!blequal(&l_admin_low->tsl_label, clabel)) {
 491  524                          if (!do_rfs_label_check(clabel, dvp,
 492  525                              DOMINANCE_CHECK, exi)) {
 493      -                                if (publicfh_flag && exi != NULL)
 494      -                                        exi_rele(exi);
 495  526                                  VN_RELE(vp);
 496  527                                  error = EACCES;
 497  528                          }
 498  529                  }
 499  530          }
 500  531  
 501  532          dva.va_mask = AT_ALL;
 502  533          dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
 503  534  
 504  535          if (error)
 505  536                  goto out;
 506  537  
 507  538          if (sec.sec_flags & SEC_QUERY) {
 508  539                  error = makefh3_ol(&resp->resok.object, exi, sec.sec_index);
 509  540          } else {
 510  541                  error = makefh3(&resp->resok.object, vp, exi);
 511  542                  if (!error && publicfh_flag && !chk_clnt_sec(exi, req))
 512  543                          auth_weak = TRUE;
 513  544          }
 514  545  
 515      -        /*
 516      -         * If publicfh_flag is true then we have called rfs_publicfh_mclookup
 517      -         * and have obtained a new exportinfo in exi which needs to be
 518      -         * released. Note that the original exportinfo pointed to by exi
 519      -         * will be released by the caller, common_dispatch.
 520      -         */
 521      -        if (publicfh_flag)
 522      -                exi_rele(exi);
 523      -
 524  546          if (error) {
 525  547                  VN_RELE(vp);
 526  548                  goto out;
 527  549          }
 528  550  
 529  551          va.va_mask = AT_ALL;
 530  552          vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
 531  553  
      554 +        exi_rele(&exi);
 532  555          VN_RELE(vp);
 533  556  
 534  557          resp->status = NFS3_OK;
 535  558          vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
 536  559          vattr_to_post_op_attr(dvap, &resp->resok.dir_attributes);
 537  560  
 538  561          /*
 539  562           * If it's public fh, no 0x81, and client's flavor is
 540  563           * invalid, set WebNFS status to WNFSERR_CLNT_FLAVOR now.
 541  564           * Then set RPC status to AUTH_TOOWEAK in common_dispatch.
 542  565           */
 543  566          if (auth_weak)
 544  567                  resp->status = (enum nfsstat3)WNFSERR_CLNT_FLAVOR;
 545  568  
 546      -        DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req,
 547      -            cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp);
      569 +        DTRACE_NFSV3_5(op__lookup__done, struct svc_req *, req,
      570 +            cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
      571 +            LOOKUP3res *, resp);
 548  572          VN_RELE(dvp);
 549  573  
 550  574          return;
 551  575  
 552  576  out:
 553  577          if (curthread->t_flag & T_WOULDBLOCK) {
 554  578                  curthread->t_flag &= ~T_WOULDBLOCK;
 555  579                  resp->status = NFS3ERR_JUKEBOX;
 556  580          } else
 557  581                  resp->status = puterrno3(error);
 558  582  out1:
 559      -        DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req,
 560      -            cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp);
      583 +        if (exi != NULL)
      584 +                exi_rele(&exi);
 561  585  
      586 +        DTRACE_NFSV3_5(op__lookup__done, struct svc_req *, req,
      587 +            cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
      588 +            LOOKUP3res *, resp);
      589 +
 562  590          if (dvp != NULL)
 563  591                  VN_RELE(dvp);
 564  592          vattr_to_post_op_attr(dvap, &resp->resfail.dir_attributes);
 565  593  
 566  594  }
 567  595  
 568  596  void *
 569  597  rfs3_lookup_getfh(LOOKUP3args *args)
 570  598  {
 571      -
 572  599          return (&args->what.dir);
 573  600  }
 574  601  
 575      -/* ARGSUSED */
 576  602  void
 577  603  rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi,
 578  604      struct svc_req *req, cred_t *cr, bool_t ro)
 579  605  {
 580  606          int error;
 581  607          vnode_t *vp;
 582  608          struct vattr *vap;
 583  609          struct vattr va;
 584  610          int checkwriteperm;
 585  611          boolean_t dominant_label = B_FALSE;
 586  612          boolean_t equal_label = B_FALSE;
 587  613          boolean_t admin_low_client;
 588  614  
 589  615          vap = NULL;
 590  616  
 591  617          vp = nfs3_fhtovp(&args->object, exi);
 592  618  
 593      -        DTRACE_NFSV3_4(op__access__start, struct svc_req *, req,
 594      -            cred_t *, cr, vnode_t *, vp, ACCESS3args *, args);
      619 +        DTRACE_NFSV3_5(op__access__start, struct svc_req *, req,
      620 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
      621 +            ACCESS3args *, args);
 595  622  
 596  623          if (vp == NULL) {
 597  624                  error = ESTALE;
 598  625                  goto out;
 599  626          }
 600  627  
 601  628          /*
 602  629           * If the file system is exported read only, it is not appropriate
 603  630           * to check write permissions for regular files and directories.
 604  631           * Special files are interpreted by the client, so the underlying
↓ open down ↓ 89 lines elided ↑ open up ↑
 694  721                      dominant_label))
 695  722                          resp->resok.access |= ACCESS3_EXECUTE;
 696  723          }
 697  724  
 698  725          va.va_mask = AT_ALL;
 699  726          vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
 700  727  
 701  728          resp->status = NFS3_OK;
 702  729          vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
 703  730  
 704      -        DTRACE_NFSV3_4(op__access__done, struct svc_req *, req,
 705      -            cred_t *, cr, vnode_t *, vp, ACCESS3res *, resp);
      731 +        DTRACE_NFSV3_5(op__access__done, struct svc_req *, req,
      732 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
      733 +            ACCESS3res *, resp);
 706  734  
 707  735          VN_RELE(vp);
 708  736  
 709  737          return;
 710  738  
 711  739  out:
 712  740          if (curthread->t_flag & T_WOULDBLOCK) {
 713  741                  curthread->t_flag &= ~T_WOULDBLOCK;
 714  742                  resp->status = NFS3ERR_JUKEBOX;
 715  743          } else
 716  744                  resp->status = puterrno3(error);
 717      -        DTRACE_NFSV3_4(op__access__done, struct svc_req *, req,
 718      -            cred_t *, cr, vnode_t *, vp, ACCESS3res *, resp);
      745 +        DTRACE_NFSV3_5(op__access__done, struct svc_req *, req,
      746 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
      747 +            ACCESS3res *, resp);
 719  748          if (vp != NULL)
 720  749                  VN_RELE(vp);
 721  750          vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
 722  751  }
 723  752  
 724  753  void *
 725  754  rfs3_access_getfh(ACCESS3args *args)
 726  755  {
 727      -
 728  756          return (&args->object);
 729  757  }
 730  758  
 731  759  /* ARGSUSED */
 732  760  void
 733  761  rfs3_readlink(READLINK3args *args, READLINK3res *resp, struct exportinfo *exi,
 734  762      struct svc_req *req, cred_t *cr, bool_t ro)
 735  763  {
 736  764          int error;
 737  765          vnode_t *vp;
↓ open down ↓ 3 lines elided ↑ open up ↑
 741  769          struct uio uio;
 742  770          char *data;
 743  771          struct sockaddr *ca;
 744  772          char *name = NULL;
 745  773          int is_referral = 0;
 746  774  
 747  775          vap = NULL;
 748  776  
 749  777          vp = nfs3_fhtovp(&args->symlink, exi);
 750  778  
 751      -        DTRACE_NFSV3_4(op__readlink__start, struct svc_req *, req,
 752      -            cred_t *, cr, vnode_t *, vp, READLINK3args *, args);
      779 +        DTRACE_NFSV3_5(op__readlink__start, struct svc_req *, req,
      780 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
      781 +            READLINK3args *, args);
 753  782  
 754  783          if (vp == NULL) {
 755  784                  error = ESTALE;
 756  785                  goto out;
 757  786          }
 758  787  
 759  788          va.va_mask = AT_ALL;
 760  789          error = VOP_GETATTR(vp, &va, 0, cr, NULL);
 761  790          if (error)
 762  791                  goto out;
↓ open down ↓ 99 lines elided ↑ open up ↑
 862  891                   * Even though the conversion failed, we return
 863  892                   * something. We just don't translate it.
 864  893                   */
 865  894                  name = data;
 866  895          }
 867  896  
 868  897          resp->status = NFS3_OK;
 869  898          vattr_to_post_op_attr(vap, &resp->resok.symlink_attributes);
 870  899          resp->resok.data = name;
 871  900  
 872      -        DTRACE_NFSV3_4(op__readlink__done, struct svc_req *, req,
 873      -            cred_t *, cr, vnode_t *, vp, READLINK3res *, resp);
      901 +        DTRACE_NFSV3_5(op__readlink__done, struct svc_req *, req,
      902 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
      903 +            READLINK3res *, resp);
 874  904          VN_RELE(vp);
 875  905  
 876  906          if (name != data)
 877  907                  kmem_free(data, MAXPATHLEN + 1);
 878  908  
 879  909          return;
 880  910  
 881  911  out:
 882  912          if (curthread->t_flag & T_WOULDBLOCK) {
 883  913                  curthread->t_flag &= ~T_WOULDBLOCK;
 884  914                  resp->status = NFS3ERR_JUKEBOX;
 885  915          } else
 886  916                  resp->status = puterrno3(error);
 887  917  out1:
 888      -        DTRACE_NFSV3_4(op__readlink__done, struct svc_req *, req,
 889      -            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);
 890  921          if (vp != NULL)
 891  922                  VN_RELE(vp);
 892  923          vattr_to_post_op_attr(vap, &resp->resfail.symlink_attributes);
 893  924  }
 894  925  
 895  926  void *
 896  927  rfs3_readlink_getfh(READLINK3args *args)
 897  928  {
 898      -
 899  929          return (&args->symlink);
 900  930  }
 901  931  
 902  932  void
 903  933  rfs3_readlink_free(READLINK3res *resp)
 904  934  {
 905      -
 906  935          if (resp->status == NFS3_OK)
 907  936                  kmem_free(resp->resok.data, MAXPATHLEN + 1);
 908  937  }
 909  938  
 910  939  /*
 911  940   * Server routine to handle read
 912  941   * May handle RDMA data as well as mblks
 913  942   */
 914  943  /* ARGSUSED */
 915  944  void
↓ open down ↓ 13 lines elided ↑ open up ↑
 929  958          int need_rwunlock = 0;
 930  959          caller_context_t ct;
 931  960          int rdma_used = 0;
 932  961          int loaned_buffers;
 933  962          struct uio *uiop;
 934  963  
 935  964          vap = NULL;
 936  965  
 937  966          vp = nfs3_fhtovp(&args->file, exi);
 938  967  
 939      -        DTRACE_NFSV3_4(op__read__start, struct svc_req *, req,
 940      -            cred_t *, cr, vnode_t *, vp, READ3args *, args);
      968 +        DTRACE_NFSV3_5(op__read__start, struct svc_req *, req,
      969 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
      970 +            READ3args *, args);
 941  971  
      972 +
 942  973          if (vp == NULL) {
 943  974                  error = ESTALE;
 944  975                  goto out;
 945  976          }
 946  977  
 947  978          if (args->wlist) {
 948  979                  if (args->count > clist_len(args->wlist)) {
 949  980                          error = EINVAL;
 950  981                          goto out;
 951  982                  }
↓ open down ↓ 233 lines elided ↑ open up ↑
1185 1216                  resp->resok.data.data_val = (caddr_t)iov.iov_base;
1186 1217                  if (!rdma_setup_read_data3(args, &(resp->resok))) {
1187 1218                          resp->status = NFS3ERR_INVAL;
1188 1219                  }
1189 1220          } else {
1190 1221                  resp->resok.data.data_val = (caddr_t)mp->b_datap->db_base;
1191 1222                  (resp->resok).wlist = NULL;
1192 1223          }
1193 1224  
1194 1225  done:
1195      -        DTRACE_NFSV3_4(op__read__done, struct svc_req *, req,
1196      -            cred_t *, cr, vnode_t *, vp, READ3res *, resp);
     1226 +        DTRACE_NFSV3_5(op__read__done, struct svc_req *, req,
     1227 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
     1228 +            READ3res *, resp);
1197 1229  
1198 1230          VN_RELE(vp);
1199 1231  
1200 1232          if (iovp != NULL)
1201 1233                  kmem_free(iovp, iovcnt * sizeof (struct iovec));
1202 1234  
1203 1235          return;
1204 1236  
1205 1237  out:
1206 1238          if (curthread->t_flag & T_WOULDBLOCK) {
1207 1239                  curthread->t_flag &= ~T_WOULDBLOCK;
1208 1240                  resp->status = NFS3ERR_JUKEBOX;
1209 1241          } else
1210 1242                  resp->status = puterrno3(error);
1211 1243  out1:
1212      -        DTRACE_NFSV3_4(op__read__done, struct svc_req *, req,
1213      -            cred_t *, cr, vnode_t *, vp, READ3res *, resp);
     1244 +        DTRACE_NFSV3_5(op__read__done, struct svc_req *, req,
     1245 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
     1246 +            READ3res *, resp);
1214 1247  
1215 1248          if (vp != NULL) {
1216 1249                  if (need_rwunlock)
1217 1250                          VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
1218 1251                  if (in_crit)
1219 1252                          nbl_end_crit(vp);
1220 1253                  VN_RELE(vp);
1221 1254          }
1222 1255          vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
1223 1256  
↓ open down ↓ 9 lines elided ↑ open up ↑
1233 1266          if (resp->status == NFS3_OK) {
1234 1267                  mp = resp->resok.data.mp;
1235 1268                  if (mp != NULL)
1236 1269                          freemsg(mp);
1237 1270          }
1238 1271  }
1239 1272  
1240 1273  void *
1241 1274  rfs3_read_getfh(READ3args *args)
1242 1275  {
1243      -
1244 1276          return (&args->file);
1245 1277  }
1246 1278  
1247 1279  #define MAX_IOVECS      12
1248 1280  
1249 1281  #ifdef DEBUG
1250 1282  static int rfs3_write_hits = 0;
1251 1283  static int rfs3_write_misses = 0;
1252 1284  #endif
1253 1285  
1254 1286  void
1255 1287  rfs3_write(WRITE3args *args, WRITE3res *resp, struct exportinfo *exi,
1256 1288      struct svc_req *req, cred_t *cr, bool_t ro)
1257 1289  {
     1290 +        nfs3_srv_t *ns;
1258 1291          int error;
1259 1292          vnode_t *vp;
1260 1293          struct vattr *bvap = NULL;
1261 1294          struct vattr bva;
1262 1295          struct vattr *avap = NULL;
1263 1296          struct vattr ava;
1264 1297          u_offset_t rlimit;
1265 1298          struct uio uio;
1266 1299          struct iovec iov[MAX_IOVECS];
1267 1300          mblk_t *m;
1268 1301          struct iovec *iovp;
1269 1302          int iovcnt;
1270 1303          int ioflag;
1271 1304          cred_t *savecred;
1272 1305          int in_crit = 0;
1273 1306          int rwlock_ret = -1;
1274 1307          caller_context_t ct;
1275 1308  
1276 1309          vp = nfs3_fhtovp(&args->file, exi);
1277 1310  
1278      -        DTRACE_NFSV3_4(op__write__start, struct svc_req *, req,
1279      -            cred_t *, cr, vnode_t *, vp, WRITE3args *, args);
     1311 +        DTRACE_NFSV3_5(op__write__start, struct svc_req *, req,
     1312 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
     1313 +            WRITE3args *, args);
1280 1314  
1281 1315          if (vp == NULL) {
1282 1316                  error = ESTALE;
1283 1317                  goto err;
1284 1318          }
1285 1319  
     1320 +        ns = zone_getspecific(rfs3_zone_key, curzone);
1286 1321          if (is_system_labeled()) {
1287 1322                  bslabel_t *clabel = req->rq_label;
1288 1323  
1289 1324                  ASSERT(clabel != NULL);
1290 1325                  DTRACE_PROBE2(tx__rfs3__log__info__opwrite__clabel, char *,
1291 1326                      "got client label from request(1)", struct svc_req *, req);
1292 1327  
1293 1328                  if (!blequal(&l_admin_low->tsl_label, clabel)) {
1294 1329                          if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
1295 1330                              exi)) {
↓ open down ↓ 67 lines elided ↑ open up ↑
1363 1398          if (MANDLOCK(vp, bva.va_mode)) {
1364 1399                  resp->status = NFS3ERR_ACCES;
1365 1400                  goto err1;
1366 1401          }
1367 1402  
1368 1403          if (args->count == 0) {
1369 1404                  resp->status = NFS3_OK;
1370 1405                  vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
1371 1406                  resp->resok.count = 0;
1372 1407                  resp->resok.committed = args->stable;
1373      -                resp->resok.verf = write3verf;
     1408 +                resp->resok.verf = ns->write3verf;
1374 1409                  goto out;
1375 1410          }
1376 1411  
1377 1412          if (args->mblk != NULL) {
1378 1413                  iovcnt = 0;
1379 1414                  for (m = args->mblk; m != NULL; m = m->b_cont)
1380 1415                          iovcnt++;
1381 1416                  if (iovcnt <= MAX_IOVECS) {
1382 1417  #ifdef DEBUG
1383 1418                          rfs3_write_hits++;
↓ open down ↓ 81 lines elided ↑ open up ↑
1465 1500                      bvap->va_seq == 0 || avap->va_seq == 0 ||
1466 1501                      avap->va_seq != (bvap->va_seq + 1)) {
1467 1502                          bvap = NULL;
1468 1503                  }
1469 1504          }
1470 1505  
1471 1506          resp->status = NFS3_OK;
1472 1507          vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
1473 1508          resp->resok.count = args->count - uio.uio_resid;
1474 1509          resp->resok.committed = args->stable;
1475      -        resp->resok.verf = write3verf;
     1510 +        resp->resok.verf = ns->write3verf;
1476 1511          goto out;
1477 1512  
1478 1513  err:
1479 1514          if (curthread->t_flag & T_WOULDBLOCK) {
1480 1515                  curthread->t_flag &= ~T_WOULDBLOCK;
1481 1516                  resp->status = NFS3ERR_JUKEBOX;
1482 1517          } else
1483 1518                  resp->status = puterrno3(error);
1484 1519  err1:
1485 1520          vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
1486 1521  out:
1487      -        DTRACE_NFSV3_4(op__write__done, struct svc_req *, req,
1488      -            cred_t *, cr, vnode_t *, vp, WRITE3res *, resp);
     1522 +        DTRACE_NFSV3_5(op__write__done, struct svc_req *, req,
     1523 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
     1524 +            WRITE3res *, resp);
1489 1525  
1490 1526          if (vp != NULL) {
1491 1527                  if (rwlock_ret != -1)
1492 1528                          VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &ct);
1493 1529                  if (in_crit)
1494 1530                          nbl_end_crit(vp);
1495 1531                  VN_RELE(vp);
1496 1532          }
1497 1533  }
1498 1534  
1499 1535  void *
1500 1536  rfs3_write_getfh(WRITE3args *args)
1501 1537  {
1502      -
1503 1538          return (&args->file);
1504 1539  }
1505 1540  
1506 1541  void
1507 1542  rfs3_create(CREATE3args *args, CREATE3res *resp, struct exportinfo *exi,
1508 1543      struct svc_req *req, cred_t *cr, bool_t ro)
1509 1544  {
1510 1545          int error;
1511 1546          int in_crit = 0;
1512 1547          vnode_t *vp;
↓ open down ↓ 10 lines elided ↑ open up ↑
1523 1558          len_t reqsize;
1524 1559          bool_t trunc;
1525 1560          struct sockaddr *ca;
1526 1561          char *name = NULL;
1527 1562  
1528 1563          dbvap = NULL;
1529 1564          davap = NULL;
1530 1565  
1531 1566          dvp = nfs3_fhtovp(&args->where.dir, exi);
1532 1567  
1533      -        DTRACE_NFSV3_4(op__create__start, struct svc_req *, req,
1534      -            cred_t *, cr, vnode_t *, dvp, CREATE3args *, args);
     1568 +        DTRACE_NFSV3_5(op__create__start, struct svc_req *, req,
     1569 +            cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
     1570 +            CREATE3args *, args);
1535 1571  
1536 1572          if (dvp == NULL) {
1537 1573                  error = ESTALE;
1538 1574                  goto out;
1539 1575          }
1540 1576  
1541 1577          dbva.va_mask = AT_ALL;
1542 1578          dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1543 1579          davap = dbvap;
1544 1580  
↓ open down ↓ 5 lines elided ↑ open up ↑
1550 1586          if (args->where.name == NULL || *(args->where.name) == '\0') {
1551 1587                  resp->status = NFS3ERR_ACCES;
1552 1588                  goto out1;
1553 1589          }
1554 1590  
1555 1591          if (rdonly(ro, dvp)) {
1556 1592                  resp->status = NFS3ERR_ROFS;
1557 1593                  goto out1;
1558 1594          }
1559 1595  
     1596 +        if (protect_zfs_mntpt(dvp) != 0) {
     1597 +                resp->status = NFS3ERR_ACCES;
     1598 +                goto out1;
     1599 +        }
     1600 +
1560 1601          if (is_system_labeled()) {
1561 1602                  bslabel_t *clabel = req->rq_label;
1562 1603  
1563 1604                  ASSERT(clabel != NULL);
1564 1605                  DTRACE_PROBE2(tx__rfs3__log__info__opcreate__clabel, char *,
1565 1606                      "got client label from request(1)", struct svc_req *, req);
1566 1607  
1567 1608                  if (!blequal(&l_admin_low->tsl_label, clabel)) {
1568 1609                          if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
1569 1610                              exi)) {
↓ open down ↓ 253 lines elided ↑ open up ↑
1823 1864          if (tvp != NULL) {
1824 1865                  if (in_crit)
1825 1866                          nbl_end_crit(tvp);
1826 1867                  VN_RELE(tvp);
1827 1868          }
1828 1869  
1829 1870          resp->status = NFS3_OK;
1830 1871          vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
1831 1872          vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
1832 1873  
1833      -        DTRACE_NFSV3_4(op__create__done, struct svc_req *, req,
1834      -            cred_t *, cr, vnode_t *, dvp, CREATE3res *, resp);
     1874 +        DTRACE_NFSV3_5(op__create__done, struct svc_req *, req,
     1875 +            cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
     1876 +            CREATE3res *, resp);
1835 1877  
1836 1878          VN_RELE(dvp);
1837 1879          return;
1838 1880  
1839 1881  out:
1840 1882          if (curthread->t_flag & T_WOULDBLOCK) {
1841 1883                  curthread->t_flag &= ~T_WOULDBLOCK;
1842 1884                  resp->status = NFS3ERR_JUKEBOX;
1843 1885          } else
1844 1886                  resp->status = puterrno3(error);
1845 1887  out1:
1846      -        DTRACE_NFSV3_4(op__create__done, struct svc_req *, req,
1847      -            cred_t *, cr, vnode_t *, dvp, CREATE3res *, resp);
     1888 +        DTRACE_NFSV3_5(op__create__done, struct svc_req *, req,
     1889 +            cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
     1890 +            CREATE3res *, resp);
1848 1891  
1849 1892          if (name != NULL && name != args->where.name)
1850 1893                  kmem_free(name, MAXPATHLEN + 1);
1851 1894  
1852 1895          if (tvp != NULL) {
1853 1896                  if (in_crit)
1854 1897                          nbl_end_crit(tvp);
1855 1898                  VN_RELE(tvp);
1856 1899          }
1857 1900          if (dvp != NULL)
1858 1901                  VN_RELE(dvp);
1859 1902          vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
1860 1903  }
1861 1904  
1862 1905  void *
1863 1906  rfs3_create_getfh(CREATE3args *args)
1864 1907  {
1865      -
1866 1908          return (&args->where.dir);
1867 1909  }
1868 1910  
1869 1911  void
1870 1912  rfs3_mkdir(MKDIR3args *args, MKDIR3res *resp, struct exportinfo *exi,
1871 1913      struct svc_req *req, cred_t *cr, bool_t ro)
1872 1914  {
1873 1915          int error;
1874 1916          vnode_t *vp = NULL;
1875 1917          vnode_t *dvp;
↓ open down ↓ 4 lines elided ↑ open up ↑
1880 1922          struct vattr *davap;
1881 1923          struct vattr dava;
1882 1924          struct sockaddr *ca;
1883 1925          char *name = NULL;
1884 1926  
1885 1927          dbvap = NULL;
1886 1928          davap = NULL;
1887 1929  
1888 1930          dvp = nfs3_fhtovp(&args->where.dir, exi);
1889 1931  
1890      -        DTRACE_NFSV3_4(op__mkdir__start, struct svc_req *, req,
1891      -            cred_t *, cr, vnode_t *, dvp, MKDIR3args *, args);
     1932 +        DTRACE_NFSV3_5(op__mkdir__start, struct svc_req *, req,
     1933 +            cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
     1934 +            MKDIR3args *, args);
1892 1935  
1893 1936          if (dvp == NULL) {
1894 1937                  error = ESTALE;
1895 1938                  goto out;
1896 1939          }
1897 1940  
1898 1941          dbva.va_mask = AT_ALL;
1899 1942          dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1900 1943          davap = dbvap;
1901 1944  
↓ open down ↓ 5 lines elided ↑ open up ↑
1907 1950          if (args->where.name == NULL || *(args->where.name) == '\0') {
1908 1951                  resp->status = NFS3ERR_ACCES;
1909 1952                  goto out1;
1910 1953          }
1911 1954  
1912 1955          if (rdonly(ro, dvp)) {
1913 1956                  resp->status = NFS3ERR_ROFS;
1914 1957                  goto out1;
1915 1958          }
1916 1959  
     1960 +        if (protect_zfs_mntpt(dvp) != 0) {
     1961 +                resp->status = NFS3ERR_ACCES;
     1962 +                goto out1;
     1963 +        }
     1964 +
1917 1965          if (is_system_labeled()) {
1918 1966                  bslabel_t *clabel = req->rq_label;
1919 1967  
1920 1968                  ASSERT(clabel != NULL);
1921 1969                  DTRACE_PROBE2(tx__rfs3__log__info__opmkdir__clabel, char *,
1922 1970                      "got client label from request(1)", struct svc_req *, req);
1923 1971  
1924 1972                  if (!blequal(&l_admin_low->tsl_label, clabel)) {
1925 1973                          if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
1926 1974                              exi)) {
↓ open down ↓ 53 lines elided ↑ open up ↑
1980 2028           * Force modified data and metadata out to stable storage.
1981 2029           */
1982 2030          (void) VOP_FSYNC(vp, 0, cr, NULL);
1983 2031  
1984 2032          VN_RELE(vp);
1985 2033  
1986 2034          resp->status = NFS3_OK;
1987 2035          vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
1988 2036          vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
1989 2037  
1990      -        DTRACE_NFSV3_4(op__mkdir__done, struct svc_req *, req,
1991      -            cred_t *, cr, vnode_t *, dvp, MKDIR3res *, resp);
     2038 +        DTRACE_NFSV3_5(op__mkdir__done, struct svc_req *, req,
     2039 +            cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
     2040 +            MKDIR3res *, resp);
1992 2041          VN_RELE(dvp);
1993 2042  
1994 2043          return;
1995 2044  
1996 2045  out:
1997 2046          if (curthread->t_flag & T_WOULDBLOCK) {
1998 2047                  curthread->t_flag &= ~T_WOULDBLOCK;
1999 2048                  resp->status = NFS3ERR_JUKEBOX;
2000 2049          } else
2001 2050                  resp->status = puterrno3(error);
2002 2051  out1:
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          if (dvp != NULL)
2006 2056                  VN_RELE(dvp);
2007 2057          vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2008 2058  }
2009 2059  
2010 2060  void *
2011 2061  rfs3_mkdir_getfh(MKDIR3args *args)
2012 2062  {
2013      -
2014 2063          return (&args->where.dir);
2015 2064  }
2016 2065  
2017 2066  void
2018 2067  rfs3_symlink(SYMLINK3args *args, SYMLINK3res *resp, struct exportinfo *exi,
2019 2068      struct svc_req *req, cred_t *cr, bool_t ro)
2020 2069  {
2021 2070          int error;
2022 2071          vnode_t *vp;
2023 2072          vnode_t *dvp;
↓ open down ↓ 5 lines elided ↑ open up ↑
2029 2078          struct vattr dava;
2030 2079          struct sockaddr *ca;
2031 2080          char *name = NULL;
2032 2081          char *symdata = NULL;
2033 2082  
2034 2083          dbvap = NULL;
2035 2084          davap = NULL;
2036 2085  
2037 2086          dvp = nfs3_fhtovp(&args->where.dir, exi);
2038 2087  
2039      -        DTRACE_NFSV3_4(op__symlink__start, struct svc_req *, req,
2040      -            cred_t *, cr, vnode_t *, dvp, SYMLINK3args *, args);
     2088 +        DTRACE_NFSV3_5(op__symlink__start, struct svc_req *, req,
     2089 +            cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
     2090 +            SYMLINK3args *, args);
2041 2091  
2042 2092          if (dvp == NULL) {
2043 2093                  error = ESTALE;
2044 2094                  goto err;
2045 2095          }
2046 2096  
2047 2097          dbva.va_mask = AT_ALL;
2048 2098          dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2049 2099          davap = dbvap;
2050 2100  
↓ open down ↓ 5 lines elided ↑ open up ↑
2056 2106          if (args->where.name == NULL || *(args->where.name) == '\0') {
2057 2107                  resp->status = NFS3ERR_ACCES;
2058 2108                  goto err1;
2059 2109          }
2060 2110  
2061 2111          if (rdonly(ro, dvp)) {
2062 2112                  resp->status = NFS3ERR_ROFS;
2063 2113                  goto err1;
2064 2114          }
2065 2115  
     2116 +        if (protect_zfs_mntpt(dvp) != 0) {
     2117 +                resp->status = NFS3ERR_ACCES;
     2118 +                goto err1;
     2119 +        }
     2120 +
2066 2121          if (is_system_labeled()) {
2067 2122                  bslabel_t *clabel = req->rq_label;
2068 2123  
2069 2124                  ASSERT(clabel != NULL);
2070 2125                  DTRACE_PROBE2(tx__rfs3__log__info__opsymlink__clabel, char *,
2071 2126                      "got client label from request(1)", struct svc_req *, req);
2072 2127  
2073 2128                  if (!blequal(&l_admin_low->tsl_label, clabel)) {
2074 2129                          if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
2075 2130                              exi)) {
↓ open down ↓ 91 lines elided ↑ open up ↑
2167 2222          } else
2168 2223                  resp->status = puterrno3(error);
2169 2224  err1:
2170 2225          vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2171 2226  out:
2172 2227          if (name != NULL && name != args->where.name)
2173 2228                  kmem_free(name, MAXPATHLEN + 1);
2174 2229          if (symdata != NULL && symdata != args->symlink.symlink_data)
2175 2230                  kmem_free(symdata, MAXPATHLEN + 1);
2176 2231  
2177      -        DTRACE_NFSV3_4(op__symlink__done, struct svc_req *, req,
2178      -            cred_t *, cr, vnode_t *, dvp, SYMLINK3res *, resp);
     2232 +        DTRACE_NFSV3_5(op__symlink__done, struct svc_req *, req,
     2233 +            cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
     2234 +            SYMLINK3res *, resp);
2179 2235  
2180 2236          if (dvp != NULL)
2181 2237                  VN_RELE(dvp);
2182 2238  }
2183 2239  
2184 2240  void *
2185 2241  rfs3_symlink_getfh(SYMLINK3args *args)
2186 2242  {
2187      -
2188 2243          return (&args->where.dir);
2189 2244  }
2190 2245  
2191 2246  void
2192 2247  rfs3_mknod(MKNOD3args *args, MKNOD3res *resp, struct exportinfo *exi,
2193 2248      struct svc_req *req, cred_t *cr, bool_t ro)
2194 2249  {
2195 2250          int error;
2196 2251          vnode_t *vp;
2197 2252          vnode_t *realvp;
↓ open down ↓ 7 lines elided ↑ open up ↑
2205 2260          int mode;
2206 2261          enum vcexcl excl;
2207 2262          struct sockaddr *ca;
2208 2263          char *name = NULL;
2209 2264  
2210 2265          dbvap = NULL;
2211 2266          davap = NULL;
2212 2267  
2213 2268          dvp = nfs3_fhtovp(&args->where.dir, exi);
2214 2269  
2215      -        DTRACE_NFSV3_4(op__mknod__start, struct svc_req *, req,
2216      -            cred_t *, cr, vnode_t *, dvp, MKNOD3args *, args);
     2270 +        DTRACE_NFSV3_5(op__mknod__start, struct svc_req *, req,
     2271 +            cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
     2272 +            MKNOD3args *, args);
2217 2273  
2218 2274          if (dvp == NULL) {
2219 2275                  error = ESTALE;
2220 2276                  goto out;
2221 2277          }
2222 2278  
2223 2279          dbva.va_mask = AT_ALL;
2224 2280          dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2225 2281          davap = dbvap;
2226 2282  
↓ open down ↓ 5 lines elided ↑ open up ↑
2232 2288          if (args->where.name == NULL || *(args->where.name) == '\0') {
2233 2289                  resp->status = NFS3ERR_ACCES;
2234 2290                  goto out1;
2235 2291          }
2236 2292  
2237 2293          if (rdonly(ro, dvp)) {
2238 2294                  resp->status = NFS3ERR_ROFS;
2239 2295                  goto out1;
2240 2296          }
2241 2297  
     2298 +        if (protect_zfs_mntpt(dvp) != 0) {
     2299 +                resp->status = NFS3ERR_ACCES;
     2300 +                goto out1;
     2301 +        }
     2302 +
2242 2303          if (is_system_labeled()) {
2243 2304                  bslabel_t *clabel = req->rq_label;
2244 2305  
2245 2306                  ASSERT(clabel != NULL);
2246 2307                  DTRACE_PROBE2(tx__rfs3__log__info__opmknod__clabel, char *,
2247 2308                      "got client label from request(1)", struct svc_req *, req);
2248 2309  
2249 2310                  if (!blequal(&l_admin_low->tsl_label, clabel)) {
2250 2311                          if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
2251 2312                              exi)) {
↓ open down ↓ 100 lines elided ↑ open up ↑
2352 2413           */
2353 2414          if (VOP_REALVP(vp, &realvp, NULL) == 0)
2354 2415                  (void) VOP_FSYNC(realvp, FNODSYNC, cr, NULL);
2355 2416          else
2356 2417                  (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
2357 2418  
2358 2419          VN_RELE(vp);
2359 2420  
2360 2421          vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2361 2422          vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2362      -        DTRACE_NFSV3_4(op__mknod__done, struct svc_req *, req,
2363      -            cred_t *, cr, vnode_t *, dvp, MKNOD3res *, resp);
     2423 +        DTRACE_NFSV3_5(op__mknod__done, struct svc_req *, req,
     2424 +            cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
     2425 +            MKNOD3res *, resp);
2364 2426          VN_RELE(dvp);
2365 2427          return;
2366 2428  
2367 2429  out:
2368 2430          if (curthread->t_flag & T_WOULDBLOCK) {
2369 2431                  curthread->t_flag &= ~T_WOULDBLOCK;
2370 2432                  resp->status = NFS3ERR_JUKEBOX;
2371 2433          } else
2372 2434                  resp->status = puterrno3(error);
2373 2435  out1:
2374      -        DTRACE_NFSV3_4(op__mknod__done, struct svc_req *, req,
2375      -            cred_t *, cr, vnode_t *, dvp, MKNOD3res *, resp);
     2436 +        DTRACE_NFSV3_5(op__mknod__done, struct svc_req *, req,
     2437 +            cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
     2438 +            MKNOD3res *, resp);
2376 2439          if (dvp != NULL)
2377 2440                  VN_RELE(dvp);
2378 2441          vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2379 2442  }
2380 2443  
2381 2444  void *
2382 2445  rfs3_mknod_getfh(MKNOD3args *args)
2383 2446  {
2384      -
2385 2447          return (&args->where.dir);
2386 2448  }
2387 2449  
2388 2450  void
2389 2451  rfs3_remove(REMOVE3args *args, REMOVE3res *resp, struct exportinfo *exi,
2390 2452      struct svc_req *req, cred_t *cr, bool_t ro)
2391 2453  {
2392 2454          int error = 0;
2393 2455          vnode_t *vp;
2394 2456          struct vattr *bvap;
↓ open down ↓ 2 lines elided ↑ open up ↑
2397 2459          struct vattr ava;
2398 2460          vnode_t *targvp = NULL;
2399 2461          struct sockaddr *ca;
2400 2462          char *name = NULL;
2401 2463  
2402 2464          bvap = NULL;
2403 2465          avap = NULL;
2404 2466  
2405 2467          vp = nfs3_fhtovp(&args->object.dir, exi);
2406 2468  
2407      -        DTRACE_NFSV3_4(op__remove__start, struct svc_req *, req,
2408      -            cred_t *, cr, vnode_t *, vp, REMOVE3args *, args);
     2469 +        DTRACE_NFSV3_5(op__remove__start, struct svc_req *, req,
     2470 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
     2471 +            REMOVE3args *, args);
2409 2472  
2410 2473          if (vp == NULL) {
2411 2474                  error = ESTALE;
2412 2475                  goto err;
2413 2476          }
2414 2477  
2415 2478          bva.va_mask = AT_ALL;
2416 2479          bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2417 2480          avap = bvap;
2418 2481  
↓ open down ↓ 87 lines elided ↑ open up ↑
2506 2569  
2507 2570  err:
2508 2571          if (curthread->t_flag & T_WOULDBLOCK) {
2509 2572                  curthread->t_flag &= ~T_WOULDBLOCK;
2510 2573                  resp->status = NFS3ERR_JUKEBOX;
2511 2574          } else
2512 2575                  resp->status = puterrno3(error);
2513 2576  err1:
2514 2577          vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
2515 2578  out:
2516      -        DTRACE_NFSV3_4(op__remove__done, struct svc_req *, req,
2517      -            cred_t *, cr, vnode_t *, vp, REMOVE3res *, resp);
     2579 +        DTRACE_NFSV3_5(op__remove__done, struct svc_req *, req,
     2580 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
     2581 +            REMOVE3res *, resp);
2518 2582  
2519 2583          if (name != NULL && name != args->object.name)
2520 2584                  kmem_free(name, MAXPATHLEN + 1);
2521 2585  
2522 2586          if (vp != NULL)
2523 2587                  VN_RELE(vp);
2524 2588  }
2525 2589  
2526 2590  void *
2527 2591  rfs3_remove_getfh(REMOVE3args *args)
2528 2592  {
2529      -
2530 2593          return (&args->object.dir);
2531 2594  }
2532 2595  
2533 2596  void
2534 2597  rfs3_rmdir(RMDIR3args *args, RMDIR3res *resp, struct exportinfo *exi,
2535 2598      struct svc_req *req, cred_t *cr, bool_t ro)
2536 2599  {
2537 2600          int error;
2538 2601          vnode_t *vp;
2539 2602          struct vattr *bvap;
↓ open down ↓ 1 lines elided ↑ open up ↑
2541 2604          struct vattr *avap;
2542 2605          struct vattr ava;
2543 2606          struct sockaddr *ca;
2544 2607          char *name = NULL;
2545 2608  
2546 2609          bvap = NULL;
2547 2610          avap = NULL;
2548 2611  
2549 2612          vp = nfs3_fhtovp(&args->object.dir, exi);
2550 2613  
2551      -        DTRACE_NFSV3_4(op__rmdir__start, struct svc_req *, req,
2552      -            cred_t *, cr, vnode_t *, vp, RMDIR3args *, args);
     2614 +        DTRACE_NFSV3_5(op__rmdir__start, struct svc_req *, req,
     2615 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
     2616 +            RMDIR3args *, args);
2553 2617  
2554 2618          if (vp == NULL) {
2555 2619                  error = ESTALE;
2556 2620                  goto err;
2557 2621          }
2558 2622  
2559 2623          bva.va_mask = AT_ALL;
2560 2624          bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2561 2625          avap = bvap;
2562 2626  
↓ open down ↓ 35 lines elided ↑ open up ↑
2598 2662  
2599 2663          ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2600 2664          name = nfscmd_convname(ca, exi, args->object.name,
2601 2665              NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2602 2666  
2603 2667          if (name == NULL) {
2604 2668                  resp->status = NFS3ERR_INVAL;
2605 2669                  goto err1;
2606 2670          }
2607 2671  
2608      -        error = VOP_RMDIR(vp, name, rootdir, cr, NULL, 0);
     2672 +        error = VOP_RMDIR(vp, name, ZONE_ROOTVP(), cr, NULL, 0);
2609 2673  
2610 2674          if (name != args->object.name)
2611 2675                  kmem_free(name, MAXPATHLEN + 1);
2612 2676  
2613 2677          ava.va_mask = AT_ALL;
2614 2678          avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
2615 2679  
2616 2680          /*
2617 2681           * Force modified data and metadata out to stable storage.
2618 2682           */
↓ open down ↓ 17 lines elided ↑ open up ↑
2636 2700  
2637 2701  err:
2638 2702          if (curthread->t_flag & T_WOULDBLOCK) {
2639 2703                  curthread->t_flag &= ~T_WOULDBLOCK;
2640 2704                  resp->status = NFS3ERR_JUKEBOX;
2641 2705          } else
2642 2706                  resp->status = puterrno3(error);
2643 2707  err1:
2644 2708          vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
2645 2709  out:
2646      -        DTRACE_NFSV3_4(op__rmdir__done, struct svc_req *, req,
2647      -            cred_t *, cr, vnode_t *, vp, RMDIR3res *, resp);
     2710 +        DTRACE_NFSV3_5(op__rmdir__done, struct svc_req *, req,
     2711 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
     2712 +            RMDIR3res *, resp);
2648 2713          if (vp != NULL)
2649 2714                  VN_RELE(vp);
2650 2715  
2651 2716  }
2652 2717  
2653 2718  void *
2654 2719  rfs3_rmdir_getfh(RMDIR3args *args)
2655 2720  {
2656      -
2657 2721          return (&args->object.dir);
2658 2722  }
2659 2723  
2660 2724  void
2661 2725  rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi,
2662 2726      struct svc_req *req, cred_t *cr, bool_t ro)
2663 2727  {
2664 2728          int error = 0;
2665 2729          vnode_t *fvp;
2666 2730          vnode_t *tvp;
↓ open down ↓ 15 lines elided ↑ open up ↑
2682 2746          char *toname = NULL;
2683 2747  
2684 2748          fbvap = NULL;
2685 2749          favap = NULL;
2686 2750          tbvap = NULL;
2687 2751          tavap = NULL;
2688 2752          tvp = NULL;
2689 2753  
2690 2754          fvp = nfs3_fhtovp(&args->from.dir, exi);
2691 2755  
2692      -        DTRACE_NFSV3_4(op__rename__start, struct svc_req *, req,
2693      -            cred_t *, cr, vnode_t *, fvp, RENAME3args *, args);
     2756 +        DTRACE_NFSV3_5(op__rename__start, struct svc_req *, req,
     2757 +            cred_t *, cr, vnode_t *, fvp, struct exportinfo *, exi,
     2758 +            RENAME3args *, args);
2694 2759  
2695 2760          if (fvp == NULL) {
2696 2761                  error = ESTALE;
2697 2762                  goto err;
2698 2763          }
2699 2764  
2700 2765          if (is_system_labeled()) {
2701 2766                  clabel = req->rq_label;
2702 2767                  ASSERT(clabel != NULL);
2703 2768                  DTRACE_PROBE2(tx__rfs3__log__info__oprename__clabel, char *,
↓ open down ↓ 11 lines elided ↑ open up ↑
2715 2780          fbva.va_mask = AT_ALL;
2716 2781          fbvap = VOP_GETATTR(fvp, &fbva, 0, cr, NULL) ? NULL : &fbva;
2717 2782          favap = fbvap;
2718 2783  
2719 2784          fh3 = &args->to.dir;
2720 2785          to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
2721 2786          if (to_exi == NULL) {
2722 2787                  resp->status = NFS3ERR_ACCES;
2723 2788                  goto err1;
2724 2789          }
2725      -        exi_rele(to_exi);
     2790 +        exi_rele(&to_exi);
2726 2791  
2727 2792          if (to_exi != exi) {
2728 2793                  resp->status = NFS3ERR_XDEV;
2729 2794                  goto err1;
2730 2795          }
2731 2796  
2732 2797          tvp = nfs3_fhtovp(&args->to.dir, exi);
2733 2798          if (tvp == NULL) {
2734 2799                  error = ESTALE;
2735 2800                  goto err;
↓ open down ↓ 17 lines elided ↑ open up ↑
2753 2818              args->to.name == NULL || *(args->to.name) == '\0') {
2754 2819                  resp->status = NFS3ERR_ACCES;
2755 2820                  goto err1;
2756 2821          }
2757 2822  
2758 2823          if (rdonly(ro, tvp)) {
2759 2824                  resp->status = NFS3ERR_ROFS;
2760 2825                  goto err1;
2761 2826          }
2762 2827  
     2828 +        if (protect_zfs_mntpt(tvp) != 0) {
     2829 +                resp->status = NFS3ERR_ACCES;
     2830 +                goto err1;
     2831 +        }
     2832 +
2763 2833          if (is_system_labeled()) {
2764 2834                  if (!blequal(&l_admin_low->tsl_label, clabel)) {
2765 2835                          if (!do_rfs_label_check(clabel, tvp, EQUALITY_CHECK,
2766 2836                              exi)) {
2767 2837                                  resp->status = NFS3ERR_ACCES;
2768 2838                                  goto err1;
2769 2839                          }
2770 2840                  }
2771 2841          }
2772 2842  
↓ open down ↓ 27 lines elided ↑ open up ↑
2800 2870           * If we rename a delegated file we should recall the
2801 2871           * delegation, since future opens should fail or would
2802 2872           * refer to a new file.
2803 2873           */
2804 2874          if (rfs4_check_delegated(FWRITE, srcvp, FALSE)) {
2805 2875                  resp->status = NFS3ERR_JUKEBOX;
2806 2876                  goto err1;
2807 2877          }
2808 2878  
2809 2879          /*
2810      -         * Check for renaming over a delegated file.  Check rfs4_deleg_policy
     2880 +         * Check for renaming over a delegated file.  Check nfs4_deleg_policy
2811 2881           * first to avoid VOP_LOOKUP if possible.
2812 2882           */
2813      -        if (rfs4_deleg_policy != SRV_NEVER_DELEGATE &&
     2883 +        if (nfs4_get_deleg_policy() != SRV_NEVER_DELEGATE &&
2814 2884              VOP_LOOKUP(tvp, toname, &targvp, NULL, 0, NULL, cr,
2815 2885              NULL, NULL, NULL) == 0) {
2816 2886  
2817 2887                  if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
2818 2888                          VN_RELE(targvp);
2819 2889                          resp->status = NFS3ERR_JUKEBOX;
2820 2890                          goto err1;
2821 2891                  }
2822 2892                  VN_RELE(targvp);
2823 2893          }
↓ open down ↓ 43 lines elided ↑ open up ↑
2867 2937  err1:
2868 2938          vattr_to_wcc_data(fbvap, favap, &resp->resfail.fromdir_wcc);
2869 2939          vattr_to_wcc_data(tbvap, tavap, &resp->resfail.todir_wcc);
2870 2940  
2871 2941  out:
2872 2942          if (name != NULL && name != args->from.name)
2873 2943                  kmem_free(name, MAXPATHLEN + 1);
2874 2944          if (toname != NULL && toname != args->to.name)
2875 2945                  kmem_free(toname, MAXPATHLEN + 1);
2876 2946  
2877      -        DTRACE_NFSV3_4(op__rename__done, struct svc_req *, req,
2878      -            cred_t *, cr, vnode_t *, fvp, RENAME3res *, resp);
     2947 +        DTRACE_NFSV3_5(op__rename__done, struct svc_req *, req,
     2948 +            cred_t *, cr, vnode_t *, fvp, struct exportinfo *, exi,
     2949 +            RENAME3res *, resp);
2879 2950          if (fvp != NULL)
2880 2951                  VN_RELE(fvp);
2881 2952          if (tvp != NULL)
2882 2953                  VN_RELE(tvp);
2883 2954  }
2884 2955  
2885 2956  void *
2886 2957  rfs3_rename_getfh(RENAME3args *args)
2887 2958  {
2888      -
2889 2959          return (&args->from.dir);
2890 2960  }
2891 2961  
2892 2962  void
2893 2963  rfs3_link(LINK3args *args, LINK3res *resp, struct exportinfo *exi,
2894 2964      struct svc_req *req, cred_t *cr, bool_t ro)
2895 2965  {
2896 2966          int error;
2897 2967          vnode_t *vp;
2898 2968          vnode_t *dvp;
↓ open down ↓ 9 lines elided ↑ open up ↑
2908 2978          struct sockaddr *ca;
2909 2979          char *name = NULL;
2910 2980  
2911 2981          vap = NULL;
2912 2982          bvap = NULL;
2913 2983          avap = NULL;
2914 2984          dvp = NULL;
2915 2985  
2916 2986          vp = nfs3_fhtovp(&args->file, exi);
2917 2987  
2918      -        DTRACE_NFSV3_4(op__link__start, struct svc_req *, req,
2919      -            cred_t *, cr, vnode_t *, vp, LINK3args *, args);
     2988 +        DTRACE_NFSV3_5(op__link__start, struct svc_req *, req,
     2989 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
     2990 +            LINK3args *, args);
2920 2991  
2921 2992          if (vp == NULL) {
2922 2993                  error = ESTALE;
2923 2994                  goto out;
2924 2995          }
2925 2996  
2926 2997          va.va_mask = AT_ALL;
2927 2998          vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2928 2999  
2929 3000          fh3 = &args->link.dir;
2930 3001          to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
2931 3002          if (to_exi == NULL) {
2932 3003                  resp->status = NFS3ERR_ACCES;
2933 3004                  goto out1;
2934 3005          }
2935      -        exi_rele(to_exi);
     3006 +        exi_rele(&to_exi);
2936 3007  
2937 3008          if (to_exi != exi) {
2938 3009                  resp->status = NFS3ERR_XDEV;
2939 3010                  goto out1;
2940 3011          }
2941 3012  
2942 3013          if (is_system_labeled()) {
2943 3014                  clabel = req->rq_label;
2944 3015  
2945 3016                  ASSERT(clabel != NULL);
↓ open down ↓ 31 lines elided ↑ open up ↑
2977 3048          if (args->link.name == NULL || *(args->link.name) == '\0') {
2978 3049                  resp->status = NFS3ERR_ACCES;
2979 3050                  goto out1;
2980 3051          }
2981 3052  
2982 3053          if (rdonly(ro, dvp)) {
2983 3054                  resp->status = NFS3ERR_ROFS;
2984 3055                  goto out1;
2985 3056          }
2986 3057  
     3058 +        if (protect_zfs_mntpt(dvp) != 0) {
     3059 +                resp->status = NFS3ERR_ACCES;
     3060 +                goto out1;
     3061 +        }
     3062 +
2987 3063          if (is_system_labeled()) {
2988 3064                  DTRACE_PROBE2(tx__rfs3__log__info__oplinkdir__clabel, char *,
2989 3065                      "got client label from request(1)", struct svc_req *, req);
2990 3066  
2991 3067                  if (!blequal(&l_admin_low->tsl_label, clabel)) {
2992 3068                          if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
2993 3069                              exi)) {
2994 3070                                  resp->status = NFS3ERR_ACCES;
2995 3071                                  goto out1;
2996 3072                          }
↓ open down ↓ 24 lines elided ↑ open up ↑
3021 3097  
3022 3098          if (error)
3023 3099                  goto out;
3024 3100  
3025 3101          VN_RELE(dvp);
3026 3102  
3027 3103          resp->status = NFS3_OK;
3028 3104          vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
3029 3105          vattr_to_wcc_data(bvap, avap, &resp->resok.linkdir_wcc);
3030 3106  
3031      -        DTRACE_NFSV3_4(op__link__done, struct svc_req *, req,
3032      -            cred_t *, cr, vnode_t *, vp, LINK3res *, resp);
     3107 +        DTRACE_NFSV3_5(op__link__done, struct svc_req *, req,
     3108 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
     3109 +            LINK3res *, resp);
3033 3110  
3034 3111          VN_RELE(vp);
3035 3112  
3036 3113          return;
3037 3114  
3038 3115  out:
3039 3116          if (curthread->t_flag & T_WOULDBLOCK) {
3040 3117                  curthread->t_flag &= ~T_WOULDBLOCK;
3041 3118                  resp->status = NFS3ERR_JUKEBOX;
3042 3119          } else
3043 3120                  resp->status = puterrno3(error);
3044 3121  out1:
3045 3122          if (name != NULL && name != args->link.name)
3046 3123                  kmem_free(name, MAXPATHLEN + 1);
3047 3124  
3048      -        DTRACE_NFSV3_4(op__link__done, struct svc_req *, req,
3049      -            cred_t *, cr, vnode_t *, vp, LINK3res *, resp);
     3125 +        DTRACE_NFSV3_5(op__link__done, struct svc_req *, req,
     3126 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
     3127 +            LINK3res *, resp);
3050 3128  
3051 3129          if (vp != NULL)
3052 3130                  VN_RELE(vp);
3053 3131          if (dvp != NULL)
3054 3132                  VN_RELE(dvp);
3055 3133          vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
3056 3134          vattr_to_wcc_data(bvap, avap, &resp->resfail.linkdir_wcc);
3057 3135  }
3058 3136  
3059 3137  void *
3060 3138  rfs3_link_getfh(LINK3args *args)
3061 3139  {
3062      -
3063 3140          return (&args->file);
3064 3141  }
3065 3142  
3066      -/*
3067      - * This macro defines the size of a response which contains attribute
3068      - * information and one directory entry (whose length is specified by
3069      - * the macro parameter).  If the incoming request is larger than this,
3070      - * then we are guaranteed to be able to return at one directory entry
3071      - * if one exists.  Therefore, we do not need to check for
3072      - * NFS3ERR_TOOSMALL if the requested size is larger then this.  If it
3073      - * is not, then we need to check to make sure that this error does not
3074      - * need to be returned.
3075      - *
3076      - * NFS3_READDIR_MIN_COUNT is comprised of following :
3077      - *
3078      - * status - 1 * BYTES_PER_XDR_UNIT
3079      - * attr. flag - 1 * BYTES_PER_XDR_UNIT
3080      - * cookie verifier - 2 * BYTES_PER_XDR_UNIT
3081      - * attributes  - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT
3082      - * boolean - 1 * BYTES_PER_XDR_UNIT
3083      - * file id - 2 * BYTES_PER_XDR_UNIT
3084      - * directory name length - 1 * BYTES_PER_XDR_UNIT
3085      - * cookie - 2 * BYTES_PER_XDR_UNIT
3086      - * end of list - 1 * BYTES_PER_XDR_UNIT
3087      - * end of file - 1 * BYTES_PER_XDR_UNIT
3088      - * Name length of directory to the nearest byte
3089      - */
     3143 +#ifdef nextdp
     3144 +#undef nextdp
     3145 +#endif
     3146 +#define nextdp(dp)      ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
3090 3147  
3091      -#define NFS3_READDIR_MIN_COUNT(length)  \
3092      -        ((1 + 1 + 2 + NFS3_SIZEOF_FATTR3 + 1 + 2 + 1 + 2 + 1 + 1) * \
3093      -                BYTES_PER_XDR_UNIT + roundup((length), BYTES_PER_XDR_UNIT))
3094      -
3095 3148  /* ARGSUSED */
3096 3149  void
3097 3150  rfs3_readdir(READDIR3args *args, READDIR3res *resp, struct exportinfo *exi,
3098 3151      struct svc_req *req, cred_t *cr, bool_t ro)
3099 3152  {
3100 3153          int error;
3101 3154          vnode_t *vp;
3102 3155          struct vattr *vap;
3103 3156          struct vattr va;
3104 3157          struct iovec iov;
3105 3158          struct uio uio;
3106      -        char *data;
3107 3159          int iseof;
3108      -        int bufsize;
3109      -        int namlen;
3110      -        uint_t count;
3111      -        struct sockaddr *ca;
3112 3160  
3113      -        vap = NULL;
     3161 +        count3 count = args->count;
     3162 +        count3 size;            /* size of the READDIR3resok structure */
3114 3163  
     3164 +        size_t datasz;
     3165 +        char *data = NULL;
     3166 +        dirent64_t *dp;
     3167 +
     3168 +        struct sockaddr *ca;
     3169 +        entry3 **eptr;
     3170 +        entry3 *entry;
     3171 +
3115 3172          vp = nfs3_fhtovp(&args->dir, exi);
3116 3173  
3117      -        DTRACE_NFSV3_4(op__readdir__start, struct svc_req *, req,
3118      -            cred_t *, cr, vnode_t *, vp, READDIR3args *, args);
     3174 +        DTRACE_NFSV3_5(op__readdir__start, struct svc_req *, req,
     3175 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
     3176 +            READDIR3args *, args);
3119 3177  
3120 3178          if (vp == NULL) {
3121      -                error = ESTALE;
3122      -                goto out;
     3179 +                resp->status = NFS3ERR_STALE;
     3180 +                vap = NULL;
     3181 +                goto out1;
3123 3182          }
3124 3183  
     3184 +        if (vp->v_type != VDIR) {
     3185 +                resp->status = NFS3ERR_NOTDIR;
     3186 +                vap = NULL;
     3187 +                goto out1;
     3188 +        }
     3189 +
3125 3190          if (is_system_labeled()) {
3126 3191                  bslabel_t *clabel = req->rq_label;
3127 3192  
3128 3193                  ASSERT(clabel != NULL);
3129 3194                  DTRACE_PROBE2(tx__rfs3__log__info__opreaddir__clabel, char *,
3130 3195                      "got client label from request(1)", struct svc_req *, req);
3131 3196  
3132 3197                  if (!blequal(&l_admin_low->tsl_label, clabel)) {
3133 3198                          if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3134 3199                              exi)) {
3135 3200                                  resp->status = NFS3ERR_ACCES;
     3201 +                                vap = NULL;
3136 3202                                  goto out1;
3137 3203                          }
3138 3204                  }
3139 3205          }
3140 3206  
3141 3207          (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
3142 3208  
3143 3209          va.va_mask = AT_ALL;
3144 3210          vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3145 3211  
3146      -        if (vp->v_type != VDIR) {
3147      -                resp->status = NFS3ERR_NOTDIR;
3148      -                goto out1;
3149      -        }
3150      -
3151 3212          error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
3152 3213          if (error)
3153 3214                  goto out;
3154 3215  
3155 3216          /*
3156      -         * Now don't allow arbitrary count to alloc;
3157      -         * allow the maximum not to exceed rfs3_tsize()
     3217 +         * Don't allow arbitrary counts for allocation
3158 3218           */
3159      -        if (args->count > rfs3_tsize(req))
3160      -                args->count = rfs3_tsize(req);
     3219 +        if (count > rfs3_tsize(req))
     3220 +                count = rfs3_tsize(req);
3161 3221  
3162 3222          /*
     3223 +         * struct READDIR3resok:
     3224 +         *   dir_attributes:    1 + NFS3_SIZEOF_FATTR3
     3225 +         *   cookieverf:        2
     3226 +         *   entries (bool):    1
     3227 +         *   eof:               1
     3228 +         */
     3229 +        size = (1 + NFS3_SIZEOF_FATTR3 + 2 + 1 + 1) * BYTES_PER_XDR_UNIT;
     3230 +
     3231 +        if (size > count) {
     3232 +                resp->status = NFS3ERR_TOOSMALL;
     3233 +                goto out1;
     3234 +        }
     3235 +
     3236 +        /*
     3237 +         * This is simplification.  The dirent64_t size is not the same as the
     3238 +         * size of XDR representation of entry3, but the sizes are similar so
     3239 +         * we'll assume they are same.  This assumption should not cause any
     3240 +         * harm.  In worst case we will need to issue VOP_READDIR() once more.
     3241 +         */
     3242 +        datasz = count;
     3243 +
     3244 +        /*
3163 3245           * Make sure that there is room to read at least one entry
3164 3246           * if any are available.
3165 3247           */
3166      -        if (args->count < DIRENT64_RECLEN(MAXNAMELEN))
3167      -                count = DIRENT64_RECLEN(MAXNAMELEN);
3168      -        else
3169      -                count = args->count;
     3248 +        if (datasz < DIRENT64_RECLEN(MAXNAMELEN))
     3249 +                datasz = DIRENT64_RECLEN(MAXNAMELEN);
3170 3250  
3171      -        data = kmem_alloc(count, KM_SLEEP);
     3251 +        data = kmem_alloc(datasz, KM_NOSLEEP);
     3252 +        if (data == NULL) {
     3253 +                /* The allocation failed; downsize and wait for it this time */
     3254 +                if (datasz > MAXBSIZE)
     3255 +                        datasz = MAXBSIZE;
     3256 +                data = kmem_alloc(datasz, KM_SLEEP);
     3257 +        }
3172 3258  
3173      -        iov.iov_base = data;
3174      -        iov.iov_len = count;
3175 3259          uio.uio_iov = &iov;
3176 3260          uio.uio_iovcnt = 1;
3177 3261          uio.uio_segflg = UIO_SYSSPACE;
3178 3262          uio.uio_extflg = UIO_COPY_CACHED;
3179 3263          uio.uio_loffset = (offset_t)args->cookie;
3180      -        uio.uio_resid = count;
     3264 +        uio.uio_resid = datasz;
3181 3265  
3182      -        error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
     3266 +        ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
     3267 +        eptr = &resp->resok.reply.entries;
     3268 +        entry = NULL;
3183 3269  
3184      -        va.va_mask = AT_ALL;
3185      -        vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
     3270 +getmoredents:
     3271 +        iov.iov_base = data;
     3272 +        iov.iov_len = datasz;
3186 3273  
     3274 +        error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
3187 3275          if (error) {
3188      -                kmem_free(data, count);
3189      -                goto out;
     3276 +                iseof = 0;
     3277 +                goto done;
3190 3278          }
3191 3279  
3192      -        /*
3193      -         * If the count was not large enough to be able to guarantee
3194      -         * to be able to return at least one entry, then need to
3195      -         * check to see if NFS3ERR_TOOSMALL should be returned.
3196      -         */
3197      -        if (args->count < NFS3_READDIR_MIN_COUNT(MAXNAMELEN)) {
3198      -                /*
3199      -                 * bufsize is used to keep track of the size of the response.
3200      -                 * It is primed with:
3201      -                 *      1 for the status +
3202      -                 *      1 for the dir_attributes.attributes boolean +
3203      -                 *      2 for the cookie verifier
3204      -                 * all times BYTES_PER_XDR_UNIT to convert from XDR units
3205      -                 * to bytes.  If there are directory attributes to be
3206      -                 * returned, then:
3207      -                 *      NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3
3208      -                 * time BYTES_PER_XDR_UNIT is added to account for them.
3209      -                 */
3210      -                bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT;
3211      -                if (vap != NULL)
3212      -                        bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT;
3213      -                /*
3214      -                 * An entry is composed of:
3215      -                 *      1 for the true/false list indicator +
3216      -                 *      2 for the fileid +
3217      -                 *      1 for the length of the name +
3218      -                 *      2 for the cookie +
3219      -                 * all times BYTES_PER_XDR_UNIT to convert from
3220      -                 * XDR units to bytes, plus the length of the name
3221      -                 * rounded up to the nearest BYTES_PER_XDR_UNIT.
3222      -                 */
3223      -                if (count != uio.uio_resid) {
3224      -                        namlen = strlen(((struct dirent64 *)data)->d_name);
3225      -                        bufsize += (1 + 2 + 1 + 2) * BYTES_PER_XDR_UNIT +
3226      -                            roundup(namlen, BYTES_PER_XDR_UNIT);
     3280 +        if (iov.iov_len == datasz)
     3281 +                goto done;
     3282 +
     3283 +        for (dp = (dirent64_t *)data; (char *)dp - data < datasz - iov.iov_len;
     3284 +            dp = nextdp(dp)) {
     3285 +                char *name;
     3286 +                count3 esize;
     3287 +
     3288 +                if (dp->d_ino == 0) {
     3289 +                        if (entry != NULL)
     3290 +                                entry->cookie = (cookie3)dp->d_off;
     3291 +                        continue;
3227 3292                  }
     3293 +
     3294 +                name = nfscmd_convname(ca, exi, dp->d_name,
     3295 +                    NFSCMD_CONV_OUTBOUND, MAXPATHLEN + 1);
     3296 +                if (name == NULL) {
     3297 +                        if (entry != NULL)
     3298 +                                entry->cookie = (cookie3)dp->d_off;
     3299 +                        continue;
     3300 +                }
     3301 +
3228 3302                  /*
3229      -                 * We need to check to see if the number of bytes left
3230      -                 * to go into the buffer will actually fit into the
3231      -                 * buffer.  This is calculated as the size of this
3232      -                 * entry plus:
3233      -                 *      1 for the true/false list indicator +
3234      -                 *      1 for the eof indicator
3235      -                 * times BYTES_PER_XDR_UNIT to convert from from
3236      -                 * XDR units to bytes.
     3303 +                 * struct entry3:
     3304 +                 *   fileid:            2
     3305 +                 *   name (length):     1
     3306 +                 *   name (data):       length (rounded up)
     3307 +                 *   cookie:            2
     3308 +                 *   nextentry (bool):  1
3237 3309                   */
3238      -                bufsize += (1 + 1) * BYTES_PER_XDR_UNIT;
3239      -                if (bufsize > args->count) {
3240      -                        kmem_free(data, count);
3241      -                        resp->status = NFS3ERR_TOOSMALL;
3242      -                        goto out1;
     3310 +                esize = (2 + 1 + 2 + 1) * BYTES_PER_XDR_UNIT +
     3311 +                    RNDUP(strlen(name));
     3312 +
     3313 +                /* If the new entry does not fit, discard it */
     3314 +                if (esize > count - size) {
     3315 +                        if (name != dp->d_name)
     3316 +                                kmem_free(name, MAXPATHLEN + 1);
     3317 +                        iseof = 0;
     3318 +                        goto done;
3243 3319                  }
     3320 +
     3321 +                entry = kmem_alloc(sizeof (entry3), KM_SLEEP);
     3322 +
     3323 +                entry->fileid = (fileid3)dp->d_ino;
     3324 +                entry->name = strdup(name);
     3325 +                if (name != dp->d_name)
     3326 +                        kmem_free(name, MAXPATHLEN + 1);
     3327 +                entry->cookie = (cookie3)dp->d_off;
     3328 +
     3329 +                size += esize;
     3330 +
     3331 +                /* Add the entry to the linked list */
     3332 +                *eptr = entry;
     3333 +                eptr = &entry->nextentry;
3244 3334          }
3245 3335  
3246      -        /*
3247      -         * Have a valid readir buffer for the native character
3248      -         * set. Need to check if a conversion is necessary and
3249      -         * potentially rewrite the whole buffer. Note that if the
3250      -         * conversion expands names enough, the structure may not
3251      -         * fit. In this case, we need to drop entries until if fits
3252      -         * and patch the counts in order that the next readdir will
3253      -         * get the correct entries.
3254      -         */
3255      -        ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3256      -        data = nfscmd_convdirent(ca, exi, data, count, &resp->status);
     3336 +        if (!iseof && size < count) {
     3337 +                uio.uio_resid = MIN(datasz, MAXBSIZE);
     3338 +                goto getmoredents;
     3339 +        }
3257 3340  
     3341 +done:
     3342 +        *eptr = NULL;
3258 3343  
     3344 +        va.va_mask = AT_ALL;
     3345 +        vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
     3346 +
     3347 +        if (!iseof && resp->resok.reply.entries == NULL) {
     3348 +                if (error)
     3349 +                        goto out;
     3350 +                resp->status = NFS3ERR_TOOSMALL;
     3351 +                goto out1;
     3352 +        }
     3353 +
3259 3354          VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3260 3355  
3261 3356  #if 0 /* notyet */
3262 3357          /*
3263 3358           * Don't do this.  It causes local disk writes when just
3264 3359           * reading the file and the overhead is deemed larger
3265 3360           * than the benefit.
3266 3361           */
3267 3362          /*
3268 3363           * Force modified metadata out to stable storage.
3269 3364           */
3270 3365          (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3271 3366  #endif
3272 3367  
3273 3368          resp->status = NFS3_OK;
3274      -        vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
3275 3369          resp->resok.cookieverf = 0;
3276      -        resp->resok.reply.entries = (entry3 *)data;
3277      -        resp->resok.reply.eof = iseof;
3278      -        resp->resok.size = count - uio.uio_resid;
3279      -        resp->resok.count = args->count;
3280      -        resp->resok.freecount = count;
     3370 +        resp->resok.reply.eof = iseof ? TRUE : FALSE;
3281 3371  
3282      -        DTRACE_NFSV3_4(op__readdir__done, struct svc_req *, req,
3283      -            cred_t *, cr, vnode_t *, vp, READDIR3res *, resp);
     3372 +        vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
3284 3373  
     3374 +        DTRACE_NFSV3_5(op__readdir__done, struct svc_req *, req,
     3375 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
     3376 +            READDIR3res *, resp);
     3377 +
3285 3378          VN_RELE(vp);
3286 3379  
     3380 +        if (data != NULL)
     3381 +                kmem_free(data, datasz);
     3382 +
3287 3383          return;
3288 3384  
3289 3385  out:
3290 3386          if (curthread->t_flag & T_WOULDBLOCK) {
3291 3387                  curthread->t_flag &= ~T_WOULDBLOCK;
3292 3388                  resp->status = NFS3ERR_JUKEBOX;
3293 3389          } else
3294 3390                  resp->status = puterrno3(error);
3295 3391  out1:
3296      -        DTRACE_NFSV3_4(op__readdir__done, struct svc_req *, req,
3297      -            cred_t *, cr, vnode_t *, vp, READDIR3res *, resp);
     3392 +        vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3298 3393  
     3394 +        DTRACE_NFSV3_5(op__readdir__done, struct svc_req *, req,
     3395 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
     3396 +            READDIR3res *, resp);
     3397 +
3299 3398          if (vp != NULL) {
3300 3399                  VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3301 3400                  VN_RELE(vp);
3302 3401          }
3303      -        vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
     3402 +
     3403 +        if (data != NULL)
     3404 +                kmem_free(data, datasz);
3304 3405  }
3305 3406  
3306 3407  void *
3307 3408  rfs3_readdir_getfh(READDIR3args *args)
3308 3409  {
3309      -
3310 3410          return (&args->dir);
3311 3411  }
3312 3412  
3313 3413  void
3314 3414  rfs3_readdir_free(READDIR3res *resp)
3315 3415  {
     3416 +        if (resp->status == NFS3_OK) {
     3417 +                entry3 *entry, *nentry;
3316 3418  
3317      -        if (resp->status == NFS3_OK)
3318      -                kmem_free(resp->resok.reply.entries, resp->resok.freecount);
     3419 +                for (entry = resp->resok.reply.entries; entry != NULL;
     3420 +                    entry = nentry) {
     3421 +                        nentry = entry->nextentry;
     3422 +                        strfree(entry->name);
     3423 +                        kmem_free(entry, sizeof (entry3));
     3424 +                }
     3425 +        }
3319 3426  }
3320 3427  
3321 3428  #ifdef nextdp
3322 3429  #undef nextdp
3323 3430  #endif
3324 3431  #define nextdp(dp)      ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
3325 3432  
3326      -/*
3327      - * This macro computes the size of a response which contains
3328      - * one directory entry including the attributes as well as file handle.
3329      - * If the incoming request is larger than this, then we are guaranteed to be
3330      - * able to return at least one more directory entry if one exists.
3331      - *
3332      - * NFS3_READDIRPLUS_ENTRY is made up of the following:
3333      - *
3334      - * boolean - 1 * BYTES_PER_XDR_UNIT
3335      - * file id - 2 * BYTES_PER_XDR_UNIT
3336      - * directory name length - 1 * BYTES_PER_XDR_UNIT
3337      - * cookie - 2 * BYTES_PER_XDR_UNIT
3338      - * attribute flag - 1 * BYTES_PER_XDR_UNIT
3339      - * attributes - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT
3340      - * status byte for file handle - 1 *  BYTES_PER_XDR_UNIT
3341      - * length of a file handle - 1 * BYTES_PER_XDR_UNIT
3342      - * Maximum length of a file handle (NFS3_MAXFHSIZE)
3343      - * name length of the entry to the nearest bytes
3344      - */
3345      -#define NFS3_READDIRPLUS_ENTRY(namelen) \
3346      -        ((1 + 2 + 1 + 2 + 1 + NFS3_SIZEOF_FATTR3 + 1 + 1) * \
3347      -                BYTES_PER_XDR_UNIT + \
3348      -        NFS3_MAXFHSIZE + roundup(namelen, BYTES_PER_XDR_UNIT))
3349      -
3350      -static int rfs3_readdir_unit = MAXBSIZE;
3351      -
3352 3433  /* ARGSUSED */
3353 3434  void
3354 3435  rfs3_readdirplus(READDIRPLUS3args *args, READDIRPLUS3res *resp,
3355 3436      struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro)
3356 3437  {
3357 3438          int error;
3358 3439          vnode_t *vp;
3359 3440          struct vattr *vap;
3360 3441          struct vattr va;
3361 3442          struct iovec iov;
3362 3443          struct uio uio;
3363      -        char *data;
3364 3444          int iseof;
3365      -        struct dirent64 *dp;
3366      -        vnode_t *nvp;
3367      -        struct vattr *nvap;
3368      -        struct vattr nva;
3369      -        entryplus3_info *infop = NULL;
3370      -        int size = 0;
3371      -        int nents = 0;
3372      -        int bufsize = 0;
3373      -        int entrysize = 0;
3374      -        int tofit = 0;
3375      -        int rd_unit = rfs3_readdir_unit;
3376      -        int prev_len;
3377      -        int space_left;
3378      -        int i;
3379      -        uint_t *namlen = NULL;
3380      -        char *ndata = NULL;
3381      -        struct sockaddr *ca;
3382      -        size_t ret;
3383 3445  
3384      -        vap = NULL;
     3446 +        count3 dircount = args->dircount;
     3447 +        count3 maxcount = args->maxcount;
     3448 +        count3 dirsize = 0;
     3449 +        count3 size;            /* size of the READDIRPLUS3resok structure */
3385 3450  
     3451 +        size_t datasz;
     3452 +        char *data = NULL;
     3453 +        dirent64_t *dp;
     3454 +
     3455 +        struct sockaddr *ca;
     3456 +        entryplus3 **eptr;
     3457 +        entryplus3 *entry;
     3458 +
3386 3459          vp = nfs3_fhtovp(&args->dir, exi);
3387 3460  
3388      -        DTRACE_NFSV3_4(op__readdirplus__start, struct svc_req *, req,
3389      -            cred_t *, cr, vnode_t *, vp, READDIRPLUS3args *, args);
     3461 +        DTRACE_NFSV3_5(op__readdirplus__start, struct svc_req *, req,
     3462 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
     3463 +            READDIRPLUS3args *, args);
3390 3464  
3391 3465          if (vp == NULL) {
3392      -                error = ESTALE;
3393      -                goto out;
     3466 +                resp->status = NFS3ERR_STALE;
     3467 +                vap = NULL;
     3468 +                goto out1;
3394 3469          }
3395 3470  
     3471 +        if (vp->v_type != VDIR) {
     3472 +                resp->status = NFS3ERR_NOTDIR;
     3473 +                vap = NULL;
     3474 +                goto out1;
     3475 +        }
     3476 +
3396 3477          if (is_system_labeled()) {
3397 3478                  bslabel_t *clabel = req->rq_label;
3398 3479  
3399 3480                  ASSERT(clabel != NULL);
3400 3481                  DTRACE_PROBE2(tx__rfs3__log__info__opreaddirplus__clabel,
3401 3482                      char *, "got client label from request(1)",
3402 3483                      struct svc_req *, req);
3403 3484  
3404 3485                  if (!blequal(&l_admin_low->tsl_label, clabel)) {
3405 3486                          if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3406 3487                              exi)) {
3407 3488                                  resp->status = NFS3ERR_ACCES;
     3489 +                                vap = NULL;
3408 3490                                  goto out1;
3409 3491                          }
3410 3492                  }
3411 3493          }
3412 3494  
3413 3495          (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
3414 3496  
3415 3497          va.va_mask = AT_ALL;
3416 3498          vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3417 3499  
3418      -        if (vp->v_type != VDIR) {
3419      -                error = ENOTDIR;
3420      -                goto out;
3421      -        }
3422      -
3423 3500          error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
3424 3501          if (error)
3425 3502                  goto out;
3426 3503  
3427 3504          /*
3428 3505           * Don't allow arbitrary counts for allocation
3429 3506           */
3430      -        if (args->maxcount > rfs3_tsize(req))
3431      -                args->maxcount = rfs3_tsize(req);
     3507 +        if (maxcount > rfs3_tsize(req))
     3508 +                maxcount = rfs3_tsize(req);
3432 3509  
3433 3510          /*
3434      -         * Make sure that there is room to read at least one entry
3435      -         * if any are available
     3511 +         * struct READDIRPLUS3resok:
     3512 +         *   dir_attributes:    1 + NFS3_SIZEOF_FATTR3
     3513 +         *   cookieverf:        2
     3514 +         *   entries (bool):    1
     3515 +         *   eof:               1
3436 3516           */
3437      -        args->dircount = MIN(args->dircount, args->maxcount);
     3517 +        size = (1 + NFS3_SIZEOF_FATTR3 + 2 + 1 + 1) * BYTES_PER_XDR_UNIT;
3438 3518  
3439      -        if (args->dircount < DIRENT64_RECLEN(MAXNAMELEN))
3440      -                args->dircount = DIRENT64_RECLEN(MAXNAMELEN);
     3519 +        if (size > maxcount) {
     3520 +                resp->status = NFS3ERR_TOOSMALL;
     3521 +                goto out1;
     3522 +        }
3441 3523  
3442 3524          /*
3443      -         * This allocation relies on a minimum directory entry
3444      -         * being roughly 24 bytes.  Therefore, the namlen array
3445      -         * will have enough space based on the maximum number of
3446      -         * entries to read.
     3525 +         * This is simplification.  The dirent64_t size is not the same as the
     3526 +         * size of XDR representation of entryplus3 (excluding attributes and
     3527 +         * handle), but the sizes are similar so we'll assume they are same.
     3528 +         * This assumption should not cause any harm.  In worst case we will
     3529 +         * need to issue VOP_READDIR() once more.
3447 3530           */
3448      -        namlen = kmem_alloc(args->dircount, KM_SLEEP);
3449 3531  
3450      -        space_left = args->dircount;
3451      -        data = kmem_alloc(args->dircount, KM_SLEEP);
3452      -        dp = (struct dirent64 *)data;
     3532 +        datasz = MIN(dircount, maxcount);
     3533 +
     3534 +        /*
     3535 +         * Make sure that there is room to read at least one entry
     3536 +         * if any are available.
     3537 +         */
     3538 +        if (datasz < DIRENT64_RECLEN(MAXNAMELEN))
     3539 +                datasz = DIRENT64_RECLEN(MAXNAMELEN);
     3540 +
     3541 +        data = kmem_alloc(datasz, KM_NOSLEEP);
     3542 +        if (data == NULL) {
     3543 +                /* The allocation failed; downsize and wait for it this time */
     3544 +                if (datasz > MAXBSIZE)
     3545 +                        datasz = MAXBSIZE;
     3546 +                data = kmem_alloc(datasz, KM_SLEEP);
     3547 +        }
     3548 +
3453 3549          uio.uio_iov = &iov;
3454 3550          uio.uio_iovcnt = 1;
3455 3551          uio.uio_segflg = UIO_SYSSPACE;
3456 3552          uio.uio_extflg = UIO_COPY_CACHED;
3457 3553          uio.uio_loffset = (offset_t)args->cookie;
     3554 +        uio.uio_resid = datasz;
3458 3555  
3459      -        /*
3460      -         * bufsize is used to keep track of the size of the response as we
3461      -         * get post op attributes and filehandles for each entry.  This is
3462      -         * an optimization as the server may have read more entries than will
3463      -         * fit in the buffer specified by maxcount.  We stop calculating
3464      -         * post op attributes and filehandles once we have exceeded maxcount.
3465      -         * This will minimize the effect of truncation.
3466      -         *
3467      -         * It is primed with:
3468      -         *      1 for the status +
3469      -         *      1 for the dir_attributes.attributes boolean +
3470      -         *      2 for the cookie verifier
3471      -         * all times BYTES_PER_XDR_UNIT to convert from XDR units
3472      -         * to bytes.  If there are directory attributes to be
3473      -         * returned, then:
3474      -         *      NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3
3475      -         * time BYTES_PER_XDR_UNIT is added to account for them.
3476      -         */
3477      -        bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT;
3478      -        if (vap != NULL)
3479      -                bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT;
     3556 +        ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
     3557 +        eptr = &resp->resok.reply.entries;
     3558 +        entry = NULL;
3480 3559  
3481 3560  getmoredents:
3482      -        /*
3483      -         * Here we make a check so that our read unit is not larger than
3484      -         * the space left in the buffer.
3485      -         */
3486      -        rd_unit = MIN(rd_unit, space_left);
3487      -        iov.iov_base = (char *)dp;
3488      -        iov.iov_len = rd_unit;
3489      -        uio.uio_resid = rd_unit;
3490      -        prev_len = rd_unit;
     3561 +        iov.iov_base = data;
     3562 +        iov.iov_len = datasz;
3491 3563  
3492 3564          error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
3493      -
3494 3565          if (error) {
3495      -                kmem_free(data, args->dircount);
3496      -                goto out;
     3566 +                iseof = 0;
     3567 +                goto done;
3497 3568          }
3498 3569  
3499      -        if (uio.uio_resid == prev_len && !iseof) {
3500      -                if (nents == 0) {
3501      -                        kmem_free(data, args->dircount);
3502      -                        resp->status = NFS3ERR_TOOSMALL;
3503      -                        goto out1;
3504      -                }
     3570 +        if (iov.iov_len == datasz)
     3571 +                goto done;
3505 3572  
3506      -                /*
3507      -                 * We could not get any more entries, so get the attributes
3508      -                 * and filehandle for the entries already obtained.
3509      -                 */
3510      -                goto good;
3511      -        }
     3573 +        for (dp = (dirent64_t *)data; (char *)dp - data < datasz - iov.iov_len;
     3574 +            dp = nextdp(dp)) {
     3575 +                char *name;
     3576 +                vnode_t *nvp;
     3577 +                count3 edirsize;
     3578 +                count3 esize;
3512 3579  
3513      -        /*
3514      -         * We estimate the size of the response by assuming the
3515      -         * entry exists and attributes and filehandle are also valid
3516      -         */
3517      -        for (size = prev_len - uio.uio_resid;
3518      -            size > 0;
3519      -            size -= dp->d_reclen, dp = nextdp(dp)) {
3520      -
3521 3580                  if (dp->d_ino == 0) {
3522      -                        nents++;
     3581 +                        if (entry != NULL)
     3582 +                                entry->cookie = (cookie3)dp->d_off;
3523 3583                          continue;
3524 3584                  }
3525 3585  
3526      -                namlen[nents] = strlen(dp->d_name);
3527      -                entrysize = NFS3_READDIRPLUS_ENTRY(namlen[nents]);
     3586 +                name = nfscmd_convname(ca, exi, dp->d_name,
     3587 +                    NFSCMD_CONV_OUTBOUND, MAXPATHLEN + 1);
     3588 +                if (name == NULL) {
     3589 +                        if (entry != NULL)
     3590 +                                entry->cookie = (cookie3)dp->d_off;
     3591 +                        continue;
     3592 +                }
3528 3593  
3529 3594                  /*
3530      -                 * We need to check to see if the number of bytes left
3531      -                 * to go into the buffer will actually fit into the
3532      -                 * buffer.  This is calculated as the size of this
3533      -                 * entry plus:
3534      -                 *      1 for the true/false list indicator +
3535      -                 *      1 for the eof indicator
3536      -                 * times BYTES_PER_XDR_UNIT to convert from XDR units
3537      -                 * to bytes.
3538      -                 *
3539      -                 * Also check the dircount limit against the first entry read
3540      -                 *
     3595 +                 * struct entryplus3:
     3596 +                 *   fileid:            2
     3597 +                 *   name (length):     1
     3598 +                 *   name (data):       length (rounded up)
     3599 +                 *   cookie:            2
3541 3600                   */
3542      -                tofit = entrysize + (1 + 1) * BYTES_PER_XDR_UNIT;
3543      -                if (bufsize + tofit > args->maxcount) {
3544      -                        /*
3545      -                         * We make a check here to see if this was the
3546      -                         * first entry being measured.  If so, then maxcount
3547      -                         * was too small to begin with and so we need to
3548      -                         * return with NFS3ERR_TOOSMALL.
3549      -                         */
3550      -                        if (nents == 0) {
3551      -                                kmem_free(data, args->dircount);
3552      -                                resp->status = NFS3ERR_TOOSMALL;
3553      -                                goto out1;
3554      -                        }
3555      -                        iseof = FALSE;
3556      -                        goto good;
     3601 +                edirsize = (2 + 1 + 2) * BYTES_PER_XDR_UNIT +
     3602 +                    RNDUP(strlen(name));
     3603 +
     3604 +                /*
     3605 +                 * struct entryplus3:
     3606 +                 *   attributes_follow: 1
     3607 +                 *   handle_follows:    1
     3608 +                 *   nextentry (bool):  1
     3609 +                 */
     3610 +                esize = edirsize + (1 + 1 + 1) * BYTES_PER_XDR_UNIT;
     3611 +
     3612 +                /* If the new entry does not fit, we are done */
     3613 +                if (edirsize > dircount - dirsize || esize > maxcount - size) {
     3614 +                        if (name != dp->d_name)
     3615 +                                kmem_free(name, MAXPATHLEN + 1);
     3616 +                        iseof = 0;
     3617 +                        error = 0;
     3618 +                        goto done;
3557 3619                  }
3558      -                bufsize += entrysize;
3559      -                nents++;
3560      -        }
3561 3620  
3562      -        /*
3563      -         * If there is enough room to fit at least 1 more entry including
3564      -         * post op attributes and filehandle in the buffer AND that we haven't
3565      -         * exceeded dircount then go back and get some more.
3566      -         */
3567      -        if (!iseof &&
3568      -            (args->maxcount - bufsize) >= NFS3_READDIRPLUS_ENTRY(MAXNAMELEN)) {
3569      -                space_left -= (prev_len - uio.uio_resid);
3570      -                if (space_left >= DIRENT64_RECLEN(MAXNAMELEN))
3571      -                        goto getmoredents;
     3621 +                entry = kmem_alloc(sizeof (entryplus3), KM_SLEEP);
3572 3622  
3573      -                /* else, fall through */
3574      -        }
3575      -good:
3576      -        va.va_mask = AT_ALL;
3577      -        vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
     3623 +                entry->fileid = (fileid3)dp->d_ino;
     3624 +                entry->name = strdup(name);
     3625 +                if (name != dp->d_name)
     3626 +                        kmem_free(name, MAXPATHLEN + 1);
     3627 +                entry->cookie = (cookie3)dp->d_off;
3578 3628  
3579      -        VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
     3629 +                error = VOP_LOOKUP(vp, dp->d_name, &nvp, NULL, 0, NULL, cr,
     3630 +                    NULL, NULL, NULL);
     3631 +                if (error) {
     3632 +                        entry->name_attributes.attributes = FALSE;
     3633 +                        entry->name_handle.handle_follows = FALSE;
     3634 +                } else {
     3635 +                        struct vattr nva;
     3636 +                        struct vattr *nvap;
3580 3637  
3581      -        infop = kmem_alloc(nents * sizeof (struct entryplus3_info), KM_SLEEP);
3582      -        resp->resok.infop = infop;
     3638 +                        nva.va_mask = AT_ALL;
     3639 +                        nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ? NULL :
     3640 +                            &nva;
3583 3641  
3584      -        dp = (struct dirent64 *)data;
3585      -        for (i = 0; i < nents; i++) {
     3642 +                        /* Lie about the object type for a referral */
     3643 +                        if (nvap != NULL && vn_is_nfs_reparse(nvp, cr))
     3644 +                                nvap->va_type = VLNK;
3586 3645  
3587      -                if (dp->d_ino == 0) {
3588      -                        infop[i].attr.attributes = FALSE;
3589      -                        infop[i].fh.handle_follows = FALSE;
3590      -                        dp = nextdp(dp);
3591      -                        continue;
3592      -                }
     3646 +                        if (vn_ismntpt(nvp)) {
     3647 +                                entry->name_attributes.attributes = FALSE;
     3648 +                                entry->name_handle.handle_follows = FALSE;
     3649 +                        } else {
     3650 +                                vattr_to_post_op_attr(nvap,
     3651 +                                    &entry->name_attributes);
3593 3652  
3594      -                infop[i].namelen = namlen[i];
     3653 +                                error = makefh3(&entry->name_handle.handle, nvp,
     3654 +                                    exi);
     3655 +                                if (!error)
     3656 +                                        entry->name_handle.handle_follows =
     3657 +                                            TRUE;
     3658 +                                else
     3659 +                                        entry->name_handle.handle_follows =
     3660 +                                            FALSE;
     3661 +                        }
3595 3662  
3596      -                error = VOP_LOOKUP(vp, dp->d_name, &nvp, NULL, 0, NULL, cr,
3597      -                    NULL, NULL, NULL);
3598      -                if (error) {
3599      -                        infop[i].attr.attributes = FALSE;
3600      -                        infop[i].fh.handle_follows = FALSE;
3601      -                        dp = nextdp(dp);
3602      -                        continue;
     3663 +                        VN_RELE(nvp);
3603 3664                  }
3604 3665  
3605      -                nva.va_mask = AT_ALL;
3606      -                nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ? NULL : &nva;
     3666 +                /*
     3667 +                 * struct entryplus3 (optionally):
     3668 +                 *   attributes:        NFS3_SIZEOF_FATTR3
     3669 +                 *   handle length:     1
     3670 +                 *   handle data:       length (rounded up)
     3671 +                 */
     3672 +                if (entry->name_attributes.attributes == TRUE)
     3673 +                        esize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT;
     3674 +                if (entry->name_handle.handle_follows == TRUE)
     3675 +                        esize += 1 * BYTES_PER_XDR_UNIT +
     3676 +                            RNDUP(entry->name_handle.handle.fh3_length);
3607 3677  
3608      -                /* Lie about the object type for a referral */
3609      -                if (vn_is_nfs_reparse(nvp, cr))
3610      -                        nvap->va_type = VLNK;
     3678 +                /* If the new entry does not fit, discard it */
     3679 +                if (esize > maxcount - size) {
     3680 +                        strfree(entry->name);
     3681 +                        kmem_free(entry, sizeof (entryplus3));
     3682 +                        iseof = 0;
     3683 +                        error = 0;
     3684 +                        goto done;
     3685 +                }
3611 3686  
3612      -                vattr_to_post_op_attr(nvap, &infop[i].attr);
     3687 +                dirsize += edirsize;
     3688 +                size += esize;
3613 3689  
3614      -                error = makefh3(&infop[i].fh.handle, nvp, exi);
3615      -                if (!error)
3616      -                        infop[i].fh.handle_follows = TRUE;
3617      -                else
3618      -                        infop[i].fh.handle_follows = FALSE;
     3690 +                /* Add the entry to the linked list */
     3691 +                *eptr = entry;
     3692 +                eptr = &entry->nextentry;
     3693 +        }
3619 3694  
3620      -                VN_RELE(nvp);
3621      -                dp = nextdp(dp);
     3695 +        if (!iseof && dirsize < dircount && size < maxcount) {
     3696 +                uio.uio_resid = MIN(datasz, MAXBSIZE);
     3697 +                goto getmoredents;
3622 3698          }
3623 3699  
3624      -        ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3625      -        ret = nfscmd_convdirplus(ca, exi, data, nents, args->dircount, &ndata);
3626      -        if (ndata == NULL)
3627      -                ndata = data;
     3700 +done:
     3701 +        *eptr = NULL;
3628 3702  
3629      -        if (ret > 0) {
3630      -                /*
3631      -                 * We had to drop one or more entries in order to fit
3632      -                 * during the character conversion.  We need to patch
3633      -                 * up the size and eof info.
3634      -                 */
3635      -                if (iseof)
3636      -                        iseof = FALSE;
     3703 +        va.va_mask = AT_ALL;
     3704 +        vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3637 3705  
3638      -                ret = nfscmd_dropped_entrysize((struct dirent64 *)data,
3639      -                    nents, ret);
     3706 +        if (!iseof && resp->resok.reply.entries == NULL) {
     3707 +                if (error)
     3708 +                        goto out;
     3709 +                resp->status = NFS3ERR_TOOSMALL;
     3710 +                goto out1;
3640 3711          }
3641 3712  
     3713 +        VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3642 3714  
3643 3715  #if 0 /* notyet */
3644 3716          /*
3645 3717           * Don't do this.  It causes local disk writes when just
3646 3718           * reading the file and the overhead is deemed larger
3647 3719           * than the benefit.
3648 3720           */
3649 3721          /*
3650 3722           * Force modified metadata out to stable storage.
3651 3723           */
3652 3724          (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3653 3725  #endif
3654 3726  
3655      -        kmem_free(namlen, args->dircount);
3656      -
3657 3727          resp->status = NFS3_OK;
3658      -        vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
3659 3728          resp->resok.cookieverf = 0;
3660      -        resp->resok.reply.entries = (entryplus3 *)ndata;
3661      -        resp->resok.reply.eof = iseof;
3662      -        resp->resok.size = nents;
3663      -        resp->resok.count = args->dircount - ret;
3664      -        resp->resok.maxcount = args->maxcount;
     3729 +        resp->resok.reply.eof = iseof ? TRUE : FALSE;
3665 3730  
3666      -        DTRACE_NFSV3_4(op__readdirplus__done, struct svc_req *, req,
3667      -            cred_t *, cr, vnode_t *, vp, READDIRPLUS3res *, resp);
3668      -        if (ndata != data)
3669      -                kmem_free(data, args->dircount);
     3731 +        vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
3670 3732  
     3733 +        DTRACE_NFSV3_5(op__readdirplus__done, struct svc_req *, req,
     3734 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
     3735 +            READDIRPLUS3res *, resp);
3671 3736  
3672 3737          VN_RELE(vp);
3673 3738  
     3739 +        if (data != NULL)
     3740 +                kmem_free(data, datasz);
     3741 +
3674 3742          return;
3675 3743  
3676 3744  out:
3677 3745          if (curthread->t_flag & T_WOULDBLOCK) {
3678 3746                  curthread->t_flag &= ~T_WOULDBLOCK;
3679 3747                  resp->status = NFS3ERR_JUKEBOX;
3680 3748          } else {
3681 3749                  resp->status = puterrno3(error);
3682 3750          }
3683 3751  out1:
3684      -        DTRACE_NFSV3_4(op__readdirplus__done, struct svc_req *, req,
3685      -            cred_t *, cr, vnode_t *, vp, READDIRPLUS3res *, resp);
     3752 +        vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3686 3753  
     3754 +        DTRACE_NFSV3_5(op__readdirplus__done, struct svc_req *, req,
     3755 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
     3756 +            READDIRPLUS3res *, resp);
     3757 +
3687 3758          if (vp != NULL) {
3688 3759                  VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3689 3760                  VN_RELE(vp);
3690 3761          }
3691 3762  
3692      -        if (namlen != NULL)
3693      -                kmem_free(namlen, args->dircount);
3694      -
3695      -        vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
     3763 +        if (data != NULL)
     3764 +                kmem_free(data, datasz);
3696 3765  }
3697 3766  
3698 3767  void *
3699 3768  rfs3_readdirplus_getfh(READDIRPLUS3args *args)
3700 3769  {
3701      -
3702 3770          return (&args->dir);
3703 3771  }
3704 3772  
3705 3773  void
3706 3774  rfs3_readdirplus_free(READDIRPLUS3res *resp)
3707 3775  {
3708      -
3709 3776          if (resp->status == NFS3_OK) {
3710      -                kmem_free(resp->resok.reply.entries, resp->resok.count);
3711      -                kmem_free(resp->resok.infop,
3712      -                    resp->resok.size * sizeof (struct entryplus3_info));
     3777 +                entryplus3 *entry, *nentry;
     3778 +
     3779 +                for (entry = resp->resok.reply.entries; entry != NULL;
     3780 +                    entry = nentry) {
     3781 +                        nentry = entry->nextentry;
     3782 +                        strfree(entry->name);
     3783 +                        kmem_free(entry, sizeof (entryplus3));
     3784 +                }
3713 3785          }
3714 3786  }
3715 3787  
3716 3788  /* ARGSUSED */
3717 3789  void
3718 3790  rfs3_fsstat(FSSTAT3args *args, FSSTAT3res *resp, struct exportinfo *exi,
3719 3791      struct svc_req *req, cred_t *cr, bool_t ro)
3720 3792  {
3721 3793          int error;
3722 3794          vnode_t *vp;
3723 3795          struct vattr *vap;
3724 3796          struct vattr va;
3725 3797          struct statvfs64 sb;
3726 3798  
3727 3799          vap = NULL;
3728 3800  
3729 3801          vp = nfs3_fhtovp(&args->fsroot, exi);
3730 3802  
3731      -        DTRACE_NFSV3_4(op__fsstat__start, struct svc_req *, req,
3732      -            cred_t *, cr, vnode_t *, vp, FSSTAT3args *, args);
     3803 +        DTRACE_NFSV3_5(op__fsstat__start, struct svc_req *, req,
     3804 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
     3805 +            FSSTAT3args *, args);
3733 3806  
3734 3807          if (vp == NULL) {
3735 3808                  error = ESTALE;
3736 3809                  goto out;
3737 3810          }
3738 3811  
3739 3812          if (is_system_labeled()) {
3740 3813                  bslabel_t *clabel = req->rq_label;
3741 3814  
3742 3815                  ASSERT(clabel != NULL);
↓ open down ↓ 29 lines elided ↑ open up ↑
3772 3845                  resp->resok.fbytes = (size3)sb.f_bfree;
3773 3846          if (sb.f_bavail != (fsblkcnt64_t)-1)
3774 3847                  resp->resok.abytes = (size3)sb.f_frsize * (size3)sb.f_bavail;
3775 3848          else
3776 3849                  resp->resok.abytes = (size3)sb.f_bavail;
3777 3850          resp->resok.tfiles = (size3)sb.f_files;
3778 3851          resp->resok.ffiles = (size3)sb.f_ffree;
3779 3852          resp->resok.afiles = (size3)sb.f_favail;
3780 3853          resp->resok.invarsec = 0;
3781 3854  
3782      -        DTRACE_NFSV3_4(op__fsstat__done, struct svc_req *, req,
3783      -            cred_t *, cr, vnode_t *, vp, FSSTAT3res *, resp);
     3855 +        DTRACE_NFSV3_5(op__fsstat__done, struct svc_req *, req,
     3856 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
     3857 +            FSSTAT3res *, resp);
3784 3858          VN_RELE(vp);
3785 3859  
3786 3860          return;
3787 3861  
3788 3862  out:
3789 3863          if (curthread->t_flag & T_WOULDBLOCK) {
3790 3864                  curthread->t_flag &= ~T_WOULDBLOCK;
3791 3865                  resp->status = NFS3ERR_JUKEBOX;
3792 3866          } else
3793 3867                  resp->status = puterrno3(error);
3794 3868  out1:
3795      -        DTRACE_NFSV3_4(op__fsstat__done, struct svc_req *, req,
3796      -            cred_t *, cr, vnode_t *, vp, FSSTAT3res *, resp);
     3869 +        DTRACE_NFSV3_5(op__fsstat__done, struct svc_req *, req,
     3870 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
     3871 +            FSSTAT3res *, resp);
3797 3872  
3798 3873          if (vp != NULL)
3799 3874                  VN_RELE(vp);
3800 3875          vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
3801 3876  }
3802 3877  
3803 3878  void *
3804 3879  rfs3_fsstat_getfh(FSSTAT3args *args)
3805 3880  {
3806      -
3807 3881          return (&args->fsroot);
3808 3882  }
3809 3883  
3810 3884  /* ARGSUSED */
3811 3885  void
3812 3886  rfs3_fsinfo(FSINFO3args *args, FSINFO3res *resp, struct exportinfo *exi,
3813 3887      struct svc_req *req, cred_t *cr, bool_t ro)
3814 3888  {
3815 3889          vnode_t *vp;
3816 3890          struct vattr *vap;
3817 3891          struct vattr va;
3818 3892          uint32_t xfer_size;
3819 3893          ulong_t l = 0;
3820 3894          int error;
3821 3895  
3822 3896          vp = nfs3_fhtovp(&args->fsroot, exi);
3823 3897  
3824      -        DTRACE_NFSV3_4(op__fsinfo__start, struct svc_req *, req,
3825      -            cred_t *, cr, vnode_t *, vp, FSINFO3args *, args);
     3898 +        DTRACE_NFSV3_5(op__fsinfo__start, struct svc_req *, req,
     3899 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
     3900 +            FSINFO3args *, args);
3826 3901  
3827 3902          if (vp == NULL) {
3828 3903                  if (curthread->t_flag & T_WOULDBLOCK) {
3829 3904                          curthread->t_flag &= ~T_WOULDBLOCK;
3830 3905                          resp->status = NFS3ERR_JUKEBOX;
3831 3906                  } else
3832 3907                          resp->status = NFS3ERR_STALE;
3833 3908                  vattr_to_post_op_attr(NULL, &resp->resfail.obj_attributes);
3834 3909                  goto out;
3835 3910          }
↓ open down ↓ 53 lines elided ↑ open up ↑
3889 3964                          resp->resok.maxfilesize = INT64_MAX;
3890 3965                  else
3891 3966                          resp->resok.maxfilesize = (1LL << (l-1)) - 1;
3892 3967          }
3893 3968  
3894 3969          resp->resok.time_delta.seconds = 0;
3895 3970          resp->resok.time_delta.nseconds = 1000;
3896 3971          resp->resok.properties = FSF3_LINK | FSF3_SYMLINK |
3897 3972              FSF3_HOMOGENEOUS | FSF3_CANSETTIME;
3898 3973  
3899      -        DTRACE_NFSV3_4(op__fsinfo__done, struct svc_req *, req,
3900      -            cred_t *, cr, vnode_t *, vp, FSINFO3res *, resp);
     3974 +        DTRACE_NFSV3_5(op__fsinfo__done, struct svc_req *, req,
     3975 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
     3976 +            FSINFO3res *, resp);
3901 3977  
3902 3978          VN_RELE(vp);
3903 3979  
3904 3980          return;
3905 3981  
3906 3982  out:
3907      -        DTRACE_NFSV3_4(op__fsinfo__done, struct svc_req *, req,
3908      -            cred_t *, cr, vnode_t *, NULL, FSINFO3res *, resp);
     3983 +        DTRACE_NFSV3_5(op__fsinfo__done, struct svc_req *, req,
     3984 +            cred_t *, cr, vnode_t *, NULL, struct exportinfo *, exi,
     3985 +            FSINFO3res *, resp);
3909 3986          if (vp != NULL)
3910 3987                  VN_RELE(vp);
3911 3988  }
3912 3989  
3913 3990  void *
3914 3991  rfs3_fsinfo_getfh(FSINFO3args *args)
3915 3992  {
3916 3993          return (&args->fsroot);
3917 3994  }
3918 3995  
↓ open down ↓ 5 lines elided ↑ open up ↑
3924 4001          int error;
3925 4002          vnode_t *vp;
3926 4003          struct vattr *vap;
3927 4004          struct vattr va;
3928 4005          ulong_t val;
3929 4006  
3930 4007          vap = NULL;
3931 4008  
3932 4009          vp = nfs3_fhtovp(&args->object, exi);
3933 4010  
3934      -        DTRACE_NFSV3_4(op__pathconf__start, struct svc_req *, req,
3935      -            cred_t *, cr, vnode_t *, vp, PATHCONF3args *, args);
     4011 +        DTRACE_NFSV3_5(op__pathconf__start, struct svc_req *, req,
     4012 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
     4013 +            PATHCONF3args *, args);
3936 4014  
3937 4015          if (vp == NULL) {
3938 4016                  error = ESTALE;
3939 4017                  goto out;
3940 4018          }
3941 4019  
3942 4020          if (is_system_labeled()) {
3943 4021                  bslabel_t *clabel = req->rq_label;
3944 4022  
3945 4023                  ASSERT(clabel != NULL);
↓ open down ↓ 35 lines elided ↑ open up ↑
3981 4059                  goto out;
3982 4060          if (val == 1)
3983 4061                  resp->resok.info.chown_restricted = TRUE;
3984 4062          else
3985 4063                  resp->resok.info.chown_restricted = FALSE;
3986 4064  
3987 4065          resp->status = NFS3_OK;
3988 4066          vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
3989 4067          resp->resok.info.case_insensitive = FALSE;
3990 4068          resp->resok.info.case_preserving = TRUE;
3991      -        DTRACE_NFSV3_4(op__pathconf__done, struct svc_req *, req,
3992      -            cred_t *, cr, vnode_t *, vp, PATHCONF3res *, resp);
     4069 +        DTRACE_NFSV3_5(op__pathconf__done, struct svc_req *, req,
     4070 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
     4071 +            PATHCONF3res *, resp);
3993 4072          VN_RELE(vp);
3994 4073          return;
3995 4074  
3996 4075  out:
3997 4076          if (curthread->t_flag & T_WOULDBLOCK) {
3998 4077                  curthread->t_flag &= ~T_WOULDBLOCK;
3999 4078                  resp->status = NFS3ERR_JUKEBOX;
4000 4079          } else
4001 4080                  resp->status = puterrno3(error);
4002 4081  out1:
4003      -        DTRACE_NFSV3_4(op__pathconf__done, struct svc_req *, req,
4004      -            cred_t *, cr, vnode_t *, vp, PATHCONF3res *, resp);
     4082 +        DTRACE_NFSV3_5(op__pathconf__done, struct svc_req *, req,
     4083 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
     4084 +            PATHCONF3res *, resp);
4005 4085          if (vp != NULL)
4006 4086                  VN_RELE(vp);
4007 4087          vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
4008 4088  }
4009 4089  
4010 4090  void *
4011 4091  rfs3_pathconf_getfh(PATHCONF3args *args)
4012 4092  {
4013      -
4014 4093          return (&args->object);
4015 4094  }
4016 4095  
4017 4096  void
4018 4097  rfs3_commit(COMMIT3args *args, COMMIT3res *resp, struct exportinfo *exi,
4019 4098      struct svc_req *req, cred_t *cr, bool_t ro)
4020 4099  {
     4100 +        nfs3_srv_t *ns;
4021 4101          int error;
4022 4102          vnode_t *vp;
4023 4103          struct vattr *bvap;
4024 4104          struct vattr bva;
4025 4105          struct vattr *avap;
4026 4106          struct vattr ava;
4027 4107  
4028 4108          bvap = NULL;
4029 4109          avap = NULL;
4030 4110  
4031 4111          vp = nfs3_fhtovp(&args->file, exi);
4032 4112  
4033      -        DTRACE_NFSV3_4(op__commit__start, struct svc_req *, req,
4034      -            cred_t *, cr, vnode_t *, vp, COMMIT3args *, args);
     4113 +        DTRACE_NFSV3_5(op__commit__start, struct svc_req *, req,
     4114 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
     4115 +            COMMIT3args *, args);
4035 4116  
4036 4117          if (vp == NULL) {
4037 4118                  error = ESTALE;
4038 4119                  goto out;
4039 4120          }
4040 4121  
     4122 +        ns = zone_getspecific(rfs3_zone_key, curzone);
4041 4123          bva.va_mask = AT_ALL;
4042 4124          error = VOP_GETATTR(vp, &bva, 0, cr, NULL);
4043 4125  
4044 4126          /*
4045 4127           * If we can't get the attributes, then we can't do the
4046 4128           * right access checking.  So, we'll fail the request.
4047 4129           */
4048 4130          if (error)
4049 4131                  goto out;
4050 4132  
↓ open down ↓ 32 lines elided ↑ open up ↑
4083 4165          error = VOP_FSYNC(vp, FSYNC, cr, NULL);
4084 4166  
4085 4167          ava.va_mask = AT_ALL;
4086 4168          avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
4087 4169  
4088 4170          if (error)
4089 4171                  goto out;
4090 4172  
4091 4173          resp->status = NFS3_OK;
4092 4174          vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
4093      -        resp->resok.verf = write3verf;
     4175 +        resp->resok.verf = ns->write3verf;
4094 4176  
4095      -        DTRACE_NFSV3_4(op__commit__done, struct svc_req *, req,
4096      -            cred_t *, cr, vnode_t *, vp, COMMIT3res *, resp);
     4177 +        DTRACE_NFSV3_5(op__commit__done, struct svc_req *, req,
     4178 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
     4179 +            COMMIT3res *, resp);
4097 4180  
4098 4181          VN_RELE(vp);
4099 4182  
4100 4183          return;
4101 4184  
4102 4185  out:
4103 4186          if (curthread->t_flag & T_WOULDBLOCK) {
4104 4187                  curthread->t_flag &= ~T_WOULDBLOCK;
4105 4188                  resp->status = NFS3ERR_JUKEBOX;
4106 4189          } else
4107 4190                  resp->status = puterrno3(error);
4108 4191  out1:
4109      -        DTRACE_NFSV3_4(op__commit__done, struct svc_req *, req,
4110      -            cred_t *, cr, vnode_t *, vp, COMMIT3res *, resp);
     4192 +        DTRACE_NFSV3_5(op__commit__done, struct svc_req *, req,
     4193 +            cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
     4194 +            COMMIT3res *, resp);
4111 4195  
4112 4196          if (vp != NULL)
4113 4197                  VN_RELE(vp);
4114 4198          vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
4115 4199  }
4116 4200  
4117 4201  void *
4118 4202  rfs3_commit_getfh(COMMIT3args *args)
4119 4203  {
4120      -
4121 4204          return (&args->file);
4122 4205  }
4123 4206  
4124 4207  static int
4125 4208  sattr3_to_vattr(sattr3 *sap, struct vattr *vap)
4126 4209  {
4127 4210  
4128 4211          vap->va_mask = 0;
4129 4212  
4130 4213          if (sap->mode.set_it) {
↓ open down ↓ 47 lines elided ↑ open up ↑
4178 4261                  vap->va_mtime.tv_nsec = (uint32_t)sap->mtime.mtime.nseconds;
4179 4262                  vap->va_mask |= AT_MTIME;
4180 4263          } else if (sap->mtime.set_it == SET_TO_SERVER_TIME) {
4181 4264                  gethrestime(&vap->va_mtime);
4182 4265                  vap->va_mask |= AT_MTIME;
4183 4266          }
4184 4267  
4185 4268          return (0);
4186 4269  }
4187 4270  
4188      -static ftype3 vt_to_nf3[] = {
     4271 +static const ftype3 vt_to_nf3[] = {
4189 4272          0, NF3REG, NF3DIR, NF3BLK, NF3CHR, NF3LNK, NF3FIFO, 0, 0, NF3SOCK, 0
4190 4273  };
4191 4274  
4192 4275  static int
4193 4276  vattr_to_fattr3(struct vattr *vap, fattr3 *fap)
4194 4277  {
4195 4278  
4196 4279          ASSERT(vap->va_type >= VNON && vap->va_type <= VBAD);
4197 4280          /* Return error if time or size overflow */
4198 4281          if (! (NFS_VAP_TIME_OK(vap) && NFS3_SIZE_OK(vap->va_size))) {
↓ open down ↓ 61 lines elided ↑ open up ↑
4260 4343          /* don't return attrs if time overflow */
4261 4344          if ((vap != NULL) && !vattr_to_fattr3(vap, &poap->attr)) {
4262 4345                  poap->attributes = TRUE;
4263 4346          } else
4264 4347                  poap->attributes = FALSE;
4265 4348  }
4266 4349  
4267 4350  static void
4268 4351  vattr_to_wcc_data(struct vattr *bvap, struct vattr *avap, wcc_data *wccp)
4269 4352  {
4270      -
4271 4353          vattr_to_pre_op_attr(bvap, &wccp->before);
4272 4354          vattr_to_post_op_attr(avap, &wccp->after);
4273 4355  }
4274 4356  
4275      -void
4276      -rfs3_srvrinit(void)
     4357 +static int
     4358 +rdma_setup_read_data3(READ3args *args, READ3resok *rok)
4277 4359  {
     4360 +        struct clist    *wcl;
     4361 +        int             wlist_len;
     4362 +        count3          count = rok->count;
     4363 +
     4364 +        wcl = args->wlist;
     4365 +        if (rdma_setup_read_chunks(wcl, count, &wlist_len) == FALSE)
     4366 +                return (FALSE);
     4367 +
     4368 +        wcl = args->wlist;
     4369 +        rok->wlist_len = wlist_len;
     4370 +        rok->wlist = wcl;
     4371 +        return (TRUE);
     4372 +}
     4373 +
     4374 +/* ARGSUSED */
     4375 +static void *
     4376 +rfs3_zone_init(zoneid_t zoneid)
     4377 +{
     4378 +        nfs3_srv_t *ns;
4278 4379          struct rfs3_verf_overlay {
4279 4380                  uint_t id; /* a "unique" identifier */
4280 4381                  int ts; /* a unique timestamp */
4281 4382          } *verfp;
4282 4383          timestruc_t now;
4283 4384  
     4385 +        ns = kmem_zalloc(sizeof (*ns), KM_SLEEP);
     4386 +
4284 4387          /*
4285 4388           * The following algorithm attempts to find a unique verifier
4286 4389           * to be used as the write verifier returned from the server
4287 4390           * to the client.  It is important that this verifier change
4288 4391           * whenever the server reboots.  Of secondary importance, it
4289 4392           * is important for the verifier to be unique between two
4290 4393           * different servers.
4291 4394           *
4292 4395           * Thus, an attempt is made to use the system hostid and the
4293 4396           * current time in seconds when the nfssrv kernel module is
↓ open down ↓ 3 lines elided ↑ open up ↑
4297 4400           * time is used.  This will ensure different verifiers each
4298 4401           * time the server reboots and minimize the chances that two
4299 4402           * different servers will have the same verifier.
4300 4403           */
4301 4404  
4302 4405  #ifndef lint
4303 4406          /*
4304 4407           * We ASSERT that this constant logic expression is
4305 4408           * always true because in the past, it wasn't.
4306 4409           */
4307      -        ASSERT(sizeof (*verfp) <= sizeof (write3verf));
     4410 +        ASSERT(sizeof (*verfp) <= sizeof (ns->write3verf));
4308 4411  #endif
4309 4412  
4310 4413          gethrestime(&now);
4311      -        verfp = (struct rfs3_verf_overlay *)&write3verf;
     4414 +        verfp = (struct rfs3_verf_overlay *)&ns->write3verf;
4312 4415          verfp->ts = (int)now.tv_sec;
4313 4416          verfp->id = zone_get_hostid(NULL);
4314 4417  
4315 4418          if (verfp->id == 0)
4316 4419                  verfp->id = (uint_t)now.tv_nsec;
4317 4420  
4318      -        nfs3_srv_caller_id = fs_new_caller_id();
4319      -
     4421 +        return (ns);
4320 4422  }
4321 4423  
4322      -static int
4323      -rdma_setup_read_data3(READ3args *args, READ3resok *rok)
     4424 +/* ARGSUSED */
     4425 +static void
     4426 +rfs3_zone_fini(zoneid_t zoneid, void *data)
4324 4427  {
4325      -        struct clist    *wcl;
4326      -        int             wlist_len;
4327      -        count3          count = rok->count;
     4428 +        nfs3_srv_t *ns = data;
4328 4429  
4329      -        wcl = args->wlist;
4330      -        if (rdma_setup_read_chunks(wcl, count, &wlist_len) == FALSE) {
4331      -                return (FALSE);
4332      -        }
     4430 +        kmem_free(ns, sizeof (*ns));
     4431 +}
4333 4432  
4334      -        wcl = args->wlist;
4335      -        rok->wlist_len = wlist_len;
4336      -        rok->wlist = wcl;
4337      -        return (TRUE);
     4433 +void
     4434 +rfs3_srvrinit(void)
     4435 +{
     4436 +        nfs3_srv_caller_id = fs_new_caller_id();
     4437 +        zone_key_create(&rfs3_zone_key, rfs3_zone_init, NULL, rfs3_zone_fini);
4338 4438  }
4339 4439  
4340 4440  void
4341 4441  rfs3_srvrfini(void)
4342 4442  {
4343 4443          /* Nothing to do */
4344 4444  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX