Print this page
2988 nfssrv: need ability to go to submounts for v3 and v2 protocols
Portions contributed by: Marcel Telka <marcel.telka@nexenta.com>
Portions contributed by: Jean McCormack <jean.mccormack@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Dan McDonald <danmcd@joyent.com>
Change-Id: I6fdf110cc17e789353c4442b83a46cb80643456e

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/nfs/nfs_srv.c
          +++ new/usr/src/uts/common/fs/nfs/nfs_srv.c
↓ open down ↓ 10 lines elided ↑ open up ↑
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
       21 +
  21   22  /*
  22   23   * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
  23      - * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
       24 + * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  24   25   * Copyright (c) 2016 by Delphix. All rights reserved.
  25   26   */
  26   27  
  27   28  /*
  28   29   *      Copyright (c) 1983,1984,1985,1986,1987,1988,1989  AT&T.
  29   30   *      All rights reserved.
  30   31   */
  31   32  
  32   33  #include <sys/param.h>
  33   34  #include <sys/types.h>
↓ open down ↓ 288 lines elided ↑ open up ↑
 322  323          VN_RELE(vp);
 323  324  
 324  325          ns->ns_status = puterrno(error);
 325  326  }
 326  327  void *
 327  328  rfs_setattr_getfh(struct nfssaargs *args)
 328  329  {
 329  330          return (&args->saa_fh);
 330  331  }
 331  332  
      333 +/* Change and release @exip and @vpp only in success */
      334 +int
      335 +rfs_cross_mnt(vnode_t **vpp, struct exportinfo **exip)
      336 +{
      337 +        struct exportinfo *exi;
      338 +        vnode_t *vp = *vpp;
      339 +        fid_t fid;
      340 +        int error;
      341 +
      342 +        VN_HOLD(vp);
      343 +
      344 +        if ((error = traverse(&vp)) != 0) {
      345 +                VN_RELE(vp);
      346 +                return (error);
      347 +        }
      348 +
      349 +        bzero(&fid, sizeof (fid));
      350 +        fid.fid_len = MAXFIDSZ;
      351 +        error = VOP_FID(vp, &fid, NULL);
      352 +        if (error) {
      353 +                VN_RELE(vp);
      354 +                return (error);
      355 +        }
      356 +
      357 +        exi = checkexport(&vp->v_vfsp->vfs_fsid, &fid);
      358 +        if (exi == NULL ||
      359 +            (exi->exi_export.ex_flags & EX_NOHIDE) == 0) {
      360 +                /*
      361 +                 * It is not error, just subdir is not exported
      362 +                 * or "nohide" is not set
      363 +                 */
      364 +                if (exi != NULL)
      365 +                        exi_rele(exi);
      366 +                VN_RELE(vp);
      367 +        } else {
      368 +                /* go to submount */
      369 +                exi_rele(*exip);
      370 +                *exip = exi;
      371 +
      372 +                VN_RELE(*vpp);
      373 +                *vpp = vp;
      374 +        }
      375 +
      376 +        return (0);
      377 +}
      378 +
 332  379  /*
      380 + * Given mounted "dvp" and "exi", go upper mountpoint
      381 + * with dvp/exi correction
      382 + * Return 0 in success
      383 + */
      384 +int
      385 +rfs_climb_crossmnt(vnode_t **dvpp, struct exportinfo **exip, cred_t *cr)
      386 +{
      387 +        struct exportinfo *exi;
      388 +        vnode_t *dvp = *dvpp;
      389 +
      390 +        ASSERT(dvp->v_flag & VROOT);
      391 +
      392 +        VN_HOLD(dvp);
      393 +        dvp = untraverse(dvp);
      394 +        exi = nfs_vptoexi(NULL, dvp, cr, NULL, NULL, FALSE);
      395 +        if (exi == NULL) {
      396 +                VN_RELE(dvp);
      397 +                return (-1);
      398 +        }
      399 +
      400 +        exi_rele(*exip);
      401 +        *exip = exi;
      402 +        VN_RELE(*dvpp);
      403 +        *dvpp = dvp;
      404 +
      405 +        return (0);
      406 +}
      407 +/*
 333  408   * Directory lookup.
 334  409   * Returns an fhandle and file attributes for file name in a directory.
 335  410   */
 336  411  /* ARGSUSED */
 337  412  void
 338  413  rfs_lookup(struct nfsdiropargs *da, struct nfsdiropres *dr,
 339  414      struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro)
 340  415  {
 341  416          int error;
 342  417          vnode_t *dvp;
↓ open down ↓ 31 lines elided ↑ open up ↑
 374  449                  dvp = rootdir;
 375  450                  VN_HOLD(dvp);
 376  451          } else {
 377  452                  dvp = nfs_fhtovp(fhp, exi);
 378  453                  if (dvp == NULL) {
 379  454                          dr->dr_status = NFSERR_STALE;
 380  455                          return;
 381  456                  }
 382  457          }
 383  458  
      459 +        exi_hold(exi);
      460 +
 384  461          /*
 385  462           * Not allow lookup beyond root.
 386  463           * If the filehandle matches a filehandle of the exi,
 387  464           * then the ".." refers beyond the root of an exported filesystem.
 388  465           */
 389  466          if (strcmp(da->da_name, "..") == 0 &&
 390  467              EQFID(&exi->exi_fid, (fid_t *)&fhp->fh_len)) {
 391      -                VN_RELE(dvp);
 392      -                dr->dr_status = NFSERR_NOENT;
 393      -                return;
      468 +                if ((exi->exi_export.ex_flags & EX_NOHIDE) &&
      469 +                    (dvp->v_flag & VROOT)) {
      470 +                        /*
      471 +                         * special case for ".." and 'nohide'exported root
      472 +                         */
      473 +                        if (rfs_climb_crossmnt(&dvp, &exi, cr) != 0) {
      474 +                                error = NFSERR_ACCES;
      475 +                                goto out;
      476 +                        }
      477 +                } else  {
      478 +                        error = NFSERR_NOENT;
      479 +                        goto out;
      480 +                }
 394  481          }
 395  482  
 396  483          ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
 397  484          name = nfscmd_convname(ca, exi, da->da_name, NFSCMD_CONV_INBOUND,
 398  485              MAXPATHLEN);
 399  486  
 400  487          if (name == NULL) {
 401      -                dr->dr_status = NFSERR_ACCES;
 402      -                return;
      488 +                error = NFSERR_ACCES;
      489 +                goto out;
 403  490          }
 404  491  
 405  492          /*
 406  493           * If the public filehandle is used then allow
 407  494           * a multi-component lookup, i.e. evaluate
 408  495           * a pathname and follow symbolic links if
 409  496           * necessary.
 410  497           *
 411  498           * This may result in a vnode in another filesystem
 412  499           * which is OK as long as the filesystem is exported.
 413  500           */
 414  501          if (PUBLIC_FH2(fhp)) {
 415  502                  publicfh_flag = TRUE;
      503 +
      504 +                exi_rele(exi);
      505 +
 416  506                  error = rfs_publicfh_mclookup(name, dvp, cr, &vp, &exi,
 417  507                      &sec);
 418  508          } else {
 419  509                  /*
 420  510                   * Do a normal single component lookup.
 421  511                   */
 422  512                  error = VOP_LOOKUP(dvp, name, &vp, NULL, 0, NULL, cr,
 423  513                      NULL, NULL, NULL);
 424  514          }
 425  515  
 426  516          if (name != da->da_name)
 427  517                  kmem_free(name, MAXPATHLEN);
 428  518  
      519 +        if (error == 0 && vn_ismntpt(vp)) {
      520 +                error = rfs_cross_mnt(&vp, &exi);
      521 +                if (error)
      522 +                        VN_RELE(vp);
      523 +        }
 429  524  
 430  525          if (!error) {
 431  526                  va.va_mask = AT_ALL;    /* we want everything */
 432  527  
 433  528                  error = rfs4_delegated_getattr(vp, &va, 0, cr);
 434  529  
 435  530                  /* check for overflows */
 436  531                  if (!error) {
 437  532                          acl_perm(vp, exi, &va, cr);
 438  533                          error = vattr_to_nattr(&va, &dr->dr_attr);
↓ open down ↓ 6 lines elided ↑ open up ↑
 445  540                                              exi);
 446  541                                          if (!error && publicfh_flag &&
 447  542                                              !chk_clnt_sec(exi, req))
 448  543                                                  auth_weak = TRUE;
 449  544                                  }
 450  545                          }
 451  546                  }
 452  547                  VN_RELE(vp);
 453  548          }
 454  549  
      550 +out:
 455  551          VN_RELE(dvp);
 456  552  
 457      -        /*
 458      -         * If publicfh_flag is true then we have called rfs_publicfh_mclookup
 459      -         * and have obtained a new exportinfo in exi which needs to be
 460      -         * released. Note the the original exportinfo pointed to by exi
 461      -         * will be released by the caller, comon_dispatch.
 462      -         */
 463      -        if (publicfh_flag && exi != NULL)
      553 +        if (exi != NULL)
 464  554                  exi_rele(exi);
 465  555  
 466  556          /*
 467  557           * If it's public fh, no 0x81, and client's flavor is
 468  558           * invalid, set WebNFS status to WNFSERR_CLNT_FLAVOR now.
 469  559           * Then set RPC status to AUTH_TOOWEAK in common_dispatch.
 470  560           */
 471  561          if (auth_weak)
 472  562                  dr->dr_status = (enum nfsstat)WNFSERR_CLNT_FLAVOR;
 473  563          else
↓ open down ↓ 2540 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX