* [PATCH v3 1/4] cifs: on replayable errors back-off before replay, not after
@ 2026-01-29 17:37 nspmangalore
2026-01-29 17:37 ` [PATCH v3 2/4] netfs: when subreq is marked for retry, do not check if it faced an error nspmangalore
` (3 more replies)
0 siblings, 4 replies; 10+ messages in thread
From: nspmangalore @ 2026-01-29 17:37 UTC (permalink / raw)
To: linux-cifs, smfrench, pc, bharathsm, dhowells, netfs; +Cc: Shyam Prasad N
From: Shyam Prasad N <sprasad@microsoft.com>
On replayable errors, we call smb2_should_replays that does these
things today:
1. decide if we need to replay the command again
2. sleep to back-off the failed request
3. update the next sleep value
We will not be able to use this for async requests, when this is
processed in callbacks (as this will be called in cifsd threads that
should not sleep in response processing).
Modify the behaviour by taking the sleep out of smb2_should_replay
and performing the sleep for back-off just before actually
performing the replay.
Signed-off-by: Shyam Prasad N <sprasad@microsoft.com>
---
fs/smb/client/cached_dir.c | 6 +-
fs/smb/client/smb2inode.c | 21 +++++--
fs/smb/client/smb2ops.c | 32 ++++++++---
fs/smb/client/smb2pdu.c | 112 +++++++++++++++++++++++++++----------
4 files changed, 129 insertions(+), 42 deletions(-)
diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c
index 1db7ab6c2529c..df9977030d199 100644
--- a/fs/smb/client/cached_dir.c
+++ b/fs/smb/client/cached_dir.c
@@ -154,7 +154,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
struct cached_fid *cfid;
struct cached_fids *cfids;
const char *npath;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
__le32 lease_flags = 0;
if (cifs_sb->root == NULL)
@@ -304,6 +304,10 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
smb2_set_related(&rqst[1]);
if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
+
smb2_set_replay(server, &rqst[0]);
smb2_set_replay(server, &rqst[1]);
}
diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c
index 2ded3246600c0..498a26a7bd415 100644
--- a/fs/smb/client/smb2inode.c
+++ b/fs/smb/client/smb2inode.c
@@ -188,7 +188,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
struct reparse_data_buffer *rbuf;
struct TCP_Server_Info *server;
int resp_buftype[MAX_COMPOUND];
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
__u8 delete_pending[8] = {1,};
struct kvec *rsp_iov, *iov;
struct inode *inode = NULL;
@@ -638,18 +638,26 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
num_rqst++;
if (cfile) {
- if (retries)
+ if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
for (i = 1; i < num_rqst - 2; i++)
smb2_set_replay(server, &rqst[i]);
+ }
rc = compound_send_recv(xid, ses, server,
flags, num_rqst - 2,
&rqst[1], &resp_buftype[1],
&rsp_iov[1]);
} else {
- if (retries)
+ if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
for (i = 0; i < num_rqst; i++)
smb2_set_replay(server, &rqst[i]);
+ }
rc = compound_send_recv(xid, ses, server,
flags, num_rqst,
@@ -1180,7 +1188,7 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
{
struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
__le16 *utf16_path __free(kfree) = NULL;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
struct TCP_Server_Info *server;
struct cifs_open_parms oparms;
struct smb2_create_req *creq;
@@ -1242,6 +1250,9 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
goto err_free;
if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
for (int i = 0; i < ARRAY_SIZE(rqst); i++)
smb2_set_replay(server, &rqst[i]);
}
@@ -1262,7 +1273,7 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
if (rc == -EINVAL && dentry) {
dentry = NULL;
retries = 0;
- cur_sleep = 1;
+ cur_sleep = 0;
goto again;
}
/*
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index a16ded46b5a26..7980c6f80730f 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -1184,7 +1184,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
struct smb2_file_full_ea_info *ea;
struct smb2_query_info_rsp *rsp;
int rc, used_len = 0;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
replay_again:
/* reinitialize for possible replay */
@@ -1314,6 +1314,9 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
smb2_set_related(&rqst[2]);
if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
smb2_set_replay(server, &rqst[0]);
smb2_set_replay(server, &rqst[1]);
smb2_set_replay(server, &rqst[2]);
@@ -1582,7 +1585,7 @@ smb2_ioctl_query_info(const unsigned int xid,
void *data[2];
int create_options = is_dir ? CREATE_NOT_FILE : CREATE_NOT_DIR;
void (*free_req1_func)(struct smb_rqst *r);
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
replay_again:
/* reinitialize for possible replay */
@@ -1731,6 +1734,9 @@ smb2_ioctl_query_info(const unsigned int xid,
smb2_set_related(&rqst[2]);
if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
smb2_set_replay(server, &rqst[0]);
smb2_set_replay(server, &rqst[1]);
smb2_set_replay(server, &rqst[2]);
@@ -2440,7 +2446,7 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
struct smb2_query_directory_rsp *qd_rsp = NULL;
struct smb2_create_rsp *op_rsp = NULL;
struct TCP_Server_Info *server;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
replay_again:
/* reinitialize for possible replay */
@@ -2498,6 +2504,9 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
smb2_set_related(&rqst[1]);
if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
smb2_set_replay(server, &rqst[0]);
smb2_set_replay(server, &rqst[1]);
}
@@ -2774,10 +2783,14 @@ bool smb2_should_replay(struct cifs_tcon *tcon,
return false;
if (tcon->retry || (*pretries)++ < tcon->ses->server->retrans) {
- msleep(*pcur_sleep);
- (*pcur_sleep) = ((*pcur_sleep) << 1);
- if ((*pcur_sleep) > CIFS_MAX_SLEEP)
- (*pcur_sleep) = CIFS_MAX_SLEEP;
+ /* Update sleep time for exponential backoff */
+ if (!(*pcur_sleep))
+ (*pcur_sleep) = 1;
+ else {
+ (*pcur_sleep) = ((*pcur_sleep) << 1);
+ if ((*pcur_sleep) > CIFS_MAX_SLEEP)
+ (*pcur_sleep) = CIFS_MAX_SLEEP;
+ }
return true;
}
@@ -2808,7 +2821,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
int rc;
__le16 *utf16_path;
struct cached_fid *cfid;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
replay_again:
/* reinitialize for possible replay */
@@ -2898,6 +2911,9 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
smb2_set_related(&rqst[2]);
if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
if (!cfid) {
smb2_set_replay(server, &rqst[0]);
smb2_set_replay(server, &rqst[2]);
diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index 5d57c895ca37a..7d75ba675f774 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -2904,7 +2904,7 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
unsigned int total_len;
__le16 *utf16_path = NULL;
struct TCP_Server_Info *server;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
replay_again:
/* reinitialize for possible replay */
@@ -3016,8 +3016,12 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
trace_smb3_posix_mkdir_enter(xid, tcon->tid, ses->Suid, full_path, CREATE_NOT_FILE,
FILE_WRITE_ATTRIBUTES);
- if (retries)
+ if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
smb2_set_replay(server, &rqst);
+ }
/* resource #4: response buffer */
rc = cifs_send_recv(xid, ses, server,
@@ -3265,7 +3269,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
int resp_buftype = CIFS_NO_BUFFER;
int rc = 0;
int flags = 0;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
replay_again:
/* reinitialize for possible replay */
@@ -3293,8 +3297,12 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
trace_smb3_open_enter(xid, tcon->tid, tcon->ses->Suid, oparms->path,
oparms->create_options, oparms->desired_access);
- if (retries)
+ if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
smb2_set_replay(server, &rqst);
+ }
rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buftype, flags,
@@ -3478,7 +3486,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
int resp_buftype = CIFS_NO_BUFFER;
int rc = 0;
int flags = 0;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
if (!tcon)
return smb_EIO(smb_eio_trace_null_pointers);
@@ -3518,8 +3526,12 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
if (rc)
goto ioctl_exit;
- if (retries)
+ if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
smb2_set_replay(server, &rqst);
+ }
rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buftype, flags,
@@ -3675,7 +3687,7 @@ __SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
int rc = 0;
int flags = 0;
bool query_attrs = false;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
replay_again:
/* reinitialize for possible replay */
@@ -3707,8 +3719,12 @@ __SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
if (rc)
goto close_exit;
- if (retries)
+ if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
smb2_set_replay(server, &rqst);
+ }
rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buftype, flags, &rsp_iov);
@@ -3878,7 +3894,7 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
struct TCP_Server_Info *server;
int flags = 0;
bool allocated = false;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
cifs_dbg(FYI, "Query Info\n");
@@ -3912,8 +3928,12 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
trace_smb3_query_info_enter(xid, persistent_fid, tcon->tid,
ses->Suid, info_class, (__u32)info_type);
- if (retries)
+ if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
smb2_set_replay(server, &rqst);
+ }
rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buftype, flags, &rsp_iov);
@@ -4069,7 +4089,7 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
int resp_buftype = CIFS_NO_BUFFER;
int flags = 0;
int rc = 0;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
replay_again:
/* reinitialize for possible replay */
@@ -4100,8 +4120,12 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
trace_smb3_notify_enter(xid, persistent_fid, tcon->tid, ses->Suid,
(u8)watch_tree, completion_filter);
- if (retries)
+ if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
smb2_set_replay(server, &rqst);
+ }
rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buftype, flags, &rsp_iov);
@@ -4405,7 +4429,7 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
int resp_buftype = CIFS_NO_BUFFER;
int flags = 0;
int rc = 0;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
replay_again:
/* reinitialize for possible replay */
@@ -4431,8 +4455,12 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
trace_smb3_flush_enter(xid, persistent_fid, tcon->tid, ses->Suid);
- if (retries)
+ if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
smb2_set_replay(server, &rqst);
+ }
rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buftype, flags, &rsp_iov);
@@ -5190,7 +5218,7 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
int flags = 0;
unsigned int total_len;
struct TCP_Server_Info *server;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
replay_again:
/* reinitialize for possible replay */
@@ -5238,8 +5266,12 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
rqst.rq_iov = iov;
rqst.rq_nvec = n_vec + 1;
- if (retries)
+ if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
smb2_set_replay(server, &rqst);
+ }
rc = cifs_send_recv(xid, io_parms->tcon->ses, server,
&rqst,
@@ -5590,7 +5622,7 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_ses *ses = tcon->ses;
struct TCP_Server_Info *server;
int flags = 0;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
replay_again:
/* reinitialize for possible replay */
@@ -5615,8 +5647,12 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
if (rc)
goto qdir_exit;
- if (retries)
+ if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
smb2_set_replay(server, &rqst);
+ }
rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buftype, flags, &rsp_iov);
@@ -5725,7 +5761,7 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_ses *ses = tcon->ses;
struct TCP_Server_Info *server;
int flags = 0;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
replay_again:
/* reinitialize for possible replay */
@@ -5758,8 +5794,12 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
return rc;
}
- if (retries)
+ if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
smb2_set_replay(server, &rqst);
+ }
rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buftype, flags,
@@ -5838,7 +5878,7 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
struct kvec iov[1];
struct kvec rsp_iov;
int resp_buf_type;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
replay_again:
/* reinitialize for possible replay */
@@ -5868,8 +5908,12 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
rqst.rq_iov = iov;
rqst.rq_nvec = 1;
- if (retries)
+ if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
smb2_set_replay(server, &rqst);
+ }
rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buf_type, flags, &rsp_iov);
@@ -5971,7 +6015,7 @@ SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon,
struct TCP_Server_Info *server;
FILE_SYSTEM_POSIX_INFO *info = NULL;
int flags = 0;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
replay_again:
/* reinitialize for possible replay */
@@ -5992,8 +6036,12 @@ SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon,
rqst.rq_iov = &iov;
rqst.rq_nvec = 1;
- if (retries)
+ if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
smb2_set_replay(server, &rqst);
+ }
rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buftype, flags, &rsp_iov);
@@ -6036,7 +6084,7 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
struct TCP_Server_Info *server;
unsigned int rsp_len, offset;
int flags = 0;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
replay_again:
/* reinitialize for possible replay */
@@ -6073,8 +6121,12 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
rqst.rq_iov = &iov;
rqst.rq_nvec = 1;
- if (retries)
+ if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
smb2_set_replay(server, &rqst);
+ }
rc = cifs_send_recv(xid, ses, server,
&rqst, &resp_buftype, flags, &rsp_iov);
@@ -6136,7 +6188,7 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
int flags = CIFS_NO_RSP_BUF;
unsigned int total_len;
struct TCP_Server_Info *server;
- int retries = 0, cur_sleep = 1;
+ int retries = 0, cur_sleep = 0;
replay_again:
/* reinitialize for possible replay */
@@ -6172,8 +6224,12 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
rqst.rq_iov = iov;
rqst.rq_nvec = 2;
- if (retries)
+ if (retries) {
+ /* Back-off before retry */
+ if (cur_sleep)
+ msleep(cur_sleep);
smb2_set_replay(server, &rqst);
+ }
rc = cifs_send_recv(xid, tcon->ses, server,
&rqst, &resp_buf_type, flags,
--
2.43.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 2/4] netfs: when subreq is marked for retry, do not check if it faced an error
2026-01-29 17:37 [PATCH v3 1/4] cifs: on replayable errors back-off before replay, not after nspmangalore
@ 2026-01-29 17:37 ` nspmangalore
2026-01-30 13:24 ` David Howells
2026-01-29 17:37 ` [PATCH v3 3/4] netfs: avoid double increment of retry_count in subreq nspmangalore
` (2 subsequent siblings)
3 siblings, 1 reply; 10+ messages in thread
From: nspmangalore @ 2026-01-29 17:37 UTC (permalink / raw)
To: linux-cifs, smfrench, pc, bharathsm, dhowells, netfs; +Cc: Shyam Prasad N
From: Shyam Prasad N <sprasad@microsoft.com>
The *_subreq_terminated functions today only process the NEED_RETRY
flag when the subreq was successful or failed with EAGAIN error.
However, there could be other retriable errors for network filesystems.
Avoid this by processing the NEED_RETRY irrespective of the error
code faced by the subreq. If it was specifically marked for retry,
the error code must not matter.
Cc: David Howells <dhowells@redhat.com>
Signed-off-by: Shyam Prasad N <sprasad@microsoft.com>
---
fs/netfs/read_collect.c | 10 +++++++++-
fs/netfs/read_retry.c | 4 ++--
fs/netfs/write_collect.c | 8 ++++----
fs/netfs/write_issue.c | 1 +
4 files changed, 16 insertions(+), 7 deletions(-)
diff --git a/fs/netfs/read_collect.c b/fs/netfs/read_collect.c
index a95e7aadafd07..7ac11125ca028 100644
--- a/fs/netfs/read_collect.c
+++ b/fs/netfs/read_collect.c
@@ -546,19 +546,27 @@ void netfs_read_subreq_terminated(struct netfs_io_subrequest *subreq)
}
}
+ /* if need retry is set, error should not matter. pause the rreq */
+ if (test_bit(NETFS_SREQ_NEED_RETRY, &subreq->flags)) {
+ trace_netfs_rreq(rreq, netfs_rreq_trace_set_pause);
+ set_bit(NETFS_RREQ_PAUSE, &rreq->flags);
+ goto skip_error_checks;
+ }
+
if (unlikely(subreq->error < 0)) {
- trace_netfs_failure(rreq, subreq, subreq->error, netfs_fail_read);
if (subreq->source == NETFS_READ_FROM_CACHE) {
netfs_stat(&netfs_n_rh_read_failed);
__set_bit(NETFS_SREQ_NEED_RETRY, &subreq->flags);
} else {
netfs_stat(&netfs_n_rh_download_failed);
__set_bit(NETFS_SREQ_FAILED, &subreq->flags);
+ trace_netfs_failure(rreq, subreq, subreq->error, netfs_fail_read);
}
trace_netfs_rreq(rreq, netfs_rreq_trace_set_pause);
set_bit(NETFS_RREQ_PAUSE, &rreq->flags);
}
+skip_error_checks:
trace_netfs_sreq(subreq, netfs_sreq_trace_terminated);
netfs_subreq_clear_in_progress(subreq);
netfs_put_subrequest(subreq, netfs_sreq_trace_put_terminated);
diff --git a/fs/netfs/read_retry.c b/fs/netfs/read_retry.c
index b99e84a8170af..7793ba5e3e8fc 100644
--- a/fs/netfs/read_retry.c
+++ b/fs/netfs/read_retry.c
@@ -12,6 +12,7 @@
static void netfs_reissue_read(struct netfs_io_request *rreq,
struct netfs_io_subrequest *subreq)
{
+ subreq->error = 0;
__clear_bit(NETFS_SREQ_MADE_PROGRESS, &subreq->flags);
__set_bit(NETFS_SREQ_IN_PROGRESS, &subreq->flags);
netfs_stat(&netfs_n_rh_retry_read_subreq);
@@ -242,8 +243,7 @@ static void netfs_retry_read_subrequests(struct netfs_io_request *rreq)
subreq = list_next_entry(subreq, rreq_link);
abandon:
list_for_each_entry_from(subreq, &stream->subrequests, rreq_link) {
- if (!subreq->error &&
- !test_bit(NETFS_SREQ_FAILED, &subreq->flags) &&
+ if (!test_bit(NETFS_SREQ_FAILED, &subreq->flags) &&
!test_bit(NETFS_SREQ_NEED_RETRY, &subreq->flags))
continue;
subreq->error = -ENOMEM;
diff --git a/fs/netfs/write_collect.c b/fs/netfs/write_collect.c
index cbf3d9194c7bf..61eab34ea67ef 100644
--- a/fs/netfs/write_collect.c
+++ b/fs/netfs/write_collect.c
@@ -492,11 +492,11 @@ void netfs_write_subrequest_terminated(void *_op, ssize_t transferred_or_error)
if (IS_ERR_VALUE(transferred_or_error)) {
subreq->error = transferred_or_error;
- if (subreq->error == -EAGAIN)
- set_bit(NETFS_SREQ_NEED_RETRY, &subreq->flags);
- else
+ /* if need retry is set, error should not matter */
+ if (!test_bit(NETFS_SREQ_NEED_RETRY, &subreq->flags)) {
set_bit(NETFS_SREQ_FAILED, &subreq->flags);
- trace_netfs_failure(wreq, subreq, transferred_or_error, netfs_fail_write);
+ trace_netfs_failure(wreq, subreq, transferred_or_error, netfs_fail_write);
+ }
switch (subreq->source) {
case NETFS_WRITE_TO_CACHE:
diff --git a/fs/netfs/write_issue.c b/fs/netfs/write_issue.c
index dd8743bc8d7fe..34894da5a23ec 100644
--- a/fs/netfs/write_issue.c
+++ b/fs/netfs/write_issue.c
@@ -250,6 +250,7 @@ void netfs_reissue_write(struct netfs_io_stream *stream,
iov_iter_truncate(&subreq->io_iter, size);
subreq->retry_count++;
+ subreq->error = 0;
__clear_bit(NETFS_SREQ_MADE_PROGRESS, &subreq->flags);
__set_bit(NETFS_SREQ_IN_PROGRESS, &subreq->flags);
netfs_stat(&netfs_n_wh_retry_write_subreq);
--
2.43.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 3/4] netfs: avoid double increment of retry_count in subreq
2026-01-29 17:37 [PATCH v3 1/4] cifs: on replayable errors back-off before replay, not after nspmangalore
2026-01-29 17:37 ` [PATCH v3 2/4] netfs: when subreq is marked for retry, do not check if it faced an error nspmangalore
@ 2026-01-29 17:37 ` nspmangalore
2026-01-30 13:25 ` David Howells
2026-01-29 17:37 ` [PATCH v3 4/4] cifs: make retry logic in read/write path consistent with other paths nspmangalore
2026-01-30 3:37 ` [PATCH v3 1/4] cifs: on replayable errors back-off before replay, not after Steve French
3 siblings, 1 reply; 10+ messages in thread
From: nspmangalore @ 2026-01-29 17:37 UTC (permalink / raw)
To: linux-cifs, smfrench, pc, bharathsm, dhowells, netfs; +Cc: Shyam Prasad N
From: Shyam Prasad N <sprasad@microsoft.com>
This change fixes the instance of double incrementing of
retry_count. The increment of this count already happens
when netfs_reissue_write gets called. Incrementing this
value before is not necessary.
Fixes: 4acb665cf4f3 ("netfs: Work around recursion by abandoning retry if nothing read")
Cc: David Howells <dhowells@redhat.com>
Acked-by: David Howells <dhowells@redhat.com>
Signed-off-by: Shyam Prasad N <sprasad@microsoft.com>
---
fs/netfs/write_retry.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/fs/netfs/write_retry.c b/fs/netfs/write_retry.c
index fc9c3e0d34d81..29489a23a2209 100644
--- a/fs/netfs/write_retry.c
+++ b/fs/netfs/write_retry.c
@@ -98,7 +98,6 @@ static void netfs_retry_write_stream(struct netfs_io_request *wreq,
subreq->start = start;
subreq->len = len;
__clear_bit(NETFS_SREQ_NEED_RETRY, &subreq->flags);
- subreq->retry_count++;
trace_netfs_sreq(subreq, netfs_sreq_trace_retry);
/* Renegotiate max_len (wsize) */
--
2.43.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 4/4] cifs: make retry logic in read/write path consistent with other paths
2026-01-29 17:37 [PATCH v3 1/4] cifs: on replayable errors back-off before replay, not after nspmangalore
2026-01-29 17:37 ` [PATCH v3 2/4] netfs: when subreq is marked for retry, do not check if it faced an error nspmangalore
2026-01-29 17:37 ` [PATCH v3 3/4] netfs: avoid double increment of retry_count in subreq nspmangalore
@ 2026-01-29 17:37 ` nspmangalore
2026-01-30 13:36 ` David Howells
2026-01-30 3:37 ` [PATCH v3 1/4] cifs: on replayable errors back-off before replay, not after Steve French
3 siblings, 1 reply; 10+ messages in thread
From: nspmangalore @ 2026-01-29 17:37 UTC (permalink / raw)
To: linux-cifs, smfrench, pc, bharathsm, dhowells, netfs; +Cc: Shyam Prasad N
From: Shyam Prasad N <sprasad@microsoft.com>
Today in most other code paths in cifs.ko, the decision of whether
to retry a command depends on two mount options: retrans and hard.
However, the read/write code paths diverged from this and would only
retry if the error returned was -EAGAIN. However, there are other
replayable errors in cifs.ko, for which is_replayable_errors helper
was written. This change makes read/write codepaths consistent with
other code-paths.
This change also does the following:
1. The SMB2 read/write code diverged significantly (presumably since
they were changed during netfs refactor at different times). This
changes the response verification logic to be consistent.
2. Moves the netfs tracepoints to slightly different locations in order
to make debugging easier.
Cc: David Howells <dhowells@redhat.com>
Signed-off-by: Shyam Prasad N <sprasad@microsoft.com>
---
fs/smb/client/cifsglob.h | 2 +
fs/smb/client/smb2pdu.c | 79 ++++++++++++++++++++++++++++++++++++----
2 files changed, 74 insertions(+), 7 deletions(-)
diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 3eca5bfb70303..f6ebd3fd176d7 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -1507,6 +1507,8 @@ struct cifs_io_subrequest {
int result;
bool have_xid;
bool replay;
+ unsigned int retries; /* number of retries so far */
+ unsigned int cur_sleep; /* time to sleep before replay */
struct kvec iov[2];
struct TCP_Server_Info *server;
#ifdef CONFIG_CIFS_SMB_DIRECT
diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index 7d75ba675f774..b8adfd2c55b8b 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -4650,9 +4650,19 @@ smb2_readv_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid)
iov_iter_truncate(&rqst.rq_iter, rdata->got_bytes);
rc = smb2_verify_signature(&rqst, server);
- if (rc)
+ if (rc) {
cifs_tcon_dbg(VFS, "SMB signature verification returned error = %d\n",
- rc);
+ rc);
+ rdata->subreq.error = rc;
+ rdata->result = rc;
+
+ if (is_replayable_error(rc)) {
+ trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_req_submitted);
+ __set_bit(NETFS_SREQ_NEED_RETRY, &rdata->subreq.flags);
+ } else
+ trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_bad);
+ } else
+ trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_progress);
}
/* FIXME: should this be counted toward the initiating task? */
task_io_account_read(rdata->got_bytes);
@@ -4728,6 +4738,14 @@ smb2_readv_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid)
if (rdata->got_bytes)
__set_bit(NETFS_SREQ_MADE_PROGRESS, &rdata->subreq.flags);
}
+
+ /* see if we need to retry */
+ if (is_replayable_error(rdata->result) &&
+ smb2_should_replay(tcon,
+ &rdata->retries,
+ &rdata->cur_sleep))
+ rdata->replay = true;
+
trace_smb3_rw_credits(rreq_debug_id, subreq_debug_index, rdata->credits.value,
server->credits, server->in_flight,
0, cifs_trace_rw_credits_read_response_clear);
@@ -4776,7 +4794,7 @@ smb2_async_readv(struct cifs_io_subrequest *rdata)
rc = smb2_new_read_req(
(void **) &buf, &total_len, &io_parms, rdata, 0, 0);
if (rc)
- return rc;
+ goto out;
if (smb3_encryption_required(io_parms.tcon))
flags |= CIFS_TRANSFORM_REQ;
@@ -4788,6 +4806,13 @@ smb2_async_readv(struct cifs_io_subrequest *rdata)
shdr = (struct smb2_hdr *)buf;
+ if (rdata->replay) {
+ /* Back-off before retry */
+ if (rdata->cur_sleep)
+ msleep(rdata->cur_sleep);
+ smb2_set_replay(server, &rqst);
+ }
+
if (rdata->credits.value > 0) {
shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(io_parms.length,
SMB2_MAX_BUFFER_SIZE));
@@ -4823,6 +4848,17 @@ smb2_async_readv(struct cifs_io_subrequest *rdata)
async_readv_out:
cifs_small_buf_release(buf);
+
+out:
+ /* if the send error is retryable, let netfs know about it */
+ if (is_replayable_error(rc) &&
+ smb2_should_replay(tcon,
+ &rdata->retries,
+ &rdata->cur_sleep)) {
+ trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_retry_needed);
+ __set_bit(NETFS_SREQ_NEED_RETRY, &rdata->subreq.flags);
+ }
+
return rc;
}
@@ -4936,14 +4972,20 @@ smb2_writev_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid)
switch (mid->mid_state) {
case MID_RESPONSE_RECEIVED:
- trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_progress);
credits.value = le16_to_cpu(rsp->hdr.CreditRequest);
credits.instance = server->reconnect_instance;
result = smb2_check_receive(mid, server, 0);
if (result != 0) {
- trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_bad);
+ if (is_replayable_error(result)) {
+ trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_req_submitted);
+ __set_bit(NETFS_SREQ_NEED_RETRY, &wdata->subreq.flags);
+ } else {
+ wdata->subreq.error = result;
+ trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_bad);
+ }
break;
}
+ trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_progress);
written = le32_to_cpu(rsp->DataLength);
/*
@@ -4958,7 +5000,7 @@ smb2_writev_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid)
cifs_stats_bytes_written(tcon, written);
if (written < wdata->subreq.len) {
- wdata->result = -ENOSPC;
+ result = -ENOSPC;
} else if (written > 0) {
wdata->subreq.len = written;
__set_bit(NETFS_SREQ_MADE_PROGRESS, &wdata->subreq.flags);
@@ -5000,6 +5042,7 @@ smb2_writev_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid)
}
#endif
if (result) {
+ wdata->result = result;
cifs_stats_fail_inc(tcon, SMB2_WRITE_HE);
trace_smb3_write_err(wdata->rreq->debug_id,
wdata->subreq.debug_index,
@@ -5022,6 +5065,14 @@ smb2_writev_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid)
server->credits, server->in_flight,
0, cifs_trace_rw_credits_write_response_clear);
wdata->credits.value = 0;
+
+ /* see if we need to retry */
+ if (is_replayable_error(wdata->result) &&
+ smb2_should_replay(tcon,
+ &wdata->retries,
+ &wdata->cur_sleep))
+ wdata->replay = true;
+
cifs_write_subrequest_terminated(wdata, result ?: written);
release_mid(server, mid);
trace_smb3_rw_credits(rreq_debug_id, subreq_debug_index, 0,
@@ -5140,8 +5191,12 @@ smb2_async_writev(struct cifs_io_subrequest *wdata)
}
#endif
- if (wdata->subreq.retry_count > 0)
+ if (wdata->replay) {
+ /* Back-off before retry */
+ if (wdata->cur_sleep)
+ msleep(wdata->cur_sleep);
smb2_set_replay(server, &rqst);
+ }
cifs_dbg(FYI, "async write at %llu %u bytes iter=%zx\n",
io_parms->offset, io_parms->length, iov_iter_count(&wdata->subreq.io_iter));
@@ -5187,6 +5242,16 @@ smb2_async_writev(struct cifs_io_subrequest *wdata)
async_writev_out:
cifs_small_buf_release(req);
out:
+ /* if the send error is retryable, let netfs know about it */
+ if (is_replayable_error(rc) &&
+ smb2_should_replay(tcon,
+ &wdata->retries,
+ &wdata->cur_sleep)) {
+ wdata->replay = true;
+ trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_retry_needed);
+ __set_bit(NETFS_SREQ_NEED_RETRY, &wdata->subreq.flags);
+ }
+
if (rc) {
trace_smb3_rw_credits(wdata->rreq->debug_id,
wdata->subreq.debug_index,
--
2.43.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v3 1/4] cifs: on replayable errors back-off before replay, not after
2026-01-29 17:37 [PATCH v3 1/4] cifs: on replayable errors back-off before replay, not after nspmangalore
` (2 preceding siblings ...)
2026-01-29 17:37 ` [PATCH v3 4/4] cifs: make retry logic in read/write path consistent with other paths nspmangalore
@ 2026-01-30 3:37 ` Steve French
2026-01-31 8:35 ` Shyam Prasad N
3 siblings, 1 reply; 10+ messages in thread
From: Steve French @ 2026-01-30 3:37 UTC (permalink / raw)
To: nspmangalore; +Cc: linux-cifs, pc, bharathsm, dhowells, netfs, Shyam Prasad N
Have updated cifs-2.6.git for-next with these four patches
On Thu, Jan 29, 2026 at 11:37 AM <nspmangalore@gmail.com> wrote:
>
> From: Shyam Prasad N <sprasad@microsoft.com>
>
> On replayable errors, we call smb2_should_replays that does these
> things today:
> 1. decide if we need to replay the command again
> 2. sleep to back-off the failed request
> 3. update the next sleep value
>
> We will not be able to use this for async requests, when this is
> processed in callbacks (as this will be called in cifsd threads that
> should not sleep in response processing).
>
> Modify the behaviour by taking the sleep out of smb2_should_replay
> and performing the sleep for back-off just before actually
> performing the replay.
>
> Signed-off-by: Shyam Prasad N <sprasad@microsoft.com>
> ---
> fs/smb/client/cached_dir.c | 6 +-
> fs/smb/client/smb2inode.c | 21 +++++--
> fs/smb/client/smb2ops.c | 32 ++++++++---
> fs/smb/client/smb2pdu.c | 112 +++++++++++++++++++++++++++----------
> 4 files changed, 129 insertions(+), 42 deletions(-)
>
> diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c
> index 1db7ab6c2529c..df9977030d199 100644
> --- a/fs/smb/client/cached_dir.c
> +++ b/fs/smb/client/cached_dir.c
> @@ -154,7 +154,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
> struct cached_fid *cfid;
> struct cached_fids *cfids;
> const char *npath;
> - int retries = 0, cur_sleep = 1;
> + int retries = 0, cur_sleep = 0;
> __le32 lease_flags = 0;
>
> if (cifs_sb->root == NULL)
> @@ -304,6 +304,10 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
> smb2_set_related(&rqst[1]);
>
> if (retries) {
> + /* Back-off before retry */
> + if (cur_sleep)
> + msleep(cur_sleep);
> +
> smb2_set_replay(server, &rqst[0]);
> smb2_set_replay(server, &rqst[1]);
> }
> diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c
> index 2ded3246600c0..498a26a7bd415 100644
> --- a/fs/smb/client/smb2inode.c
> +++ b/fs/smb/client/smb2inode.c
> @@ -188,7 +188,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
> struct reparse_data_buffer *rbuf;
> struct TCP_Server_Info *server;
> int resp_buftype[MAX_COMPOUND];
> - int retries = 0, cur_sleep = 1;
> + int retries = 0, cur_sleep = 0;
> __u8 delete_pending[8] = {1,};
> struct kvec *rsp_iov, *iov;
> struct inode *inode = NULL;
> @@ -638,18 +638,26 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
> num_rqst++;
>
> if (cfile) {
> - if (retries)
> + if (retries) {
> + /* Back-off before retry */
> + if (cur_sleep)
> + msleep(cur_sleep);
> for (i = 1; i < num_rqst - 2; i++)
> smb2_set_replay(server, &rqst[i]);
> + }
>
> rc = compound_send_recv(xid, ses, server,
> flags, num_rqst - 2,
> &rqst[1], &resp_buftype[1],
> &rsp_iov[1]);
> } else {
> - if (retries)
> + if (retries) {
> + /* Back-off before retry */
> + if (cur_sleep)
> + msleep(cur_sleep);
> for (i = 0; i < num_rqst; i++)
> smb2_set_replay(server, &rqst[i]);
> + }
>
> rc = compound_send_recv(xid, ses, server,
> flags, num_rqst,
> @@ -1180,7 +1188,7 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
> {
> struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
> __le16 *utf16_path __free(kfree) = NULL;
> - int retries = 0, cur_sleep = 1;
> + int retries = 0, cur_sleep = 0;
> struct TCP_Server_Info *server;
> struct cifs_open_parms oparms;
> struct smb2_create_req *creq;
> @@ -1242,6 +1250,9 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
> goto err_free;
>
> if (retries) {
> + /* Back-off before retry */
> + if (cur_sleep)
> + msleep(cur_sleep);
> for (int i = 0; i < ARRAY_SIZE(rqst); i++)
> smb2_set_replay(server, &rqst[i]);
> }
> @@ -1262,7 +1273,7 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
> if (rc == -EINVAL && dentry) {
> dentry = NULL;
> retries = 0;
> - cur_sleep = 1;
> + cur_sleep = 0;
> goto again;
> }
> /*
> diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
> index a16ded46b5a26..7980c6f80730f 100644
> --- a/fs/smb/client/smb2ops.c
> +++ b/fs/smb/client/smb2ops.c
> @@ -1184,7 +1184,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
> struct smb2_file_full_ea_info *ea;
> struct smb2_query_info_rsp *rsp;
> int rc, used_len = 0;
> - int retries = 0, cur_sleep = 1;
> + int retries = 0, cur_sleep = 0;
>
> replay_again:
> /* reinitialize for possible replay */
> @@ -1314,6 +1314,9 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
> smb2_set_related(&rqst[2]);
>
> if (retries) {
> + /* Back-off before retry */
> + if (cur_sleep)
> + msleep(cur_sleep);
> smb2_set_replay(server, &rqst[0]);
> smb2_set_replay(server, &rqst[1]);
> smb2_set_replay(server, &rqst[2]);
> @@ -1582,7 +1585,7 @@ smb2_ioctl_query_info(const unsigned int xid,
> void *data[2];
> int create_options = is_dir ? CREATE_NOT_FILE : CREATE_NOT_DIR;
> void (*free_req1_func)(struct smb_rqst *r);
> - int retries = 0, cur_sleep = 1;
> + int retries = 0, cur_sleep = 0;
>
> replay_again:
> /* reinitialize for possible replay */
> @@ -1731,6 +1734,9 @@ smb2_ioctl_query_info(const unsigned int xid,
> smb2_set_related(&rqst[2]);
>
> if (retries) {
> + /* Back-off before retry */
> + if (cur_sleep)
> + msleep(cur_sleep);
> smb2_set_replay(server, &rqst[0]);
> smb2_set_replay(server, &rqst[1]);
> smb2_set_replay(server, &rqst[2]);
> @@ -2440,7 +2446,7 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
> struct smb2_query_directory_rsp *qd_rsp = NULL;
> struct smb2_create_rsp *op_rsp = NULL;
> struct TCP_Server_Info *server;
> - int retries = 0, cur_sleep = 1;
> + int retries = 0, cur_sleep = 0;
>
> replay_again:
> /* reinitialize for possible replay */
> @@ -2498,6 +2504,9 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
> smb2_set_related(&rqst[1]);
>
> if (retries) {
> + /* Back-off before retry */
> + if (cur_sleep)
> + msleep(cur_sleep);
> smb2_set_replay(server, &rqst[0]);
> smb2_set_replay(server, &rqst[1]);
> }
> @@ -2774,10 +2783,14 @@ bool smb2_should_replay(struct cifs_tcon *tcon,
> return false;
>
> if (tcon->retry || (*pretries)++ < tcon->ses->server->retrans) {
> - msleep(*pcur_sleep);
> - (*pcur_sleep) = ((*pcur_sleep) << 1);
> - if ((*pcur_sleep) > CIFS_MAX_SLEEP)
> - (*pcur_sleep) = CIFS_MAX_SLEEP;
> + /* Update sleep time for exponential backoff */
> + if (!(*pcur_sleep))
> + (*pcur_sleep) = 1;
> + else {
> + (*pcur_sleep) = ((*pcur_sleep) << 1);
> + if ((*pcur_sleep) > CIFS_MAX_SLEEP)
> + (*pcur_sleep) = CIFS_MAX_SLEEP;
> + }
> return true;
> }
>
> @@ -2808,7 +2821,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
> int rc;
> __le16 *utf16_path;
> struct cached_fid *cfid;
> - int retries = 0, cur_sleep = 1;
> + int retries = 0, cur_sleep = 0;
>
> replay_again:
> /* reinitialize for possible replay */
> @@ -2898,6 +2911,9 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
> smb2_set_related(&rqst[2]);
>
> if (retries) {
> + /* Back-off before retry */
> + if (cur_sleep)
> + msleep(cur_sleep);
> if (!cfid) {
> smb2_set_replay(server, &rqst[0]);
> smb2_set_replay(server, &rqst[2]);
> diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
> index 5d57c895ca37a..7d75ba675f774 100644
> --- a/fs/smb/client/smb2pdu.c
> +++ b/fs/smb/client/smb2pdu.c
> @@ -2904,7 +2904,7 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
> unsigned int total_len;
> __le16 *utf16_path = NULL;
> struct TCP_Server_Info *server;
> - int retries = 0, cur_sleep = 1;
> + int retries = 0, cur_sleep = 0;
>
> replay_again:
> /* reinitialize for possible replay */
> @@ -3016,8 +3016,12 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
> trace_smb3_posix_mkdir_enter(xid, tcon->tid, ses->Suid, full_path, CREATE_NOT_FILE,
> FILE_WRITE_ATTRIBUTES);
>
> - if (retries)
> + if (retries) {
> + /* Back-off before retry */
> + if (cur_sleep)
> + msleep(cur_sleep);
> smb2_set_replay(server, &rqst);
> + }
>
> /* resource #4: response buffer */
> rc = cifs_send_recv(xid, ses, server,
> @@ -3265,7 +3269,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
> int resp_buftype = CIFS_NO_BUFFER;
> int rc = 0;
> int flags = 0;
> - int retries = 0, cur_sleep = 1;
> + int retries = 0, cur_sleep = 0;
>
> replay_again:
> /* reinitialize for possible replay */
> @@ -3293,8 +3297,12 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
> trace_smb3_open_enter(xid, tcon->tid, tcon->ses->Suid, oparms->path,
> oparms->create_options, oparms->desired_access);
>
> - if (retries)
> + if (retries) {
> + /* Back-off before retry */
> + if (cur_sleep)
> + msleep(cur_sleep);
> smb2_set_replay(server, &rqst);
> + }
>
> rc = cifs_send_recv(xid, ses, server,
> &rqst, &resp_buftype, flags,
> @@ -3478,7 +3486,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
> int resp_buftype = CIFS_NO_BUFFER;
> int rc = 0;
> int flags = 0;
> - int retries = 0, cur_sleep = 1;
> + int retries = 0, cur_sleep = 0;
>
> if (!tcon)
> return smb_EIO(smb_eio_trace_null_pointers);
> @@ -3518,8 +3526,12 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
> if (rc)
> goto ioctl_exit;
>
> - if (retries)
> + if (retries) {
> + /* Back-off before retry */
> + if (cur_sleep)
> + msleep(cur_sleep);
> smb2_set_replay(server, &rqst);
> + }
>
> rc = cifs_send_recv(xid, ses, server,
> &rqst, &resp_buftype, flags,
> @@ -3675,7 +3687,7 @@ __SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
> int rc = 0;
> int flags = 0;
> bool query_attrs = false;
> - int retries = 0, cur_sleep = 1;
> + int retries = 0, cur_sleep = 0;
>
> replay_again:
> /* reinitialize for possible replay */
> @@ -3707,8 +3719,12 @@ __SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
> if (rc)
> goto close_exit;
>
> - if (retries)
> + if (retries) {
> + /* Back-off before retry */
> + if (cur_sleep)
> + msleep(cur_sleep);
> smb2_set_replay(server, &rqst);
> + }
>
> rc = cifs_send_recv(xid, ses, server,
> &rqst, &resp_buftype, flags, &rsp_iov);
> @@ -3878,7 +3894,7 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
> struct TCP_Server_Info *server;
> int flags = 0;
> bool allocated = false;
> - int retries = 0, cur_sleep = 1;
> + int retries = 0, cur_sleep = 0;
>
> cifs_dbg(FYI, "Query Info\n");
>
> @@ -3912,8 +3928,12 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
> trace_smb3_query_info_enter(xid, persistent_fid, tcon->tid,
> ses->Suid, info_class, (__u32)info_type);
>
> - if (retries)
> + if (retries) {
> + /* Back-off before retry */
> + if (cur_sleep)
> + msleep(cur_sleep);
> smb2_set_replay(server, &rqst);
> + }
>
> rc = cifs_send_recv(xid, ses, server,
> &rqst, &resp_buftype, flags, &rsp_iov);
> @@ -4069,7 +4089,7 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
> int resp_buftype = CIFS_NO_BUFFER;
> int flags = 0;
> int rc = 0;
> - int retries = 0, cur_sleep = 1;
> + int retries = 0, cur_sleep = 0;
>
> replay_again:
> /* reinitialize for possible replay */
> @@ -4100,8 +4120,12 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
> trace_smb3_notify_enter(xid, persistent_fid, tcon->tid, ses->Suid,
> (u8)watch_tree, completion_filter);
>
> - if (retries)
> + if (retries) {
> + /* Back-off before retry */
> + if (cur_sleep)
> + msleep(cur_sleep);
> smb2_set_replay(server, &rqst);
> + }
>
> rc = cifs_send_recv(xid, ses, server,
> &rqst, &resp_buftype, flags, &rsp_iov);
> @@ -4405,7 +4429,7 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
> int resp_buftype = CIFS_NO_BUFFER;
> int flags = 0;
> int rc = 0;
> - int retries = 0, cur_sleep = 1;
> + int retries = 0, cur_sleep = 0;
>
> replay_again:
> /* reinitialize for possible replay */
> @@ -4431,8 +4455,12 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
>
> trace_smb3_flush_enter(xid, persistent_fid, tcon->tid, ses->Suid);
>
> - if (retries)
> + if (retries) {
> + /* Back-off before retry */
> + if (cur_sleep)
> + msleep(cur_sleep);
> smb2_set_replay(server, &rqst);
> + }
>
> rc = cifs_send_recv(xid, ses, server,
> &rqst, &resp_buftype, flags, &rsp_iov);
> @@ -5190,7 +5218,7 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
> int flags = 0;
> unsigned int total_len;
> struct TCP_Server_Info *server;
> - int retries = 0, cur_sleep = 1;
> + int retries = 0, cur_sleep = 0;
>
> replay_again:
> /* reinitialize for possible replay */
> @@ -5238,8 +5266,12 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
> rqst.rq_iov = iov;
> rqst.rq_nvec = n_vec + 1;
>
> - if (retries)
> + if (retries) {
> + /* Back-off before retry */
> + if (cur_sleep)
> + msleep(cur_sleep);
> smb2_set_replay(server, &rqst);
> + }
>
> rc = cifs_send_recv(xid, io_parms->tcon->ses, server,
> &rqst,
> @@ -5590,7 +5622,7 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
> struct cifs_ses *ses = tcon->ses;
> struct TCP_Server_Info *server;
> int flags = 0;
> - int retries = 0, cur_sleep = 1;
> + int retries = 0, cur_sleep = 0;
>
> replay_again:
> /* reinitialize for possible replay */
> @@ -5615,8 +5647,12 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
> if (rc)
> goto qdir_exit;
>
> - if (retries)
> + if (retries) {
> + /* Back-off before retry */
> + if (cur_sleep)
> + msleep(cur_sleep);
> smb2_set_replay(server, &rqst);
> + }
>
> rc = cifs_send_recv(xid, ses, server,
> &rqst, &resp_buftype, flags, &rsp_iov);
> @@ -5725,7 +5761,7 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
> struct cifs_ses *ses = tcon->ses;
> struct TCP_Server_Info *server;
> int flags = 0;
> - int retries = 0, cur_sleep = 1;
> + int retries = 0, cur_sleep = 0;
>
> replay_again:
> /* reinitialize for possible replay */
> @@ -5758,8 +5794,12 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
> return rc;
> }
>
> - if (retries)
> + if (retries) {
> + /* Back-off before retry */
> + if (cur_sleep)
> + msleep(cur_sleep);
> smb2_set_replay(server, &rqst);
> + }
>
> rc = cifs_send_recv(xid, ses, server,
> &rqst, &resp_buftype, flags,
> @@ -5838,7 +5878,7 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
> struct kvec iov[1];
> struct kvec rsp_iov;
> int resp_buf_type;
> - int retries = 0, cur_sleep = 1;
> + int retries = 0, cur_sleep = 0;
>
> replay_again:
> /* reinitialize for possible replay */
> @@ -5868,8 +5908,12 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
> rqst.rq_iov = iov;
> rqst.rq_nvec = 1;
>
> - if (retries)
> + if (retries) {
> + /* Back-off before retry */
> + if (cur_sleep)
> + msleep(cur_sleep);
> smb2_set_replay(server, &rqst);
> + }
>
> rc = cifs_send_recv(xid, ses, server,
> &rqst, &resp_buf_type, flags, &rsp_iov);
> @@ -5971,7 +6015,7 @@ SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon,
> struct TCP_Server_Info *server;
> FILE_SYSTEM_POSIX_INFO *info = NULL;
> int flags = 0;
> - int retries = 0, cur_sleep = 1;
> + int retries = 0, cur_sleep = 0;
>
> replay_again:
> /* reinitialize for possible replay */
> @@ -5992,8 +6036,12 @@ SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon,
> rqst.rq_iov = &iov;
> rqst.rq_nvec = 1;
>
> - if (retries)
> + if (retries) {
> + /* Back-off before retry */
> + if (cur_sleep)
> + msleep(cur_sleep);
> smb2_set_replay(server, &rqst);
> + }
>
> rc = cifs_send_recv(xid, ses, server,
> &rqst, &resp_buftype, flags, &rsp_iov);
> @@ -6036,7 +6084,7 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
> struct TCP_Server_Info *server;
> unsigned int rsp_len, offset;
> int flags = 0;
> - int retries = 0, cur_sleep = 1;
> + int retries = 0, cur_sleep = 0;
>
> replay_again:
> /* reinitialize for possible replay */
> @@ -6073,8 +6121,12 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
> rqst.rq_iov = &iov;
> rqst.rq_nvec = 1;
>
> - if (retries)
> + if (retries) {
> + /* Back-off before retry */
> + if (cur_sleep)
> + msleep(cur_sleep);
> smb2_set_replay(server, &rqst);
> + }
>
> rc = cifs_send_recv(xid, ses, server,
> &rqst, &resp_buftype, flags, &rsp_iov);
> @@ -6136,7 +6188,7 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
> int flags = CIFS_NO_RSP_BUF;
> unsigned int total_len;
> struct TCP_Server_Info *server;
> - int retries = 0, cur_sleep = 1;
> + int retries = 0, cur_sleep = 0;
>
> replay_again:
> /* reinitialize for possible replay */
> @@ -6172,8 +6224,12 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
> rqst.rq_iov = iov;
> rqst.rq_nvec = 2;
>
> - if (retries)
> + if (retries) {
> + /* Back-off before retry */
> + if (cur_sleep)
> + msleep(cur_sleep);
> smb2_set_replay(server, &rqst);
> + }
>
> rc = cifs_send_recv(xid, tcon->ses, server,
> &rqst, &resp_buf_type, flags,
> --
> 2.43.0
>
--
Thanks,
Steve
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 2/4] netfs: when subreq is marked for retry, do not check if it faced an error
2026-01-29 17:37 ` [PATCH v3 2/4] netfs: when subreq is marked for retry, do not check if it faced an error nspmangalore
@ 2026-01-30 13:24 ` David Howells
0 siblings, 0 replies; 10+ messages in thread
From: David Howells @ 2026-01-30 13:24 UTC (permalink / raw)
To: nspmangalore
Cc: dhowells, linux-cifs, smfrench, pc, bharathsm, netfs,
Shyam Prasad N
nspmangalore@gmail.com wrote:
> + /* if need retry is set, error should not matter. pause the rreq */
I think I'd say:
/* If need retry is set, error should not matter unless we hit too
* many retries. Pause the generation of new subreqs.
*/
But other than that:
Acked-by: David Howells <dhowells@redhat.com>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 3/4] netfs: avoid double increment of retry_count in subreq
2026-01-29 17:37 ` [PATCH v3 3/4] netfs: avoid double increment of retry_count in subreq nspmangalore
@ 2026-01-30 13:25 ` David Howells
0 siblings, 0 replies; 10+ messages in thread
From: David Howells @ 2026-01-30 13:25 UTC (permalink / raw)
To: nspmangalore
Cc: dhowells, linux-cifs, smfrench, pc, bharathsm, netfs,
Shyam Prasad N
nspmangalore@gmail.com wrote:
> Cc: David Howells <dhowells@redhat.com>
> Acked-by: David Howells <dhowells@redhat.com>
Don't need the cc as well ;-)
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 4/4] cifs: make retry logic in read/write path consistent with other paths
2026-01-29 17:37 ` [PATCH v3 4/4] cifs: make retry logic in read/write path consistent with other paths nspmangalore
@ 2026-01-30 13:36 ` David Howells
2026-01-31 8:17 ` Shyam Prasad N
0 siblings, 1 reply; 10+ messages in thread
From: David Howells @ 2026-01-30 13:36 UTC (permalink / raw)
To: nspmangalore
Cc: dhowells, linux-cifs, smfrench, pc, bharathsm, netfs,
Shyam Prasad N
nspmangalore@gmail.com wrote:
> + unsigned int retries; /* number of retries so far */
Is this redundant with netfs_io_subrequest::retry_count? (This can be changed
from u8 to unsigned int if it helps). I suspect that there might be a fight
over who gets to increment it, though.
> + if (is_replayable_error(rc)) {
> + trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_req_submitted);
> + __set_bit(NETFS_SREQ_NEED_RETRY, &rdata->subreq.flags);
You didn't see MID_RESPONSE_SUBMITTED, so I would pick a different trace value
there.
David
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 4/4] cifs: make retry logic in read/write path consistent with other paths
2026-01-30 13:36 ` David Howells
@ 2026-01-31 8:17 ` Shyam Prasad N
0 siblings, 0 replies; 10+ messages in thread
From: Shyam Prasad N @ 2026-01-31 8:17 UTC (permalink / raw)
To: David Howells; +Cc: linux-cifs, smfrench, pc, bharathsm, netfs, Shyam Prasad N
On Fri, Jan 30, 2026 at 7:06 PM David Howells <dhowells@redhat.com> wrote:
>
> nspmangalore@gmail.com wrote:
>
> > + unsigned int retries; /* number of retries so far */
>
> Is this redundant with netfs_io_subrequest::retry_count? (This can be changed
> from u8 to unsigned int if it helps). I suspect that there might be a fight
> over who gets to increment it, though.
This is mainly used to track the number of retransmissions from the
client (retrans mount option) when soft mounts are used.
I don't mind netfs doing it's own tracking (the purpose maybe
different from what is there here). I don't see a major issue if
they're not in sync with each other too.
So I'm okay with that.
>
> > + if (is_replayable_error(rc)) {
> > + trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_req_submitted);
> > + __set_bit(NETFS_SREQ_NEED_RETRY, &rdata->subreq.flags);
>
> You didn't see MID_RESPONSE_SUBMITTED, so I would pick a different trace value
> there.
That's a typo. Thanks for reviewing. Will fix it.
>
> David
>
--
Regards,
Shyam
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 1/4] cifs: on replayable errors back-off before replay, not after
2026-01-30 3:37 ` [PATCH v3 1/4] cifs: on replayable errors back-off before replay, not after Steve French
@ 2026-01-31 8:35 ` Shyam Prasad N
0 siblings, 0 replies; 10+ messages in thread
From: Shyam Prasad N @ 2026-01-31 8:35 UTC (permalink / raw)
To: Steve French; +Cc: linux-cifs, pc, bharathsm, dhowells, netfs, Shyam Prasad N
On Fri, Jan 30, 2026 at 9:07 AM Steve French <smfrench@gmail.com> wrote:
>
> Have updated cifs-2.6.git for-next with these four patches
>
> On Thu, Jan 29, 2026 at 11:37 AM <nspmangalore@gmail.com> wrote:
> >
> > From: Shyam Prasad N <sprasad@microsoft.com>
> >
> > On replayable errors, we call smb2_should_replays that does these
> > things today:
> > 1. decide if we need to replay the command again
> > 2. sleep to back-off the failed request
> > 3. update the next sleep value
> >
> > We will not be able to use this for async requests, when this is
> > processed in callbacks (as this will be called in cifsd threads that
> > should not sleep in response processing).
> >
> > Modify the behaviour by taking the sleep out of smb2_should_replay
> > and performing the sleep for back-off just before actually
> > performing the replay.
> >
> > Signed-off-by: Shyam Prasad N <sprasad@microsoft.com>
> > ---
> > fs/smb/client/cached_dir.c | 6 +-
> > fs/smb/client/smb2inode.c | 21 +++++--
> > fs/smb/client/smb2ops.c | 32 ++++++++---
> > fs/smb/client/smb2pdu.c | 112 +++++++++++++++++++++++++++----------
> > 4 files changed, 129 insertions(+), 42 deletions(-)
> >
> > diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c
> > index 1db7ab6c2529c..df9977030d199 100644
> > --- a/fs/smb/client/cached_dir.c
> > +++ b/fs/smb/client/cached_dir.c
> > @@ -154,7 +154,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
> > struct cached_fid *cfid;
> > struct cached_fids *cfids;
> > const char *npath;
> > - int retries = 0, cur_sleep = 1;
> > + int retries = 0, cur_sleep = 0;
> > __le32 lease_flags = 0;
> >
> > if (cifs_sb->root == NULL)
> > @@ -304,6 +304,10 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
> > smb2_set_related(&rqst[1]);
> >
> > if (retries) {
> > + /* Back-off before retry */
> > + if (cur_sleep)
> > + msleep(cur_sleep);
> > +
> > smb2_set_replay(server, &rqst[0]);
> > smb2_set_replay(server, &rqst[1]);
> > }
> > diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c
> > index 2ded3246600c0..498a26a7bd415 100644
> > --- a/fs/smb/client/smb2inode.c
> > +++ b/fs/smb/client/smb2inode.c
> > @@ -188,7 +188,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
> > struct reparse_data_buffer *rbuf;
> > struct TCP_Server_Info *server;
> > int resp_buftype[MAX_COMPOUND];
> > - int retries = 0, cur_sleep = 1;
> > + int retries = 0, cur_sleep = 0;
> > __u8 delete_pending[8] = {1,};
> > struct kvec *rsp_iov, *iov;
> > struct inode *inode = NULL;
> > @@ -638,18 +638,26 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
> > num_rqst++;
> >
> > if (cfile) {
> > - if (retries)
> > + if (retries) {
> > + /* Back-off before retry */
> > + if (cur_sleep)
> > + msleep(cur_sleep);
> > for (i = 1; i < num_rqst - 2; i++)
> > smb2_set_replay(server, &rqst[i]);
> > + }
> >
> > rc = compound_send_recv(xid, ses, server,
> > flags, num_rqst - 2,
> > &rqst[1], &resp_buftype[1],
> > &rsp_iov[1]);
> > } else {
> > - if (retries)
> > + if (retries) {
> > + /* Back-off before retry */
> > + if (cur_sleep)
> > + msleep(cur_sleep);
> > for (i = 0; i < num_rqst; i++)
> > smb2_set_replay(server, &rqst[i]);
> > + }
> >
> > rc = compound_send_recv(xid, ses, server,
> > flags, num_rqst,
> > @@ -1180,7 +1188,7 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
> > {
> > struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
> > __le16 *utf16_path __free(kfree) = NULL;
> > - int retries = 0, cur_sleep = 1;
> > + int retries = 0, cur_sleep = 0;
> > struct TCP_Server_Info *server;
> > struct cifs_open_parms oparms;
> > struct smb2_create_req *creq;
> > @@ -1242,6 +1250,9 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
> > goto err_free;
> >
> > if (retries) {
> > + /* Back-off before retry */
> > + if (cur_sleep)
> > + msleep(cur_sleep);
> > for (int i = 0; i < ARRAY_SIZE(rqst); i++)
> > smb2_set_replay(server, &rqst[i]);
> > }
> > @@ -1262,7 +1273,7 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
> > if (rc == -EINVAL && dentry) {
> > dentry = NULL;
> > retries = 0;
> > - cur_sleep = 1;
> > + cur_sleep = 0;
> > goto again;
> > }
> > /*
> > diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
> > index a16ded46b5a26..7980c6f80730f 100644
> > --- a/fs/smb/client/smb2ops.c
> > +++ b/fs/smb/client/smb2ops.c
> > @@ -1184,7 +1184,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
> > struct smb2_file_full_ea_info *ea;
> > struct smb2_query_info_rsp *rsp;
> > int rc, used_len = 0;
> > - int retries = 0, cur_sleep = 1;
> > + int retries = 0, cur_sleep = 0;
> >
> > replay_again:
> > /* reinitialize for possible replay */
> > @@ -1314,6 +1314,9 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
> > smb2_set_related(&rqst[2]);
> >
> > if (retries) {
> > + /* Back-off before retry */
> > + if (cur_sleep)
> > + msleep(cur_sleep);
> > smb2_set_replay(server, &rqst[0]);
> > smb2_set_replay(server, &rqst[1]);
> > smb2_set_replay(server, &rqst[2]);
> > @@ -1582,7 +1585,7 @@ smb2_ioctl_query_info(const unsigned int xid,
> > void *data[2];
> > int create_options = is_dir ? CREATE_NOT_FILE : CREATE_NOT_DIR;
> > void (*free_req1_func)(struct smb_rqst *r);
> > - int retries = 0, cur_sleep = 1;
> > + int retries = 0, cur_sleep = 0;
> >
> > replay_again:
> > /* reinitialize for possible replay */
> > @@ -1731,6 +1734,9 @@ smb2_ioctl_query_info(const unsigned int xid,
> > smb2_set_related(&rqst[2]);
> >
> > if (retries) {
> > + /* Back-off before retry */
> > + if (cur_sleep)
> > + msleep(cur_sleep);
> > smb2_set_replay(server, &rqst[0]);
> > smb2_set_replay(server, &rqst[1]);
> > smb2_set_replay(server, &rqst[2]);
> > @@ -2440,7 +2446,7 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
> > struct smb2_query_directory_rsp *qd_rsp = NULL;
> > struct smb2_create_rsp *op_rsp = NULL;
> > struct TCP_Server_Info *server;
> > - int retries = 0, cur_sleep = 1;
> > + int retries = 0, cur_sleep = 0;
> >
> > replay_again:
> > /* reinitialize for possible replay */
> > @@ -2498,6 +2504,9 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
> > smb2_set_related(&rqst[1]);
> >
> > if (retries) {
> > + /* Back-off before retry */
> > + if (cur_sleep)
> > + msleep(cur_sleep);
> > smb2_set_replay(server, &rqst[0]);
> > smb2_set_replay(server, &rqst[1]);
> > }
> > @@ -2774,10 +2783,14 @@ bool smb2_should_replay(struct cifs_tcon *tcon,
> > return false;
> >
> > if (tcon->retry || (*pretries)++ < tcon->ses->server->retrans) {
> > - msleep(*pcur_sleep);
> > - (*pcur_sleep) = ((*pcur_sleep) << 1);
> > - if ((*pcur_sleep) > CIFS_MAX_SLEEP)
> > - (*pcur_sleep) = CIFS_MAX_SLEEP;
> > + /* Update sleep time for exponential backoff */
> > + if (!(*pcur_sleep))
> > + (*pcur_sleep) = 1;
> > + else {
> > + (*pcur_sleep) = ((*pcur_sleep) << 1);
> > + if ((*pcur_sleep) > CIFS_MAX_SLEEP)
> > + (*pcur_sleep) = CIFS_MAX_SLEEP;
> > + }
> > return true;
> > }
> >
> > @@ -2808,7 +2821,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
> > int rc;
> > __le16 *utf16_path;
> > struct cached_fid *cfid;
> > - int retries = 0, cur_sleep = 1;
> > + int retries = 0, cur_sleep = 0;
> >
> > replay_again:
> > /* reinitialize for possible replay */
> > @@ -2898,6 +2911,9 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
> > smb2_set_related(&rqst[2]);
> >
> > if (retries) {
> > + /* Back-off before retry */
> > + if (cur_sleep)
> > + msleep(cur_sleep);
> > if (!cfid) {
> > smb2_set_replay(server, &rqst[0]);
> > smb2_set_replay(server, &rqst[2]);
> > diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
> > index 5d57c895ca37a..7d75ba675f774 100644
> > --- a/fs/smb/client/smb2pdu.c
> > +++ b/fs/smb/client/smb2pdu.c
> > @@ -2904,7 +2904,7 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
> > unsigned int total_len;
> > __le16 *utf16_path = NULL;
> > struct TCP_Server_Info *server;
> > - int retries = 0, cur_sleep = 1;
> > + int retries = 0, cur_sleep = 0;
> >
> > replay_again:
> > /* reinitialize for possible replay */
> > @@ -3016,8 +3016,12 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
> > trace_smb3_posix_mkdir_enter(xid, tcon->tid, ses->Suid, full_path, CREATE_NOT_FILE,
> > FILE_WRITE_ATTRIBUTES);
> >
> > - if (retries)
> > + if (retries) {
> > + /* Back-off before retry */
> > + if (cur_sleep)
> > + msleep(cur_sleep);
> > smb2_set_replay(server, &rqst);
> > + }
> >
> > /* resource #4: response buffer */
> > rc = cifs_send_recv(xid, ses, server,
> > @@ -3265,7 +3269,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
> > int resp_buftype = CIFS_NO_BUFFER;
> > int rc = 0;
> > int flags = 0;
> > - int retries = 0, cur_sleep = 1;
> > + int retries = 0, cur_sleep = 0;
> >
> > replay_again:
> > /* reinitialize for possible replay */
> > @@ -3293,8 +3297,12 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
> > trace_smb3_open_enter(xid, tcon->tid, tcon->ses->Suid, oparms->path,
> > oparms->create_options, oparms->desired_access);
> >
> > - if (retries)
> > + if (retries) {
> > + /* Back-off before retry */
> > + if (cur_sleep)
> > + msleep(cur_sleep);
> > smb2_set_replay(server, &rqst);
> > + }
> >
> > rc = cifs_send_recv(xid, ses, server,
> > &rqst, &resp_buftype, flags,
> > @@ -3478,7 +3486,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
> > int resp_buftype = CIFS_NO_BUFFER;
> > int rc = 0;
> > int flags = 0;
> > - int retries = 0, cur_sleep = 1;
> > + int retries = 0, cur_sleep = 0;
> >
> > if (!tcon)
> > return smb_EIO(smb_eio_trace_null_pointers);
> > @@ -3518,8 +3526,12 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
> > if (rc)
> > goto ioctl_exit;
> >
> > - if (retries)
> > + if (retries) {
> > + /* Back-off before retry */
> > + if (cur_sleep)
> > + msleep(cur_sleep);
> > smb2_set_replay(server, &rqst);
> > + }
> >
> > rc = cifs_send_recv(xid, ses, server,
> > &rqst, &resp_buftype, flags,
> > @@ -3675,7 +3687,7 @@ __SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
> > int rc = 0;
> > int flags = 0;
> > bool query_attrs = false;
> > - int retries = 0, cur_sleep = 1;
> > + int retries = 0, cur_sleep = 0;
> >
> > replay_again:
> > /* reinitialize for possible replay */
> > @@ -3707,8 +3719,12 @@ __SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
> > if (rc)
> > goto close_exit;
> >
> > - if (retries)
> > + if (retries) {
> > + /* Back-off before retry */
> > + if (cur_sleep)
> > + msleep(cur_sleep);
> > smb2_set_replay(server, &rqst);
> > + }
> >
> > rc = cifs_send_recv(xid, ses, server,
> > &rqst, &resp_buftype, flags, &rsp_iov);
> > @@ -3878,7 +3894,7 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
> > struct TCP_Server_Info *server;
> > int flags = 0;
> > bool allocated = false;
> > - int retries = 0, cur_sleep = 1;
> > + int retries = 0, cur_sleep = 0;
> >
> > cifs_dbg(FYI, "Query Info\n");
> >
> > @@ -3912,8 +3928,12 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
> > trace_smb3_query_info_enter(xid, persistent_fid, tcon->tid,
> > ses->Suid, info_class, (__u32)info_type);
> >
> > - if (retries)
> > + if (retries) {
> > + /* Back-off before retry */
> > + if (cur_sleep)
> > + msleep(cur_sleep);
> > smb2_set_replay(server, &rqst);
> > + }
> >
> > rc = cifs_send_recv(xid, ses, server,
> > &rqst, &resp_buftype, flags, &rsp_iov);
> > @@ -4069,7 +4089,7 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
> > int resp_buftype = CIFS_NO_BUFFER;
> > int flags = 0;
> > int rc = 0;
> > - int retries = 0, cur_sleep = 1;
> > + int retries = 0, cur_sleep = 0;
> >
> > replay_again:
> > /* reinitialize for possible replay */
> > @@ -4100,8 +4120,12 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
> > trace_smb3_notify_enter(xid, persistent_fid, tcon->tid, ses->Suid,
> > (u8)watch_tree, completion_filter);
> >
> > - if (retries)
> > + if (retries) {
> > + /* Back-off before retry */
> > + if (cur_sleep)
> > + msleep(cur_sleep);
> > smb2_set_replay(server, &rqst);
> > + }
> >
> > rc = cifs_send_recv(xid, ses, server,
> > &rqst, &resp_buftype, flags, &rsp_iov);
> > @@ -4405,7 +4429,7 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
> > int resp_buftype = CIFS_NO_BUFFER;
> > int flags = 0;
> > int rc = 0;
> > - int retries = 0, cur_sleep = 1;
> > + int retries = 0, cur_sleep = 0;
> >
> > replay_again:
> > /* reinitialize for possible replay */
> > @@ -4431,8 +4455,12 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
> >
> > trace_smb3_flush_enter(xid, persistent_fid, tcon->tid, ses->Suid);
> >
> > - if (retries)
> > + if (retries) {
> > + /* Back-off before retry */
> > + if (cur_sleep)
> > + msleep(cur_sleep);
> > smb2_set_replay(server, &rqst);
> > + }
> >
> > rc = cifs_send_recv(xid, ses, server,
> > &rqst, &resp_buftype, flags, &rsp_iov);
> > @@ -5190,7 +5218,7 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
> > int flags = 0;
> > unsigned int total_len;
> > struct TCP_Server_Info *server;
> > - int retries = 0, cur_sleep = 1;
> > + int retries = 0, cur_sleep = 0;
> >
> > replay_again:
> > /* reinitialize for possible replay */
> > @@ -5238,8 +5266,12 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
> > rqst.rq_iov = iov;
> > rqst.rq_nvec = n_vec + 1;
> >
> > - if (retries)
> > + if (retries) {
> > + /* Back-off before retry */
> > + if (cur_sleep)
> > + msleep(cur_sleep);
> > smb2_set_replay(server, &rqst);
> > + }
> >
> > rc = cifs_send_recv(xid, io_parms->tcon->ses, server,
> > &rqst,
> > @@ -5590,7 +5622,7 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
> > struct cifs_ses *ses = tcon->ses;
> > struct TCP_Server_Info *server;
> > int flags = 0;
> > - int retries = 0, cur_sleep = 1;
> > + int retries = 0, cur_sleep = 0;
> >
> > replay_again:
> > /* reinitialize for possible replay */
> > @@ -5615,8 +5647,12 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
> > if (rc)
> > goto qdir_exit;
> >
> > - if (retries)
> > + if (retries) {
> > + /* Back-off before retry */
> > + if (cur_sleep)
> > + msleep(cur_sleep);
> > smb2_set_replay(server, &rqst);
> > + }
> >
> > rc = cifs_send_recv(xid, ses, server,
> > &rqst, &resp_buftype, flags, &rsp_iov);
> > @@ -5725,7 +5761,7 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
> > struct cifs_ses *ses = tcon->ses;
> > struct TCP_Server_Info *server;
> > int flags = 0;
> > - int retries = 0, cur_sleep = 1;
> > + int retries = 0, cur_sleep = 0;
> >
> > replay_again:
> > /* reinitialize for possible replay */
> > @@ -5758,8 +5794,12 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
> > return rc;
> > }
> >
> > - if (retries)
> > + if (retries) {
> > + /* Back-off before retry */
> > + if (cur_sleep)
> > + msleep(cur_sleep);
> > smb2_set_replay(server, &rqst);
> > + }
> >
> > rc = cifs_send_recv(xid, ses, server,
> > &rqst, &resp_buftype, flags,
> > @@ -5838,7 +5878,7 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
> > struct kvec iov[1];
> > struct kvec rsp_iov;
> > int resp_buf_type;
> > - int retries = 0, cur_sleep = 1;
> > + int retries = 0, cur_sleep = 0;
> >
> > replay_again:
> > /* reinitialize for possible replay */
> > @@ -5868,8 +5908,12 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
> > rqst.rq_iov = iov;
> > rqst.rq_nvec = 1;
> >
> > - if (retries)
> > + if (retries) {
> > + /* Back-off before retry */
> > + if (cur_sleep)
> > + msleep(cur_sleep);
> > smb2_set_replay(server, &rqst);
> > + }
> >
> > rc = cifs_send_recv(xid, ses, server,
> > &rqst, &resp_buf_type, flags, &rsp_iov);
> > @@ -5971,7 +6015,7 @@ SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon,
> > struct TCP_Server_Info *server;
> > FILE_SYSTEM_POSIX_INFO *info = NULL;
> > int flags = 0;
> > - int retries = 0, cur_sleep = 1;
> > + int retries = 0, cur_sleep = 0;
> >
> > replay_again:
> > /* reinitialize for possible replay */
> > @@ -5992,8 +6036,12 @@ SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon,
> > rqst.rq_iov = &iov;
> > rqst.rq_nvec = 1;
> >
> > - if (retries)
> > + if (retries) {
> > + /* Back-off before retry */
> > + if (cur_sleep)
> > + msleep(cur_sleep);
> > smb2_set_replay(server, &rqst);
> > + }
> >
> > rc = cifs_send_recv(xid, ses, server,
> > &rqst, &resp_buftype, flags, &rsp_iov);
> > @@ -6036,7 +6084,7 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
> > struct TCP_Server_Info *server;
> > unsigned int rsp_len, offset;
> > int flags = 0;
> > - int retries = 0, cur_sleep = 1;
> > + int retries = 0, cur_sleep = 0;
> >
> > replay_again:
> > /* reinitialize for possible replay */
> > @@ -6073,8 +6121,12 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
> > rqst.rq_iov = &iov;
> > rqst.rq_nvec = 1;
> >
> > - if (retries)
> > + if (retries) {
> > + /* Back-off before retry */
> > + if (cur_sleep)
> > + msleep(cur_sleep);
> > smb2_set_replay(server, &rqst);
> > + }
> >
> > rc = cifs_send_recv(xid, ses, server,
> > &rqst, &resp_buftype, flags, &rsp_iov);
> > @@ -6136,7 +6188,7 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
> > int flags = CIFS_NO_RSP_BUF;
> > unsigned int total_len;
> > struct TCP_Server_Info *server;
> > - int retries = 0, cur_sleep = 1;
> > + int retries = 0, cur_sleep = 0;
> >
> > replay_again:
> > /* reinitialize for possible replay */
> > @@ -6172,8 +6224,12 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
> > rqst.rq_iov = iov;
> > rqst.rq_nvec = 2;
> >
> > - if (retries)
> > + if (retries) {
> > + /* Back-off before retry */
> > + if (cur_sleep)
> > + msleep(cur_sleep);
> > smb2_set_replay(server, &rqst);
> > + }
> >
> > rc = cifs_send_recv(xid, tcon->ses, server,
> > &rqst, &resp_buf_type, flags,
> > --
> > 2.43.0
> >
>
>
> --
> Thanks,
>
> Steve
Resent a v4 of all 4 patches again, so that there's no confusion about
the patches. Please consider v4 of all 4 patches.
--
Regards,
Shyam
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-01-31 8:35 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-29 17:37 [PATCH v3 1/4] cifs: on replayable errors back-off before replay, not after nspmangalore
2026-01-29 17:37 ` [PATCH v3 2/4] netfs: when subreq is marked for retry, do not check if it faced an error nspmangalore
2026-01-30 13:24 ` David Howells
2026-01-29 17:37 ` [PATCH v3 3/4] netfs: avoid double increment of retry_count in subreq nspmangalore
2026-01-30 13:25 ` David Howells
2026-01-29 17:37 ` [PATCH v3 4/4] cifs: make retry logic in read/write path consistent with other paths nspmangalore
2026-01-30 13:36 ` David Howells
2026-01-31 8:17 ` Shyam Prasad N
2026-01-30 3:37 ` [PATCH v3 1/4] cifs: on replayable errors back-off before replay, not after Steve French
2026-01-31 8:35 ` Shyam Prasad N
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox