[PATCH v3 1/6] nfsd: add routines to get/put session references for callbacks

From: Jeff Layton
Date: Wed Jan 29 2025 - 18:21:03 EST


The existing session reference counting is too heavyweight for
callbacks. There is an atomic refcount in nfsd4_session (se_ref), but
the existing functions take a client reference alongside it, and require
the nn->client_lock. This is unnecessary for callbacks as they are
already owned by the client.

Add new nfsd4_cb_get_session() and nfsd4_cb_put_session() calls that
take and put a session reference on behalf of a callback.

Signed-off-by: Jeff Layton <jlayton@xxxxxxxxxx>
---
fs/nfsd/nfs4state.c | 34 ++++++++++++++++++++++++++++++++--
fs/nfsd/state.h | 2 ++
2 files changed, 34 insertions(+), 2 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index cc819b8e8acdf5dcfe44c5bae45c6233f7b695e9..db68fd579ff0454153537817ee3cca71303654b4 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -234,6 +234,37 @@ static void put_client_renew(struct nfs4_client *clp)
spin_unlock(&nn->client_lock);
}

+/**
+ * nfsd4_cb_get_session - get a session reference for a callback
+ * @ses: session of which to get a reference
+ *
+ * Callbacks are different than client-driven RPCs. The caller doesn't
+ * need a reference to the nfs4_client, and doesn't want to renew the
+ * lease when putting the reference. Returns true if a session was
+ * acquired, or false otherwise (which indicates that the session is
+ * dead).
+ */
+bool nfsd4_cb_get_session(struct nfsd4_session *ses)
+{
+ if (is_session_dead(ses))
+ return false;
+ return atomic_inc_not_zero(&ses->se_ref);
+}
+
+/**
+ * nfsd4_cb_put_session - put a session reference for a callback
+ * @ses: session of which to put a reference
+ *
+ * Callbacks are different than client-driven RPCs. The caller doesn't
+ * need a reference to the nfs4_client, and doesn't want to renew the
+ * lease when putting the reference.
+ */
+void nfsd4_cb_put_session(struct nfsd4_session *ses)
+{
+ if (ses && atomic_dec_and_test(&ses->se_ref) && is_session_dead(ses))
+ free_session(ses);
+}
+
static __be32 nfsd4_get_session_locked(struct nfsd4_session *ses)
{
__be32 status;
@@ -254,8 +285,7 @@ static void nfsd4_put_session_locked(struct nfsd4_session *ses)

lockdep_assert_held(&nn->client_lock);

- if (atomic_dec_and_test(&ses->se_ref) && is_session_dead(ses))
- free_session(ses);
+ nfsd4_cb_put_session(ses);
put_client_renew_locked(clp);
}

diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 74d2d7b42676d907bec9159b927aeed223d668c3..79d985d2a656e1a5b22a6a9c88f309515725e847 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -753,6 +753,8 @@ struct nfsd4_compound_state;
struct nfsd_net;
struct nfsd4_copy;

+bool nfsd4_cb_get_session(struct nfsd4_session *ses);
+void nfsd4_cb_put_session(struct nfsd4_session *ses);
extern __be32 nfs4_preprocess_stateid_op(struct svc_rqst *rqstp,
struct nfsd4_compound_state *cstate, struct svc_fh *fhp,
stateid_t *stateid, int flags, struct nfsd_file **filp,

--
2.48.1