Print this page
7378 exported_lock held during nfs4 compound processing

@@ -870,10 +870,11 @@
 do_rfs4_op_secinfo(struct compound_state *cs, char *nm, SECINFO4res *resp)
 {
         int error, different_export = 0;
         vnode_t *dvp, *vp;
         struct exportinfo *exi = NULL;
+        struct exportinfo *oexi = NULL;
         fid_t fid;
         uint_t count, i;
         secinfo4 *resok_val;
         struct secinfo *secp;
         seconfig_t *si;

@@ -961,11 +962,11 @@
         } else if (vp->v_vfsp != dvp->v_vfsp) {
                 /*
                  * If vp isn't a mountpoint and the vfs ptrs aren't the same,
                  * then vp is probably an LOFS object.  We don't need the
                  * realvp, we just need to know that we might have crossed
-                 * a server fs boundary and need to call checkexport4.
+                 * a server fs boundary and need to call checkexport.
                  * (LOFS lookup hides server fs mountpoints, and actually calls
                  * traverse)
                  */
                 different_export = 1;
         }

@@ -982,15 +983,15 @@
                         VN_RELE(vp);
                         return (puterrno4(error));
                 }
 
                 if (dotdot)
-                        exi = nfs_vptoexi(NULL, vp, cs->cr, &walk, NULL, TRUE);
+                        oexi = nfs_vptoexi(NULL, vp, cs->cr, &walk, NULL, TRUE);
                 else
-                        exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp);
+                        oexi = checkexport(&vp->v_vfsp->vfs_fsid, &fid, vp);
 
-                if (exi == NULL) {
+                if (oexi == NULL) {
                         if (did_traverse == TRUE) {
                                 /*
                                  * If this vnode is a mounted-on vnode,
                                  * but the mounted-on file system is not
                                  * exported, send back the secinfo for

@@ -1000,10 +1001,12 @@
                                 exi = cs->exi;
                         } else {
                                 VN_RELE(vp);
                                 return (puterrno4(EACCES));
                         }
+                } else {
+                        exi = oexi;
                 }
         } else {
                 exi = cs->exi;
         }
         ASSERT(exi != NULL);

@@ -1015,11 +1018,11 @@
          *
          * Return all flavors for a pseudo node.
          * For a real export node, return the flavor that the client
          * has access with.
          */
-        ASSERT(RW_LOCK_HELD(&exported_lock));
+        rw_enter(&exported_lock, RW_READER);
         if (PSEUDO(exi)) {
                 count = exi->exi_export.ex_seccnt; /* total sec count */
                 resok_val = kmem_alloc(count * sizeof (secinfo4), KM_SLEEP);
                 secp = exi->exi_export.ex_secinfo;
 

@@ -1108,11 +1111,13 @@
                 }
                 resp->SECINFO4resok_len = ret_cnt;
                 resp->SECINFO4resok_val = resok_val;
                 kmem_free(flavor_list, count * sizeof (int));
         }
-
+        rw_exit(&exported_lock);
+        if (oexi)
+                exi_rele(oexi);
         VN_RELE(vp);
         return (NFS4_OK);
 }
 
 /*

@@ -2609,11 +2614,11 @@
 do_rfs4_op_lookup(char *nm, struct svc_req *req, struct compound_state *cs)
 {
         int error;
         int different_export = 0;
         vnode_t *vp, *pre_tvp = NULL, *oldvp = NULL;
-        struct exportinfo *exi = NULL, *pre_exi = NULL;
+        struct exportinfo *exi = NULL, *pre_exi = NULL, *oexi = NULL;
         nfsstat4 stat;
         fid_t fid;
         int attrdir, dotdot, walk;
         bool_t is_newvp = FALSE;
 

@@ -2703,11 +2708,11 @@
                 pre_exi = cs->exi;      /* save pre-traversed exportinfo */
                 pre_tvp = vp;           /* save pre-traversed vnode     */
 
                 /*
                  * hold pre_tvp to counteract rele by traverse.  We will
-                 * need pre_tvp below if checkexport4 fails
+                 * need pre_tvp below if checkexport fails
                  */
                 VN_HOLD(pre_tvp);
                 if ((error = traverse(&vp)) != 0) {
                         VN_RELE(vp);
                         VN_RELE(pre_tvp);

@@ -2739,11 +2744,11 @@
                 }
 
                 if (dotdot)
                         exi = nfs_vptoexi(NULL, vp, cs->cr, &walk, NULL, TRUE);
                 else
-                        exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp);
+                        exi = checkexport(&vp->v_vfsp->vfs_fsid, &fid, vp);
 
                 if (exi == NULL) {
                         if (pre_tvp) {
                                 /*
                                  * If this vnode is a mounted-on vnode,

@@ -2753,19 +2758,23 @@
                                  * the mounted-on file system.
                                  */
                                 VN_RELE(vp);
                                 vp = pre_tvp;
                                 exi = pre_exi;
+                                if (exi)
+                                        exi_hold(exi);
                         } else {
                                 VN_RELE(vp);
                                 return (puterrno4(EACCES));
                         }
                 } else if (pre_tvp) {
                         /* we're done with pre_tvp now. release extra hold */
                         VN_RELE(pre_tvp);
                 }
 
+                if (cs->exi)
+                        exi_rele(cs->exi);
                 cs->exi = exi;
 
                 /*
                  * Now we do a checkauth4. The reason is that
                  * this client/user may not have access to the new

@@ -3442,20 +3451,26 @@
                  */
                 fh_fmtp = (nfs_fh4_fmt_t *)cs->fh.nfs_fh4_val;
 
                 /*
                  * if root filesystem is exported, the exportinfo struct that we
-                 * should use is what checkexport4 returns, because root_exi is
+                 * should use is what checkexport returns, because root_exi is
                  * actually a mostly empty struct.
                  */
-                exi = checkexport4(&fh_fmtp->fh4_fsid,
+                exi = checkexport(&fh_fmtp->fh4_fsid,
                     (fid_t *)&fh_fmtp->fh4_xlen, NULL);
-                cs->exi = ((exi != NULL) ? exi : exi_public);
+                if (exi) {
+                        cs->exi = exi;
+                } else {
+                        exi_hold(exi_public);
+                        cs->exi = exi_public;
+                }
         } else {
                 /*
                  * it's a properly shared filesystem
                  */
+                exi_hold(exi_public);
                 cs->exi = exi_public;
         }
 
         if (is_system_labeled()) {
                 bslabel_t *clabel;

@@ -3468,10 +3483,12 @@
                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
                         if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
                             cs->exi)) {
                                 *cs->statusp = resp->status =
                                     NFS4ERR_SERVERFAULT;
+                                if (sav_exi)
+                                        exi_rele(sav_exi);
                                 goto out;
                         }
                 }
         }
 

@@ -3479,13 +3496,16 @@
         cs->vp = vp;
 
         if ((resp->status = call_checkauth4(cs, req)) != NFS4_OK) {
                 VN_RELE(cs->vp);
                 cs->vp = NULL;
+                exi_rele(cs->exi);
                 cs->exi = sav_exi;
                 goto out;
         }
+        if (sav_exi)
+                exi_rele(sav_exi);
 
         *cs->statusp = resp->status = NFS4_OK;
 out:
         DTRACE_NFSV4_2(op__putpubfh__done, struct compound_state *, cs,
             PUTPUBFH4res *, resp);

@@ -3534,11 +3554,13 @@
                 *cs->statusp = resp->status = NFS4ERR_BADHANDLE;
                 goto out;
         }
 
         fh_fmtp = (nfs_fh4_fmt_t *)args->object.nfs_fh4_val;
