]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
cifs: on replayable errors back-off before replay, not after
authorShyam Prasad N <sprasad@microsoft.com>
Sat, 31 Jan 2026 08:33:03 +0000 (14:03 +0530)
committerSteve French <stfrench@microsoft.com>
Sun, 8 Feb 2026 23:07:43 +0000 (17:07 -0600)
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>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/client/cached_dir.c
fs/smb/client/smb2inode.c
fs/smb/client/smb2ops.c
fs/smb/client/smb2pdu.c

index 1db7ab6c2529ce1f26746f4b77d2d564bcc3efa5..df9977030d199f6919d743b7b98887da204ad415 100644 (file)
@@ -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 @@ replay_again:
        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]);
        }
index 2ded3246600c01d7ae88772eef0c578e4a78e726..498a26a7bd415adfe7c009443f7818642cb502ac 100644 (file)
@@ -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 @@ replay_again:
        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 @@ again:
                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 @@ again:
        if (rc == -EINVAL && dentry) {
                dentry = NULL;
                retries = 0;
-               cur_sleep = 1;
+               cur_sleep = 0;
                goto again;
        }
        /*
index c1aaf77e187b6d703595b724e63d4727efc93ede..f6806946d0eeec30ec569c4a163f6eedfbe02d63 100644 (file)
@@ -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 @@ replay_again:
        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 @@ replay_again:
        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]);
@@ -2446,7 +2452,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 */
@@ -2504,6 +2510,9 @@ replay_again:
        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]);
        }
@@ -2780,10 +2789,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;
        }
 
@@ -2814,7 +2827,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 */
@@ -2904,6 +2917,9 @@ replay_again:
        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]);
index 5d57c895ca37a787cc8edb448a1d9244ea9d3204..7d75ba675f7747fabc0beb80462b67061d80b4b0 100644 (file)
@@ -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 @@ replay_again:
        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 @@ replay_again:
        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 @@ replay_again:
        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 @@ replay_again:
        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 @@ replay_again:
        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 @@ replay_again:
        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 @@ replay_again:
 
        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 @@ replay_again:
        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 @@ replay_again:
        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 @@ replay_again:
                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 @@ replay_again:
        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 @@ replay_again:
        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 @@ replay_again:
        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 @@ replay_again:
        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,