[RFC PATCH] NFS: CB_OFFLOAD should return DELAY when no copy state ID matches

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Chuck Lever <chuck.lever@xxxxxxxxxx>

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@xxxxxxxxxx>
Signed-off-by: Chuck Lever <chuck.lever@xxxxxxxxxx>
---
 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(&copy->stateid, &args->coa_stateid, NFS4_STATEID_SIZE);
-		nfs4_copy_cb_args(copy, args);
-		list_add_tail(&copy->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(&copy->stateid, &res->write_res.stateid, NFS4_STATEID_SIZE);
 	init_completion(&copy->completion);
 	copy->parent_dst_state = dst_ctx->state;
 	copy->parent_src_state = src_ctx->state;
-
 	list_add_tail(&copy->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, &copy->verf, sizeof(copy->verf));
-- 
2.47.0





[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux