]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
NFSD: Track svc_export in nfs4_stid
authorChuck Lever <chuck.lever@oracle.com>
Sun, 19 Apr 2026 18:53:05 +0000 (14:53 -0400)
committerChuck Lever <cel@kernel.org>
Tue, 9 Jun 2026 20:32:59 +0000 (16:32 -0400)
Add an sc_export field to struct nfs4_stid so that each stateid
records the export under which it was acquired.  The export
reference is taken via exp_get() at stateid creation and released
via exp_put() in nfs4_put_stid().

Open stateids record the export from current_fh->fh_export.
Lock stateids and delegations inherit the export from their
parent open stateid. Layout stateids inherit from their
parent stateid. Directory delegations record the export from
cstate->current_fh.

A subsequent commit uses sc_export to scope state revocation to a
specific export, avoiding the need to walk inode dentry aliases at
revocation time.

Reviewed-by: Jeff Layton <jlayton@kernel.org>
Tested-by: Dai Ngo <dai.ngo@oracle.com>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
fs/nfsd/nfs4layouts.c
fs/nfsd/nfs4state.c
fs/nfsd/state.h

index c3543d45670245d5d555aa81d9a4905b8ab773b9..c550b83f443231155d6fe9dfe5c9abea8c9eb2e2 100644 (file)
@@ -234,6 +234,8 @@ nfsd4_alloc_layout_stateid(struct nfsd4_compound_state *cstate,
 
        get_nfs4_file(fp);
        stp->sc_file = fp;
+       if (parent->sc_export)
+               stp->sc_export = exp_get(parent->sc_export);
 
        ls = layoutstateid(stp);
        INIT_LIST_HEAD(&ls->ls_perclnt);
index d96994627ba83189645458f2e75da1056fc19894..475d2b36ecd1700c811b7056e85fdbb3781ae140 100644 (file)
@@ -1168,6 +1168,7 @@ out_dec:
 void
 nfs4_put_stid(struct nfs4_stid *s)
 {
+       struct svc_export *exp = s->sc_export;
        struct nfs4_file *fp = s->sc_file;
        struct nfs4_client *clp = s->sc_client;
 
@@ -1183,6 +1184,8 @@ nfs4_put_stid(struct nfs4_stid *s)
        nfs4_free_cpntf_statelist(clp->net, s);
        spin_unlock(&clp->cl_lock);
        s->sc_free(s);
+       if (exp)
+               exp_put(exp);
        if (fp)
                put_nfs4_file(fp);
 }
@@ -1763,6 +1766,25 @@ static struct nfs4_stid *find_one_sb_stid(struct nfs4_client *clp,
        return stid;
 }
 
+/*
+ * Release the export reference an admin-revoked stateid holds,
+ * so the svc_export (and its vfsmount) is not pinned until the
+ * client issues FREE_STATEID.  sc_export is no longer consulted
+ * once SC_STATUS_ADMIN_REVOKED is set.
+ */
+static void drop_stid_export(struct nfs4_client *clp,
+                            struct nfs4_stid *stid)
+{
+       struct svc_export *exp;
+
+       spin_lock(&clp->cl_lock);
+       exp = stid->sc_export;
+       stid->sc_export = NULL;
+       spin_unlock(&clp->cl_lock);
+       if (exp)
+               exp_put(exp);
+}
+
 static void revoke_ol_stid(struct nfs4_client *clp,
                           struct nfs4_ol_stateid *stp)
 {
@@ -1787,6 +1809,7 @@ static void revoke_ol_stid(struct nfs4_client *clp,
                        }
                }
                release_all_access(stp);
+               drop_stid_export(clp, stid);
        } else
                spin_unlock(&clp->cl_lock);
 }
@@ -1820,9 +1843,10 @@ static void revoke_one_stid(struct nfsd_net *nn, struct nfs4_client *clp,
                if (!unhash_delegation_locked(dp, SC_STATUS_ADMIN_REVOKED))
                        dp = NULL;
                spin_unlock(&nn->deleg_lock);
-               if (dp)
+               if (dp) {
                        revoke_delegation(dp);
-               else
+                       drop_stid_export(clp, stid);
+               } else
                        nfs4_put_stid(stid);
                break;
        case SC_TYPE_LAYOUT:
@@ -1833,6 +1857,7 @@ static void revoke_one_stid(struct nfsd_net *nn, struct nfs4_client *clp,
                }
                spin_unlock(&clp->cl_lock);
                nfsd4_close_layout(layoutstateid(stid));
+               drop_stid_export(clp, stid);
                break;
        }
 }
@@ -6172,6 +6197,8 @@ nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
        dp = alloc_init_deleg(clp, fp, odstate, dl_type);
        if (!dp)
                goto out_delegees;
+       if (stp->st_stid.sc_export)
+               dp->dl_stid.sc_export = exp_get(stp->st_stid.sc_export);
 
        fl = nfs4_alloc_init_lease(dp);
        if (!fl)
@@ -6505,8 +6532,11 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
                        goto out;
                }
 
-               if (!open->op_stp)
+               if (!open->op_stp) {
                        new_stp = true;
+                       stp->st_stid.sc_export =
+                               exp_get(current_fh->fh_export);
+               }
        }
 
        /*
@@ -8202,6 +8232,9 @@ retry:
        stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner);
        get_nfs4_file(fp);
        stp->st_stid.sc_file = fp;
+       if (open_stp->st_stid.sc_export)
+               stp->st_stid.sc_export =
+                       exp_get(open_stp->st_stid.sc_export);
        stp->st_access_bmap = 0;
        stp->st_deny_bmap = open_stp->st_deny_bmap;
        stp->st_openstp = open_stp;
@@ -9532,6 +9565,9 @@ nfsd_get_dir_deleg(struct nfsd4_compound_state *cstate,
        dp = alloc_init_deleg(clp, fp, NULL, NFS4_OPEN_DELEGATE_READ);
        if (!dp)
                goto out_delegees;
+       if (cstate->current_fh.fh_export)
+               dp->dl_stid.sc_export =
+                       exp_get(cstate->current_fh.fh_export);
 
        fl = nfs4_alloc_init_lease(dp);
        if (!fl)
index c5ccea64c2817f3e252e6d9be8657b7fe5a3f345..43bd965077e1d079e3ee26c8127cadef9db20d3e 100644 (file)
@@ -145,6 +145,7 @@ struct nfs4_stid {
        spinlock_t              sc_lock;
        struct nfs4_client      *sc_client;
        struct nfs4_file        *sc_file;
+       struct svc_export       *sc_export;
        void                    (*sc_free)(struct nfs4_stid *);
 };