From: cel@kernel.org
To: Olga Kornievskaia <okorniev@redhat.com>
Cc: <linux-nfs@vger.kernel.org>, Chuck Lever <chuck.lever@oracle.com>,
Jeff Layton <jlayton@kernel.org>
Subject: [RFC PATCH] NFS: CB_OFFLOAD should return DELAY when no copy state ID matches
Date: Thu, 13 Feb 2025 11:15:55 -0500 [thread overview]
Message-ID: <20250213161555.4914-1-cel@kernel.org> (raw)
From: Chuck Lever <chuck.lever@oracle.com>
The NFSv4.2 protocol requires that a client match a CB_OFFLOAD
callback to a COPY reply containing the same copy state ID. However,
it's possible that the order of the callback and reply processing on
the client can cause the CB_OFFLOAD to be received and processed
/before/ the client has dealt with the COPY reply.
Currently, in this case, the Linux NFS client will queue a fresh
struct nfs4_copy_state in the CB_OFFLOAD handler.
handle_async_copy() then checks for a matching nfs4_copy_state
before settling down to wait for a CB_OFFLOAD reply.
But it would be simpler for the client's callback service to respond
to such a CB_OFFLOAD with "I'm not ready yet" and have the server
send the CB_OFFLOAD again later. This avoids the need for the
client's CB_OFFLOAD processing to allocate an extra struct
nfs4_copy_state -- in most cases that allocation will be tossed
immediately, and it's one less memory allocation that we have to
worry about accidentally leaking or accumulating over time.
Suggested-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/nfs/callback_proc.c | 14 ++------------
fs/nfs/nfs42proc.c | 21 +--------------------
2 files changed, 3 insertions(+), 32 deletions(-)
Compile-tested only and pushed to my "fix-async-copy" branch...
File this in the "crazy ideas" bin, or maybe it makes sense ?
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c
index 8397c43358bd..cd2c3d196f22 100644
--- a/fs/nfs/callback_proc.c
+++ b/fs/nfs/callback_proc.c
@@ -712,14 +712,10 @@ __be32 nfs4_callback_offload(void *data, void *dummy,
struct cb_process_state *cps)
{
struct cb_offloadargs *args = data;
+ struct nfs4_copy_state *tmp_copy;
struct nfs_server *server;
- struct nfs4_copy_state *copy, *tmp_copy;
bool found = false;
- copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_KERNEL);
- if (!copy)
- return cpu_to_be32(NFS4ERR_DELAY);
-
spin_lock(&cps->clp->cl_lock);
rcu_read_lock();
list_for_each_entry_rcu(server, &cps->clp->cl_superblocks,
@@ -737,17 +733,11 @@ __be32 nfs4_callback_offload(void *data, void *dummy,
}
out:
rcu_read_unlock();
- if (!found) {
- memcpy(©->stateid, &args->coa_stateid, NFS4_STATEID_SIZE);
- nfs4_copy_cb_args(copy, args);
- list_add_tail(©->copies, &cps->clp->pending_cb_stateids);
- } else
- kfree(copy);
spin_unlock(&cps->clp->cl_lock);
trace_nfs4_cb_offload(&args->coa_fh, &args->coa_stateid,
args->wr_count, args->error,
args->wr_writeverf.committed);
- return 0;
+ return found ? cpu_to_be32(NFS4_OK) : cpu_to_be32(NFS4ERR_DELAY);
}
#endif /* CONFIG_NFS_V4_2 */
diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c
index 6e00bef97915..b332eafac8a2 100644
--- a/fs/nfs/nfs42proc.c
+++ b/fs/nfs/nfs42proc.c
@@ -197,11 +197,11 @@ static int handle_async_copy(struct nfs42_copy_res *res,
nfs4_stateid *src_stateid,
bool *restart)
{
- struct nfs4_copy_state *copy, *tmp_copy = NULL, *iter;
struct nfs_open_context *dst_ctx = nfs_file_open_context(dst);
struct nfs_open_context *src_ctx = nfs_file_open_context(src);
struct nfs_client *clp = dst_server->nfs_client;
unsigned long timeout = clp->cl_lease_time >> 1;
+ struct nfs4_copy_state *copy;
int status = NFS4_OK;
bool retry = false;
u64 copied;
@@ -211,28 +211,10 @@ static int handle_async_copy(struct nfs42_copy_res *res,
return -ENOMEM;
spin_lock(&dst_server->nfs_client->cl_lock);
- list_for_each_entry(iter,
- &dst_server->nfs_client->pending_cb_stateids,
- copies) {
- if (memcmp(&res->write_res.stateid, &iter->stateid,
- NFS4_STATEID_SIZE))
- continue;
- tmp_copy = iter;
- list_del(&iter->copies);
- break;
- }
- if (tmp_copy) {
- spin_unlock(&dst_server->nfs_client->cl_lock);
- kfree(copy);
- copy = tmp_copy;
- goto out;
- }
-
memcpy(©->stateid, &res->write_res.stateid, NFS4_STATEID_SIZE);
init_completion(©->completion);
copy->parent_dst_state = dst_ctx->state;
copy->parent_src_state = src_ctx->state;
-
list_add_tail(©->copies, &dst_server->ss_copies);
spin_unlock(&dst_server->nfs_client->cl_lock);
@@ -255,7 +237,6 @@ static int handle_async_copy(struct nfs42_copy_res *res,
*restart = true;
goto out_cancel;
}
-out:
res->write_res.count = copy->count;
/* Copy out the updated write verifier provided by CB_OFFLOAD. */
memcpy(&res->write_res.verifier, ©->verf, sizeof(copy->verf));
--
2.47.0
next reply other threads:[~2025-02-13 16:15 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-02-13 16:15 cel [this message]
2025-02-13 16:54 ` [RFC PATCH] NFS: CB_OFFLOAD should return DELAY when no copy state ID matches Trond Myklebust
2025-02-13 17:06 ` Chuck Lever
2025-02-13 17:29 ` Trond Myklebust
2025-02-13 17:53 ` Olga Kornievskaia
2025-02-13 18:44 ` Trond Myklebust
2025-02-13 18:47 ` Chuck Lever
2025-02-13 18:49 ` Trond Myklebust
2025-02-13 19:12 ` Trond Myklebust
2025-02-13 19:22 ` Chuck Lever
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=20250213161555.4914-1-cel@kernel.org \
--to=cel@kernel.org \
--cc=chuck.lever@oracle.com \
--cc=jlayton@kernel.org \
--cc=linux-nfs@vger.kernel.org \
--cc=okorniev@redhat.com \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.