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/nfs3_srv.c
          +++ new/usr/src/uts/common/fs/nfs/nfs3_srv.c
↓ open down ↓ 374 lines elided ↑ open up ↑
 375  375          struct vattr *dvap;
 376  376          struct vattr dva;
 377  377          nfs_fh3 *fhp;
 378  378          struct sec_ol sec = {0, 0};
 379  379          bool_t publicfh_flag = FALSE, auth_weak = FALSE;
 380  380          struct sockaddr *ca;
 381  381          char *name = NULL;
 382  382  
 383  383          dvap = NULL;
 384  384  
      385 +        if (exi != NULL)
      386 +                exi_hold(exi);
      387 +
 385  388          /*
 386  389           * Allow lookups from the root - the default
 387  390           * location of the public filehandle.
 388  391           */
 389  392          if (exi != NULL && (exi->exi_export.ex_flags & EX_PUBLIC)) {
 390  393                  dvp = rootdir;
 391  394                  VN_HOLD(dvp);
 392  395  
 393  396                  DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req,
 394  397                      cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args);
↓ open down ↓ 18 lines elided ↑ open up ↑
 413  416          }
 414  417  
 415  418          if (args->what.name == NULL || *(args->what.name) == '\0') {
 416  419                  resp->status = NFS3ERR_ACCES;
 417  420                  goto out1;
 418  421          }
 419  422  
 420  423          fhp = &args->what.dir;
 421  424          if (strcmp(args->what.name, "..") == 0 &&
 422  425              EQFID(&exi->exi_fid, FH3TOFIDP(fhp))) {
 423      -                resp->status = NFS3ERR_NOENT;
 424      -                goto out1;
      426 +                if ((exi->exi_export.ex_flags & EX_NOHIDE) &&
      427 +                    (dvp->v_flag & VROOT)) {
      428 +                        /*
      429 +                         * special case for ".." and 'nohide'exported root
      430 +                         */
      431 +                        if (rfs_climb_crossmnt(&dvp, &exi, cr) != 0) {
      432 +                                resp->status = NFS3ERR_ACCES;
      433 +                                goto out1;
      434 +                        }
      435 +                } else {
      436 +                        resp->status = NFS3ERR_NOENT;
      437 +                        goto out1;
      438 +                }
 425  439          }
 426  440  
 427  441          ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
 428  442          name = nfscmd_convname(ca, exi, args->what.name,
 429  443              NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
 430  444  
 431  445          if (name == NULL) {
 432  446                  resp->status = NFS3ERR_ACCES;
 433  447                  goto out1;
 434  448          }
 435  449  
 436  450          /*
 437  451           * If the public filehandle is used then allow
 438  452           * a multi-component lookup
 439  453           */
 440  454          if (PUBLIC_FH3(&args->what.dir)) {
 441  455                  publicfh_flag = TRUE;
      456 +
      457 +                exi_rele(exi);
      458 +
 442  459                  error = rfs_publicfh_mclookup(name, dvp, cr, &vp,
 443  460                      &exi, &sec);
 444      -                if (error && exi != NULL)
 445      -                        exi_rele(exi); /* See comment below Re: publicfh_flag */
      461 +
 446  462                  /*
 447  463                   * Since WebNFS may bypass MOUNT, we need to ensure this
 448  464                   * request didn't come from an unlabeled admin_low client.
 449  465                   */
 450  466                  if (is_system_labeled() && error == 0) {
 451  467                          int             addr_type;
 452  468                          void            *ipaddr;
 453  469                          tsol_tpc_t      *tp;
 454  470  
 455  471                          if (ca->sa_family == AF_INET) {
↓ open down ↓ 1 lines elided ↑ open up ↑
 457  473                                  ipaddr = &((struct sockaddr_in *)ca)->sin_addr;
 458  474                          } else if (ca->sa_family == AF_INET6) {
 459  475                                  addr_type = IPV6_VERSION;
 460  476                                  ipaddr = &((struct sockaddr_in6 *)
 461  477                                      ca)->sin6_addr;
 462  478                          }
 463  479                          tp = find_tpc(ipaddr, addr_type, B_FALSE);
 464  480                          if (tp == NULL || tp->tpc_tp.tp_doi !=
 465  481                              l_admin_low->tsl_doi || tp->tpc_tp.host_type !=
 466  482                              SUN_CIPSO) {
 467      -                                if (exi != NULL)
 468      -                                        exi_rele(exi);
 469  483                                  VN_RELE(vp);
 470  484                                  error = EACCES;
 471  485                          }
 472  486                          if (tp != NULL)
 473  487                                  TPC_RELE(tp);
 474  488                  }
 475  489          } else {
 476  490                  error = VOP_LOOKUP(dvp, name, &vp,
 477  491                      NULL, 0, NULL, cr, NULL, NULL, NULL);
 478  492          }
 479  493  
 480  494          if (name != args->what.name)
 481  495                  kmem_free(name, MAXPATHLEN + 1);
 482  496  
      497 +        if (error == 0 && vn_ismntpt(vp)) {
      498 +                error = rfs_cross_mnt(&vp, &exi);
      499 +                if (error)
      500 +                        VN_RELE(vp);
      501 +        }
      502 +
 483  503          if (is_system_labeled() && error == 0) {
 484  504                  bslabel_t *clabel = req->rq_label;
 485  505  
 486  506                  ASSERT(clabel != NULL);
 487  507                  DTRACE_PROBE2(tx__rfs3__log__info__oplookup__clabel, char *,
 488  508                      "got client label from request(1)", struct svc_req *, req);
 489  509  
 490  510                  if (!blequal(&l_admin_low->tsl_label, clabel)) {
 491  511                          if (!do_rfs_label_check(clabel, dvp,
 492  512                              DOMINANCE_CHECK, exi)) {
 493      -                                if (publicfh_flag && exi != NULL)
 494      -                                        exi_rele(exi);
 495  513                                  VN_RELE(vp);
 496  514                                  error = EACCES;
 497  515                          }
 498  516                  }
 499  517          }
 500  518  
 501  519          dva.va_mask = AT_ALL;
 502  520          dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
 503  521  
 504  522          if (error)
 505  523                  goto out;
 506  524  
 507  525          if (sec.sec_flags & SEC_QUERY) {
 508  526                  error = makefh3_ol(&resp->resok.object, exi, sec.sec_index);
 509  527          } else {
 510  528                  error = makefh3(&resp->resok.object, vp, exi);
 511  529                  if (!error && publicfh_flag && !chk_clnt_sec(exi, req))
 512  530                          auth_weak = TRUE;
 513  531          }
 514  532  
 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  533          if (error) {
 525  534                  VN_RELE(vp);
 526  535                  goto out;
 527  536          }
 528  537  
 529  538          va.va_mask = AT_ALL;
 530  539          vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
 531  540  
      541 +        exi_rele(exi);
 532  542          VN_RELE(vp);
 533  543  
 534  544          resp->status = NFS3_OK;
 535  545          vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
 536  546          vattr_to_post_op_attr(dvap, &resp->resok.dir_attributes);
 537  547  
 538  548          /*
 539  549           * If it's public fh, no 0x81, and client's flavor is
 540  550           * invalid, set WebNFS status to WNFSERR_CLNT_FLAVOR now.
 541  551           * Then set RPC status to AUTH_TOOWEAK in common_dispatch.
↓ open down ↓ 7 lines elided ↑ open up ↑
 549  559  
 550  560          return;
 551  561  
 552  562  out:
 553  563          if (curthread->t_flag & T_WOULDBLOCK) {
 554  564                  curthread->t_flag &= ~T_WOULDBLOCK;
 555  565                  resp->status = NFS3ERR_JUKEBOX;
 556  566          } else
 557  567                  resp->status = puterrno3(error);
 558  568  out1:
      569 +        if (exi != NULL)
      570 +                exi_rele(exi);
      571 +
 559  572          DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req,
 560  573              cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp);
 561  574  
 562  575          if (dvp != NULL)
 563  576                  VN_RELE(dvp);
 564  577          vattr_to_post_op_attr(dvap, &resp->resfail.dir_attributes);
 565  578  
 566  579  }
 567  580  
 568  581  void *
↓ open down ↓ 3033 lines elided ↑ open up ↑
3602 3615                          continue;
3603 3616                  }
3604 3617  
3605 3618                  nva.va_mask = AT_ALL;
3606 3619                  nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ? NULL : &nva;
3607 3620  
3608 3621                  /* Lie about the object type for a referral */
3609 3622                  if (vn_is_nfs_reparse(nvp, cr))
3610 3623                          nvap->va_type = VLNK;
3611 3624  
3612      -                vattr_to_post_op_attr(nvap, &infop[i].attr);
3613      -
3614      -                error = makefh3(&infop[i].fh.handle, nvp, exi);
3615      -                if (!error)
3616      -                        infop[i].fh.handle_follows = TRUE;
3617      -                else
     3625 +                if (vn_ismntpt(nvp)) {
     3626 +                        infop[i].attr.attributes = FALSE;
3618 3627                          infop[i].fh.handle_follows = FALSE;
     3628 +                } else {
     3629 +                        vattr_to_post_op_attr(nvap, &infop[i].attr);
3619 3630  
     3631 +                        error = makefh3(&infop[i].fh.handle, nvp, exi);
     3632 +                        if (!error)
     3633 +                                infop[i].fh.handle_follows = TRUE;
     3634 +                        else
     3635 +                                infop[i].fh.handle_follows = FALSE;
     3636 +                }
     3637 +
3620 3638                  VN_RELE(nvp);
3621 3639                  dp = nextdp(dp);
3622 3640          }
3623 3641  
3624 3642          ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3625 3643          ret = nfscmd_convdirplus(ca, exi, data, nents, args->dircount, &ndata);
3626 3644          if (ndata == NULL)
3627 3645                  ndata = data;
3628 3646  
3629 3647          if (ret > 0) {
↓ open down ↓ 715 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX