]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
NFS4: Apply delay_retrans to async operations
authorJoshua Watt <jpewhacker@gmail.com>
Tue, 7 Oct 2025 21:22:58 +0000 (15:22 -0600)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 24 Nov 2025 09:35:47 +0000 (10:35 +0100)
[ Upstream commit 7a84394f02ab1985ebbe0a8d6f6d69bd040de4b3 ]

The setting of delay_retrans is applied to synchronous RPC operations
because the retransmit count is stored in same struct nfs4_exception
that is passed each time an error is checked. However, for asynchronous
operations (READ, WRITE, LOCKU, CLOSE, DELEGRETURN), a new struct
nfs4_exception is made on the stack each time the task callback is
invoked. This means that the retransmit count is always zero and thus
delay_retrans never takes effect.

Apply delay_retrans to these operations by tracking and updating their
retransmit count.

Change-Id: Ieb33e046c2b277cb979caa3faca7f52faf0568c9
Signed-off-by: Joshua Watt <jpewhacker@gmail.com>
Reviewed-by: Benjamin Coddington <bcodding@redhat.com>
Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/nfs/nfs4proc.c
include/linux/nfs_xdr.h

index b0ba9f2bef56be757720c1baaca296ff1892f0b5..a4531386c6485ed2bb43e5d5dc39f3275bdceb97 100644 (file)
@@ -3612,6 +3612,7 @@ struct nfs4_closedata {
        } lr;
        struct nfs_fattr fattr;
        unsigned long timestamp;
+       unsigned short retrans;
 };
 
 static void nfs4_free_closedata(void *data)
@@ -3640,6 +3641,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
                .state = state,
                .inode = calldata->inode,
                .stateid = &calldata->arg.stateid,
+               .retrans = calldata->retrans,
        };
 
        if (!nfs4_sequence_done(task, &calldata->res.seq_res))
@@ -3687,6 +3689,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
                default:
                        task->tk_status = nfs4_async_handle_exception(task,
                                        server, task->tk_status, &exception);
+                       calldata->retrans = exception.retrans;
                        if (exception.retry)
                                goto out_restart;
        }
@@ -5546,9 +5549,11 @@ static int nfs4_read_done_cb(struct rpc_task *task, struct nfs_pgio_header *hdr)
                        .inode = hdr->inode,
                        .state = hdr->args.context->state,
                        .stateid = &hdr->args.stateid,
+                       .retrans = hdr->retrans,
                };
                task->tk_status = nfs4_async_handle_exception(task,
                                server, task->tk_status, &exception);
+               hdr->retrans = exception.retrans;
                if (exception.retry) {
                        rpc_restart_call_prepare(task);
                        return -EAGAIN;
@@ -5662,10 +5667,12 @@ static int nfs4_write_done_cb(struct rpc_task *task,
                        .inode = hdr->inode,
                        .state = hdr->args.context->state,
                        .stateid = &hdr->args.stateid,
+                       .retrans = hdr->retrans,
                };
                task->tk_status = nfs4_async_handle_exception(task,
                                NFS_SERVER(inode), task->tk_status,
                                &exception);
+               hdr->retrans = exception.retrans;
                if (exception.retry) {
                        rpc_restart_call_prepare(task);
                        return -EAGAIN;
@@ -6677,6 +6684,7 @@ struct nfs4_delegreturndata {
        struct nfs_fh fh;
        nfs4_stateid stateid;
        unsigned long timestamp;
+       unsigned short retrans;
        struct {
                struct nfs4_layoutreturn_args arg;
                struct nfs4_layoutreturn_res res;
@@ -6697,6 +6705,7 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
                .inode = data->inode,
                .stateid = &data->stateid,
                .task_is_privileged = data->args.seq_args.sa_privileged,
+               .retrans = data->retrans,
        };
 
        if (!nfs4_sequence_done(task, &data->res.seq_res))
@@ -6768,6 +6777,7 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
                task->tk_status = nfs4_async_handle_exception(task,
                                data->res.server, task->tk_status,
                                &exception);
+               data->retrans = exception.retrans;
                if (exception.retry)
                        goto out_restart;
        }
@@ -7044,6 +7054,7 @@ struct nfs4_unlockdata {
        struct file_lock fl;
        struct nfs_server *server;
        unsigned long timestamp;
+       unsigned short retrans;
 };
 
 static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl,
@@ -7098,6 +7109,7 @@ static void nfs4_locku_done(struct rpc_task *task, void *data)
        struct nfs4_exception exception = {
                .inode = calldata->lsp->ls_state->inode,
                .stateid = &calldata->arg.stateid,
+               .retrans = calldata->retrans,
        };
 
        if (!nfs4_sequence_done(task, &calldata->res.seq_res))
@@ -7131,6 +7143,7 @@ static void nfs4_locku_done(struct rpc_task *task, void *data)
                        task->tk_status = nfs4_async_handle_exception(task,
                                        calldata->server, task->tk_status,
                                        &exception);
+                       calldata->retrans = exception.retrans;
                        if (exception.retry)
                                rpc_restart_call_prepare(task);
        }
index b48d94f099657caf5a04ac0016d309956091b3c8..b7a08c875514f1529845aa5ea1e2956709e0deb0 100644 (file)
@@ -1660,6 +1660,7 @@ struct nfs_pgio_header {
        void                    *netfs;
 #endif
 
+       unsigned short          retrans;
        int                     pnfs_error;
        int                     error;          /* merge with pnfs_error */
        unsigned int            good_bytes;     /* boundary of good data */