From: Daejun Park via B4 Relay <devnull+daejun7.park.samsung.com@kernel.org>
To: Chuck Lever <cel@kernel.org>, Jeff Layton <jlayton@kernel.org>,
NeilBrown <neil@brown.name>,
Olga Kornievskaia <okorniev@redhat.com>,
Dai Ngo <Dai.Ngo@oracle.com>, Tom Talpey <tom@talpey.com>
Cc: Christoph Hellwig <hch@lst.de>,
Benjamin Coddington <ben.coddington@hammerspace.com>,
Trond Myklebust <trondmy@kernel.org>,
Anna Schumaker <anna@kernel.org>,
linux-nfs@vger.kernel.org, linux-kernel@vger.kernel.org,
Daejun Park <daejun7.park@samsung.com>
Subject: [PATCH v2 1/4] nfsd: share the grant slot record between delegations and layouts
Date: Fri, 23 Oct 2026 11:10:22 +0900 [thread overview]
Message-ID: <20261023-nfsd-layout-refcall-v2-1-2160bddced0c@samsung.com> (raw)
In-Reply-To: <20261023-nfsd-layout-refcall-v2-0-2160bddced0c@samsung.com>
From: Daejun Park <daejun7.park@samsung.com>
The delegation code remembers the forward-channel slot that carried the
request that granted a delegation (dl_recall_grant), tests whether the
client has retired that slot since (nfsd4_recall_grant_slot_retired()),
and names the request as a referring call in the CB_SEQUENCE of a
recall. The next two patches need the same for layouts.
Make the record a type of its own, struct nfsd4_grant_slot, and move the
code that fills it in, the slot test and the code that adds the
referring call into nfsd41_record_grant_slot(),
nfsd41_grant_slot_retired() and nfsd41_cb_referring_grant(), named for
the session machinery they depend on. The flag that was part of the
delegation's record stays with the delegation, as
dl_recall_retired_at_send.
No change in behavior.
Signed-off-by: Daejun Park <daejun7.park@samsung.com>
---
fs/nfsd/nfs4state.c | 115 ++++++++++++++++++++++++++++++++++++----------------
fs/nfsd/state.h | 24 +++++++----
2 files changed, 96 insertions(+), 43 deletions(-)
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index f2b52ba901..735eaa4b7f 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1291,7 +1291,7 @@ __alloc_init_deleg(struct nfs4_client *clp, struct nfs4_file *fp,
dp->dl_recalled = false;
dp->dl_recall_rejected = false;
dp->dl_recall_grant.valid = false;
- dp->dl_recall_grant.retired_at_send = false;
+ dp->dl_recall_retired_at_send = false;
get_nfs4_file(fp);
dp->dl_stid.sc_file = fp;
nfsd4_init_cb(&dp->dl_recall, dp->dl_stid.sc_client,
@@ -6251,37 +6251,49 @@ bool nfsd_wait_for_delegreturn(struct svc_rqst *rqstp, struct inode *inode)
* gen_sessionid() composes a sessionid from the client's clientid and a
* sequence counter, so the sequence alone identifies the granting session.
*/
-static void nfsd4_recall_grant_sessionid(const struct nfs4_delegation *dp,
- struct nfsd4_sessionid *sid)
+static void nfsd41_grant_slot_sessionid(struct nfs4_client *clp,
+ const struct nfsd4_grant_slot *grant,
+ struct nfsd4_sessionid *sid)
{
- sid->clientid = dp->dl_stid.sc_client->cl_clientid;
- sid->sequence = dp->dl_recall_grant.sessionid_seq;
+ sid->clientid = clp->cl_clientid;
+ sid->sequence = grant->sessionid_seq;
sid->reserved = 0;
}
-static bool nfsd4_recall_grant_slot_retired(struct nfs4_delegation *dp)
+/**
+ * nfsd41_grant_slot_retired - has the client seen the reply to a grant?
+ * @clp: client that sent the granting request
+ * @grant: forward-channel slot that carried the request
+ *
+ * Context: Takes nn->client_lock.
+ *
+ * Return: true if the client has gone on to use the slot for a later
+ * request, or has given the slot up, so that it must have received the
+ * reply. False if that cannot be shown, and if @grant is not valid.
+ */
+bool nfsd41_grant_slot_retired(struct nfs4_client *clp,
+ const struct nfsd4_grant_slot *grant)
{
- struct nfs4_client *clp = dp->dl_stid.sc_client;
struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
struct nfsd4_session *ses;
struct nfsd4_sessionid sid;
bool retired = false;
void *entry;
- if (!dp->dl_recall_grant.valid)
+ if (!grant->valid)
return false;
- nfsd4_recall_grant_sessionid(dp, &sid);
+ nfsd41_grant_slot_sessionid(clp, grant, &sid);
/*
- * A missing session does not prove the client saw the grant: a
+ * A missing session does not prove the client saw the reply: a
* DESTROY_SESSION unhashes its own session before the reply to
* that compound is encoded.
*/
spin_lock(&nn->client_lock);
ses = __find_in_sessionid_hashtbl((struct nfs4_sessionid *)&sid,
clp->net);
- entry = ses ? xa_load(&ses->se_slots, dp->dl_recall_grant.slotid) : NULL;
+ entry = ses ? xa_load(&ses->se_slots, grant->slotid) : NULL;
if (xa_is_value(entry)) {
/*
* A slot is freed only once the client has acknowledged
@@ -6294,18 +6306,49 @@ static bool nfsd4_recall_grant_slot_retired(struct nfs4_delegation *dp)
/*
* A reactivated slot was freed and rebuilt, so the same
- * acknowledgment applies. The seqid test errs toward
- * revoking: a rebuilt slot restarting at seqid 1 matches
- * an old grant.
+ * acknowledgment applies. The seqid test errs toward "not
+ * retired", the side on which the callers do not take the
+ * client's answer at once: a rebuilt slot restarting at
+ * seqid 1 matches an old grant.
*/
retired = (slot->sl_flags & NFSD4_SLOT_REUSED) ||
((slot->sl_flags & NFSD4_SLOT_INITIALIZED) &&
- slot->sl_seqid != dp->dl_recall_grant.seqid);
+ slot->sl_seqid != grant->seqid);
}
spin_unlock(&nn->client_lock);
return retired;
}
+/**
+ * nfsd41_cb_referring_grant - name a granting request as referring call
+ * @cb: callback that refers to state the request created
+ * @clp: client that sent the request
+ * @grant: forward-channel slot that carried the request
+ *
+ * Does nothing if @grant is not valid.
+ *
+ * Context: May sleep. Caller serializes access to @cb, as for
+ * nfsd41_cb_referring_call().
+ */
+void nfsd41_cb_referring_grant(struct nfsd4_callback *cb,
+ struct nfs4_client *clp,
+ const struct nfsd4_grant_slot *grant)
+{
+ struct nfsd4_sessionid sid;
+
+ if (!grant->valid)
+ return;
+ nfsd41_grant_slot_sessionid(clp, grant, &sid);
+ nfsd41_cb_referring_call(cb, (struct nfs4_sessionid *)&sid,
+ grant->slotid, grant->seqid);
+}
+
+static bool nfsd4_recall_grant_slot_retired(struct nfs4_delegation *dp)
+{
+ return nfsd41_grant_slot_retired(dp->dl_stid.sc_client,
+ &dp->dl_recall_grant);
+}
+
/*
* ->prepare does not run on every send: nfsd4_run_cb_work() skips it
* on a requeue, and a retry via rpc_restart_call_prepare() re-enters
@@ -6315,9 +6358,9 @@ static bool nfsd4_recall_grant_slot_retired(struct nfs4_delegation *dp)
*/
static void nfsd4_refresh_recall_grant(struct nfs4_delegation *dp)
{
- dp->dl_recall_grant.retired_at_send =
+ dp->dl_recall_retired_at_send =
nfsd4_recall_grant_slot_retired(dp);
- if (dp->dl_recall_grant.retired_at_send)
+ if (dp->dl_recall_retired_at_send)
nfsd41_cb_destroy_referring_call_list(&dp->dl_recall);
}
@@ -6345,15 +6388,9 @@ static bool nfsd4_cb_recall_prepare(struct nfsd4_callback *cb)
nfsd4_refresh_recall_grant(dp);
- if (dp->dl_recall_grant.valid && !dp->dl_recall_grant.retired_at_send) {
- struct nfsd4_sessionid sid;
-
- nfsd4_recall_grant_sessionid(dp, &sid);
- nfsd41_cb_referring_call(&dp->dl_recall,
- (struct nfs4_sessionid *)&sid,
- dp->dl_recall_grant.slotid,
- dp->dl_recall_grant.seqid);
- }
+ if (!dp->dl_recall_retired_at_send)
+ nfsd41_cb_referring_grant(&dp->dl_recall, dp->dl_stid.sc_client,
+ &dp->dl_recall_grant);
return true;
}
@@ -6405,7 +6442,7 @@ static int nfsd4_cb_recall_done(struct nfsd4_callback *cb,
* the grant. Trust the rejection only if the slot had
* retired when this recall was sent.
*/
- if (dp->dl_recall_grant.retired_at_send) {
+ if (dp->dl_recall_retired_at_send) {
nfsd4_deleg_recall_rejected(dp);
return 1;
}
@@ -7014,19 +7051,25 @@ static bool nfsd4_want_read_deleg(const struct nfsd4_open *open)
OPEN4_SHARE_ACCESS_WANT_READ_DELEG;
}
-static void
-nfs4_delegation_record_grant_slot(struct nfs4_delegation *dp,
- const struct nfsd4_compound_state *cstate)
+/**
+ * nfsd41_record_grant_slot - remember the slot that carries a request
+ * @grant: record to fill in
+ * @cstate: compound state of the request
+ *
+ * Leaves @grant alone for a request without a session (NFSv4.0).
+ */
+void nfsd41_record_grant_slot(struct nfsd4_grant_slot *grant,
+ const struct nfsd4_compound_state *cstate)
{
const struct nfsd4_sessionid *sid;
if (!cstate->session)
return;
sid = (struct nfsd4_sessionid *)cstate->session->se_sessionid.data;
- dp->dl_recall_grant.sessionid_seq = sid->sequence;
- dp->dl_recall_grant.slotid = cstate->slot->sl_index;
- dp->dl_recall_grant.seqid = cstate->slot->sl_seqid;
- dp->dl_recall_grant.valid = true;
+ grant->sessionid_seq = sid->sequence;
+ grant->slotid = cstate->slot->sl_index;
+ grant->seqid = cstate->slot->sl_seqid;
+ grant->valid = true;
}
static struct nfs4_delegation *
@@ -7135,7 +7178,7 @@ nfs4_set_delegation(struct nfsd4_open *open,
* visible to lease breakers. A conflicting open can drive
* CB_RECALL to completion from that point on.
*/
- nfs4_delegation_record_grant_slot(dp, cstate);
+ nfsd41_record_grant_slot(&dp->dl_recall_grant, cstate);
if (stp->st_stid.sc_export)
dp->dl_stid.sc_export = exp_get(stp->st_stid.sc_export);
@@ -10771,7 +10814,7 @@ nfsd_get_dir_deleg(struct nfsd4_compound_state *cstate,
dp = alloc_init_dir_deleg(clp, fp);
if (!dp)
goto out_delegees;
- nfs4_delegation_record_grant_slot(dp, cstate);
+ nfsd41_record_grant_slot(&dp->dl_recall_grant, cstate);
if (cstate->current_fh.fh_export)
dp->dl_stid.sc_export =
exp_get(cstate->current_fh.fh_export);
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 5f43668486..2c00b334c3 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -276,6 +276,14 @@ struct nfsd4_cb_notify {
struct nfsd4_callback ncn_cb; // notify4 callback
};
+/* Forward-channel slot that carried a request which created state */
+struct nfsd4_grant_slot {
+ u32 sessionid_seq;
+ u32 slotid;
+ u32 seqid;
+ bool valid;
+};
+
/*
* Represents a delegation stateid. The nfs4_client holds references to these
* and they are put when it is being destroyed or when the delegation is
@@ -315,13 +323,8 @@ struct nfs4_delegation {
bool dl_setattr;
/* Forward-channel slot that carried the granting request */
- struct {
- u32 sessionid_seq;
- u32 slotid;
- u32 seqid;
- bool valid;
- bool retired_at_send;
- } dl_recall_grant;
+ struct nfsd4_grant_slot dl_recall_grant;
+ bool dl_recall_retired_at_send;
union {
/* for CB_GETATTR */
@@ -949,6 +952,13 @@ extern void nfsd41_cb_referring_call(struct nfsd4_callback *cb,
struct nfs4_sessionid *sessionid,
u32 slotid, u32 seqno);
extern void nfsd41_cb_destroy_referring_call_list(struct nfsd4_callback *cb);
+extern void nfsd41_record_grant_slot(struct nfsd4_grant_slot *grant,
+ const struct nfsd4_compound_state *cstate);
+extern bool nfsd41_grant_slot_retired(struct nfs4_client *clp,
+ const struct nfsd4_grant_slot *grant);
+extern void nfsd41_cb_referring_grant(struct nfsd4_callback *cb,
+ struct nfs4_client *clp,
+ const struct nfsd4_grant_slot *grant);
extern void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp,
const struct nfsd4_callback_ops *ops, enum nfsd4_cb_op op);
extern bool nfsd4_run_cb(struct nfsd4_callback *cb);
--
2.43.0
next prev parent reply other threads:[~2026-10-23 2:10 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-23 2:10 [PATCH v2 0/4] nfsd: keep a layout whose recall overtakes the LAYOUTGET reply Daejun Park via B4 Relay
2026-10-23 2:10 ` Daejun Park via B4 Relay [this message]
2026-10-23 2:10 ` [PATCH v2 2/4] nfsd: resend a layout recall once before trusting NOMATCHING_LAYOUT Daejun Park via B4 Relay
2026-10-23 2:10 ` [PATCH v2 3/4] nfsd: send a referring call with CB_LAYOUTRECALL Daejun Park via B4 Relay
2026-10-23 2:10 ` [PATCH v2 4/4] nfsd: do not fail a LAYOUTGET on a lease break by the same client Daejun Park via B4 Relay
2026-10-23 10:54 ` [PATCH v2 0/4] nfsd: keep a layout whose recall overtakes the LAYOUTGET reply Jeff Layton
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261023-nfsd-layout-refcall-v2-1-2160bddced0c@samsung.com \
--to=devnull+daejun7.park.samsung.com@kernel.org \
--cc=Dai.Ngo@oracle.com \
--cc=anna@kernel.org \
--cc=ben.coddington@hammerspace.com \
--cc=cel@kernel.org \
--cc=daejun7.park@samsung.com \
--cc=hch@lst.de \
--cc=jlayton@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-nfs@vger.kernel.org \
--cc=neil@brown.name \
--cc=okorniev@redhat.com \
--cc=tom@talpey.com \
--cc=trondmy@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®