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

@@ -380,10 +380,13 @@
         struct sockaddr *ca;
         char *name = NULL;
 
         dvap = NULL;
 
+        if (exi != NULL)
+                exi_hold(exi);
+
         /*
          * Allow lookups from the root - the default
          * location of the public filehandle.
          */
         if (exi != NULL && (exi->exi_export.ex_flags & EX_PUBLIC)) {

@@ -418,13 +421,24 @@
         }
 
         fhp = &args->what.dir;
         if (strcmp(args->what.name, "..") == 0 &&
             EQFID(&exi->exi_fid, FH3TOFIDP(fhp))) {
+                if ((exi->exi_export.ex_flags & EX_NOHIDE) &&
+                    (dvp->v_flag & VROOT)) {
+                        /*
+                         * special case for ".." and 'nohide'exported root
+                         */
+                        if (rfs_climb_crossmnt(&dvp, &exi, cr) != 0) {
+                                resp->status = NFS3ERR_ACCES;
+                                goto out1;
+                        }
+                } else {
                 resp->status = NFS3ERR_NOENT;
                 goto out1;
         }
+        }
 
         ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
         name = nfscmd_convname(ca, exi, args->what.name,
             NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
 

@@ -437,14 +451,16 @@
          * If the public filehandle is used then allow
          * a multi-component lookup
          */
         if (PUBLIC_FH3(&args->what.dir)) {
                 publicfh_flag = TRUE;
+
+                exi_rele(exi);
+
                 error = rfs_publicfh_mclookup(name, dvp, cr, &vp,
                     &exi, &sec);
-                if (error && exi != NULL)
-                        exi_rele(exi); /* See comment below Re: publicfh_flag */
+
                 /*
                  * Since WebNFS may bypass MOUNT, we need to ensure this
                  * request didn't come from an unlabeled admin_low client.
                  */
                 if (is_system_labeled() && error == 0) {

@@ -462,12 +478,10 @@
                         }
                         tp = find_tpc(ipaddr, addr_type, B_FALSE);
                         if (tp == NULL || tp->tpc_tp.tp_doi !=
                             l_admin_low->tsl_doi || tp->tpc_tp.host_type !=
                             SUN_CIPSO) {
-                                if (exi != NULL)
-                                        exi_rele(exi);
                                 VN_RELE(vp);
                                 error = EACCES;
                         }
                         if (tp != NULL)
                                 TPC_RELE(tp);

@@ -478,10 +492,16 @@
         }
 
         if (name != args->what.name)
                 kmem_free(name, MAXPATHLEN + 1);
 
+        if (error == 0 && vn_ismntpt(vp)) {
+                error = rfs_cross_mnt(&vp, &exi);
+                if (error)
+                        VN_RELE(vp);
+        }
+
         if (is_system_labeled() && error == 0) {
                 bslabel_t *clabel = req->rq_label;
 
                 ASSERT(clabel != NULL);
                 DTRACE_PROBE2(tx__rfs3__log__info__oplookup__clabel, char *,

@@ -488,12 +508,10 @@
                     "got client label from request(1)", struct svc_req *, req);
 
                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
                         if (!do_rfs_label_check(clabel, dvp,
                             DOMINANCE_CHECK, exi)) {
-                                if (publicfh_flag && exi != NULL)
-                                        exi_rele(exi);
                                 VN_RELE(vp);
                                 error = EACCES;
                         }
                 }
         }

@@ -510,27 +528,19 @@
                 error = makefh3(&resp->resok.object, vp, exi);
                 if (!error && publicfh_flag && !chk_clnt_sec(exi, req))
                         auth_weak = TRUE;
         }
 
-        /*
-         * If publicfh_flag is true then we have called rfs_publicfh_mclookup
-         * and have obtained a new exportinfo in exi which needs to be
-         * released. Note that the original exportinfo pointed to by exi
-         * will be released by the caller, common_dispatch.
-         */
-        if (publicfh_flag)
-                exi_rele(exi);
-
         if (error) {
                 VN_RELE(vp);
                 goto out;
         }
 
         va.va_mask = AT_ALL;
         vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
 
+        exi_rele(exi);
         VN_RELE(vp);
 
         resp->status = NFS3_OK;
         vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
         vattr_to_post_op_attr(dvap, &resp->resok.dir_attributes);

@@ -554,10 +564,13 @@
                 curthread->t_flag &= ~T_WOULDBLOCK;
                 resp->status = NFS3ERR_JUKEBOX;
         } else
                 resp->status = puterrno3(error);
 out1:
+        if (exi != NULL)
+                exi_rele(exi);
+
         DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req,
             cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp);
 
         if (dvp != NULL)
                 VN_RELE(dvp);

@@ -3607,17 +3620,22 @@
 
                 /* Lie about the object type for a referral */
                 if (vn_is_nfs_reparse(nvp, cr))
                         nvap->va_type = VLNK;
 
+                if (vn_ismntpt(nvp)) {
+                        infop[i].attr.attributes = FALSE;
+                        infop[i].fh.handle_follows = FALSE;
+                } else {
                 vattr_to_post_op_attr(nvap, &infop[i].attr);
 
                 error = makefh3(&infop[i].fh.handle, nvp, exi);
                 if (!error)
                         infop[i].fh.handle_follows = TRUE;
                 else
                         infop[i].fh.handle_follows = FALSE;
+                }
 
                 VN_RELE(nvp);
                 dp = nextdp(dp);
         }