-        cs->exi = checkexport4(&fh_fmtp->fh4_fsid, (fid_t *)&fh_fmtp->fh4_xlen,
+        if (cs->exi)
+                exi_rele(cs->exi);
+        cs->exi = checkexport(&fh_fmtp->fh4_fsid, (fid_t *)&fh_fmtp->fh4_xlen,
             NULL);
 
         if (cs->exi == NULL) {
                 *cs->statusp = resp->status = NFS4ERR_STALE;
                 goto out;

@@ -3608,25 +3630,28 @@
          * If the server root isn't exported directly, then
          * it should at least be a pseudo export based on
          * one or more exports further down in the server's
          * file tree.
          */
-        exi = checkexport4(&rootdir->v_vfsp->vfs_fsid, &fid, NULL);
+        exi = checkexport(&rootdir->v_vfsp->vfs_fsid, &fid, NULL);
         if (exi == NULL || exi->exi_export.ex_flags & EX_PUBLIC) {
                 NFS4_DEBUG(rfs4_debug,
                     (CE_WARN, "rfs4_op_putrootfh: export check failure"));
                 *cs->statusp = resp->status = NFS4ERR_SERVERFAULT;
+                if (exi)
+                        exi_rele(exi);
                 goto out;
         }
 
         /*
          * Now make a filehandle based on the root
          * export and root vnode.
          */
         error = makefh4(&cs->fh, rootdir, exi);
         if (error != 0) {
                 *cs->statusp = resp->status = puterrno4(error);
+                exi_rele(exi);
                 goto out;
         }
 
         sav_exi = cs->exi;
         cs->exi = exi;

@@ -3635,13 +3660,16 @@
         cs->vp = rootdir;
 
         if ((resp->status = call_checkauth4(cs, req)) != NFS4_OK) {
                 VN_RELE(rootdir);
                 cs->vp = NULL;
+                exi_rele(exi);
                 cs->exi = sav_exi;
                 goto out;
         }
+        if (sav_exi)
+                exi_rele(sav_exi);
 
         *cs->statusp = resp->status = NFS4_OK;
         cs->deleg = FALSE;
 out:
         DTRACE_NFSV4_2(op__putrootfh__done, struct compound_state *, cs,

@@ -4815,11 +4843,15 @@
         if (cs->vp != NULL) {
                 VN_RELE(cs->vp);
         }
         cs->vp = cs->saved_vp;
         cs->saved_vp = NULL;
+        if (cs->exi)
+                exi_rele(cs->exi);
         cs->exi = cs->saved_exi;
+        if (cs->exi)
+                exi_hold(cs->exi);
         nfs_fh4_copy(&cs->saved_fh, &cs->fh);
         *cs->statusp = resp->status = NFS4_OK;
         cs->deleg = FALSE;
 
 out:

@@ -4844,11 +4876,15 @@
         if (cs->saved_vp != NULL) {
                 VN_RELE(cs->saved_vp);
         }
         cs->saved_vp = cs->vp;
         VN_HOLD(cs->saved_vp);
+        if (cs->saved_exi)
+                exi_rele(cs->saved_exi);
         cs->saved_exi = cs->exi;
+        if (cs->saved_exi)
+                exi_hold(cs->saved_exi);
         /*
          * since SAVEFH is fairly rare, don't alloc space for its fh
          * unless necessary.
          */
         if (cs->saved_fh.nfs_fh4_val == NULL) {

@@ -5809,22 +5845,10 @@
 
         DTRACE_NFSV4_2(compound__start, struct compound_state *, &cs,
             COMPOUND4args *, args);
 
         /*
-         * For now, NFS4 compound processing must be protected by
-         * exported_lock because it can access more than one exportinfo
-         * per compound and share/unshare can now change multiple
-         * exinfo structs.  The NFS2/3 code only refs 1 exportinfo
-         * per proc (excluding public exinfo), and exi_count design
-         * is sufficient to protect concurrent execution of NFS2/3
-         * ops along with unexport.  This lock will be removed as
-         * part of the NFSv4 phase 2 namespace redesign work.
-         */
-        rw_enter(&exported_lock, RW_READER);
-
-        /*
          * If this is the first compound we've seen, we need to start all
          * new instances' grace periods.
          */
         if (rfs4_seen_first_compound == 0) {
                 rfs4_grace_start_new();

@@ -5889,15 +5913,18 @@
                         resp->array_len =  i + 1;
                         resp->array = new_res;
                 }
         }
 
-        rw_exit(&exported_lock);
 
         DTRACE_NFSV4_2(compound__done, struct compound_state *, &cs,
             COMPOUND4res *, resp);
 
+        if (cs.exi)
+                exi_rele(cs.exi);
+        if (cs.saved_exi)
+                exi_rele(cs.saved_exi);
         if (cs.vp)
                 VN_RELE(cs.vp);
         if (cs.saved_vp)
                 VN_RELE(cs.saved_vp);
         if (cs.saved_fh.nfs_fh4_val)

@@ -7494,11 +7521,13 @@
                          * it.
                          */
                         nfs_fh4_fmt_t *fh_fmtp =
                             (nfs_fh4_fmt_t *)oo->ro_reply_fh.nfs_fh4_val;
 
-                        cs->exi = checkexport4(&fh_fmtp->fh4_fsid,
+                        if (cs->exi)
+                                exi_rele(cs->exi);
+                        cs->exi = checkexport(&fh_fmtp->fh4_fsid,
                             (fid_t *)&fh_fmtp->fh4_xlen, NULL);
 
                         if (cs->exi == NULL) {
                                 resp->status = NFS4ERR_STALE;
                                 goto finish;