@@ -1108,7 +1108,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
11081108{
11091109 struct smb2_compound_vars * vars ;
11101110 struct cifs_ses * ses = tcon -> ses ;
1111- struct TCP_Server_Info * server = cifs_pick_channel ( ses ) ;
1111+ struct TCP_Server_Info * server ;
11121112 struct smb_rqst * rqst ;
11131113 struct kvec * rsp_iov ;
11141114 __le16 * utf16_path = NULL ;
@@ -1124,6 +1124,13 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
11241124 struct smb2_file_full_ea_info * ea = NULL ;
11251125 struct smb2_query_info_rsp * rsp ;
11261126 int rc , used_len = 0 ;
1127+ int retries = 0 , cur_sleep = 1 ;
1128+
1129+ replay_again :
1130+ /* reinitialize for possible replay */
1131+ flags = CIFS_CP_CREATE_CLOSE_OP ;
1132+ oplock = SMB2_OPLOCK_LEVEL_NONE ;
1133+ server = cifs_pick_channel (ses );
11271134
11281135 if (smb3_encryption_required (tcon ))
11291136 flags |= CIFS_TRANSFORM_REQ ;
@@ -1244,6 +1251,12 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
12441251 goto sea_exit ;
12451252 smb2_set_related (& rqst [2 ]);
12461253
1254+ if (retries ) {
1255+ smb2_set_replay (server , & rqst [0 ]);
1256+ smb2_set_replay (server , & rqst [1 ]);
1257+ smb2_set_replay (server , & rqst [2 ]);
1258+ }
1259+
12471260 rc = compound_send_recv (xid , ses , server ,
12481261 flags , 3 , rqst ,
12491262 resp_buftype , rsp_iov );
@@ -1260,6 +1273,11 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
12601273 kfree (vars );
12611274out_free_path :
12621275 kfree (utf16_path );
1276+
1277+ if (is_replayable_error (rc ) &&
1278+ smb2_should_replay (tcon , & retries , & cur_sleep ))
1279+ goto replay_again ;
1280+
12631281 return rc ;
12641282}
12651283#endif
@@ -1484,7 +1502,7 @@ smb2_ioctl_query_info(const unsigned int xid,
14841502 struct smb_rqst * rqst ;
14851503 struct kvec * rsp_iov ;
14861504 struct cifs_ses * ses = tcon -> ses ;
1487- struct TCP_Server_Info * server = cifs_pick_channel ( ses ) ;
1505+ struct TCP_Server_Info * server ;
14881506 char __user * arg = (char __user * )p ;
14891507 struct smb_query_info qi ;
14901508 struct smb_query_info __user * pqi ;
@@ -1501,6 +1519,13 @@ smb2_ioctl_query_info(const unsigned int xid,
15011519 void * data [2 ];
15021520 int create_options = is_dir ? CREATE_NOT_FILE : CREATE_NOT_DIR ;
15031521 void (* free_req1_func )(struct smb_rqst * r );
1522+ int retries = 0 , cur_sleep = 1 ;
1523+
1524+ replay_again :
1525+ /* reinitialize for possible replay */
1526+ flags = CIFS_CP_CREATE_CLOSE_OP ;
1527+ oplock = SMB2_OPLOCK_LEVEL_NONE ;
1528+ server = cifs_pick_channel (ses );
15041529
15051530 vars = kzalloc (sizeof (* vars ), GFP_ATOMIC );
15061531 if (vars == NULL )
@@ -1641,6 +1666,12 @@ smb2_ioctl_query_info(const unsigned int xid,
16411666 goto free_req_1 ;
16421667 smb2_set_related (& rqst [2 ]);
16431668
1669+ if (retries ) {
1670+ smb2_set_replay (server , & rqst [0 ]);
1671+ smb2_set_replay (server , & rqst [1 ]);
1672+ smb2_set_replay (server , & rqst [2 ]);
1673+ }
1674+
16441675 rc = compound_send_recv (xid , ses , server ,
16451676 flags , 3 , rqst ,
16461677 resp_buftype , rsp_iov );
@@ -1701,6 +1732,11 @@ smb2_ioctl_query_info(const unsigned int xid,
17011732 kfree (buffer );
17021733free_vars :
17031734 kfree (vars );
1735+
1736+ if (is_replayable_error (rc ) &&
1737+ smb2_should_replay (tcon , & retries , & cur_sleep ))
1738+ goto replay_again ;
1739+
17041740 return rc ;
17051741}
17061742
@@ -2227,8 +2263,14 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
22272263 struct cifs_open_parms oparms ;
22282264 struct smb2_query_directory_rsp * qd_rsp = NULL ;
22292265 struct smb2_create_rsp * op_rsp = NULL ;
2230- struct TCP_Server_Info * server = cifs_pick_channel (tcon -> ses );
2231- int retry_count = 0 ;
2266+ struct TCP_Server_Info * server ;
2267+ int retries = 0 , cur_sleep = 1 ;
2268+
2269+ replay_again :
2270+ /* reinitialize for possible replay */
2271+ flags = 0 ;
2272+ oplock = SMB2_OPLOCK_LEVEL_NONE ;
2273+ server = cifs_pick_channel (tcon -> ses );
22322274
22332275 utf16_path = cifs_convert_path_to_utf16 (path , cifs_sb );
22342276 if (!utf16_path )
@@ -2278,14 +2320,15 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
22782320
22792321 smb2_set_related (& rqst [1 ]);
22802322
2281- again :
2323+ if (retries ) {
2324+ smb2_set_replay (server , & rqst [0 ]);
2325+ smb2_set_replay (server , & rqst [1 ]);
2326+ }
2327+
22822328 rc = compound_send_recv (xid , tcon -> ses , server ,
22832329 flags , 2 , rqst ,
22842330 resp_buftype , rsp_iov );
22852331
2286- if (rc == - EAGAIN && retry_count ++ < 10 )
2287- goto again ;
2288-
22892332 /* If the open failed there is nothing to do */
22902333 op_rsp = (struct smb2_create_rsp * )rsp_iov [0 ].iov_base ;
22912334 if (op_rsp == NULL || op_rsp -> hdr .Status != STATUS_SUCCESS ) {
@@ -2333,6 +2376,11 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
23332376 SMB2_query_directory_free (& rqst [1 ]);
23342377 free_rsp_buf (resp_buftype [0 ], rsp_iov [0 ].iov_base );
23352378 free_rsp_buf (resp_buftype [1 ], rsp_iov [1 ].iov_base );
2379+
2380+ if (is_replayable_error (rc ) &&
2381+ smb2_should_replay (tcon , & retries , & cur_sleep ))
2382+ goto replay_again ;
2383+
23362384 return rc ;
23372385}
23382386
@@ -2457,6 +2505,22 @@ smb2_oplock_response(struct cifs_tcon *tcon, __u64 persistent_fid,
24572505 CIFS_CACHE_READ (cinode ) ? 1 : 0 );
24582506}
24592507
2508+ void
2509+ smb2_set_replay (struct TCP_Server_Info * server , struct smb_rqst * rqst )
2510+ {
2511+ struct smb2_hdr * shdr ;
2512+
2513+ if (server -> dialect < SMB30_PROT_ID )
2514+ return ;
2515+
2516+ shdr = (struct smb2_hdr * )(rqst -> rq_iov [0 ].iov_base );
2517+ if (shdr == NULL ) {
2518+ cifs_dbg (FYI , "shdr NULL in smb2_set_related\n" );
2519+ return ;
2520+ }
2521+ shdr -> Flags |= SMB2_FLAGS_REPLAY_OPERATION ;
2522+ }
2523+
24602524void
24612525smb2_set_related (struct smb_rqst * rqst )
24622526{
@@ -2529,6 +2593,27 @@ smb2_set_next_command(struct cifs_tcon *tcon, struct smb_rqst *rqst)
25292593 shdr -> NextCommand = cpu_to_le32 (len );
25302594}
25312595
2596+ /*
2597+ * helper function for exponential backoff and check if replayable
2598+ */
2599+ bool smb2_should_replay (struct cifs_tcon * tcon ,
2600+ int * pretries ,
2601+ int * pcur_sleep )
2602+ {
2603+ if (!pretries || !pcur_sleep )
2604+ return false;
2605+
2606+ if (tcon -> retry || (* pretries )++ < tcon -> ses -> server -> retrans ) {
2607+ msleep (* pcur_sleep );
2608+ (* pcur_sleep ) = ((* pcur_sleep ) << 1 );
2609+ if ((* pcur_sleep ) > CIFS_MAX_SLEEP )
2610+ (* pcur_sleep ) = CIFS_MAX_SLEEP ;
2611+ return true;
2612+ }
2613+
2614+ return false;
2615+ }
2616+
25322617/*
25332618 * Passes the query info response back to the caller on success.
25342619 * Caller need to free this with free_rsp_buf().
@@ -2542,7 +2627,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
25422627{
25432628 struct smb2_compound_vars * vars ;
25442629 struct cifs_ses * ses = tcon -> ses ;
2545- struct TCP_Server_Info * server = cifs_pick_channel ( ses ) ;
2630+ struct TCP_Server_Info * server ;
25462631 int flags = CIFS_CP_CREATE_CLOSE_OP ;
25472632 struct smb_rqst * rqst ;
25482633 int resp_buftype [3 ];
@@ -2553,6 +2638,13 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
25532638 int rc ;
25542639 __le16 * utf16_path ;
25552640 struct cached_fid * cfid = NULL ;
2641+ int retries = 0 , cur_sleep = 1 ;
2642+
2643+ replay_again :
2644+ /* reinitialize for possible replay */
2645+ flags = CIFS_CP_CREATE_CLOSE_OP ;
2646+ oplock = SMB2_OPLOCK_LEVEL_NONE ;
2647+ server = cifs_pick_channel (ses );
25562648
25572649 if (!path )
25582650 path = "" ;
@@ -2633,6 +2725,14 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
26332725 goto qic_exit ;
26342726 smb2_set_related (& rqst [2 ]);
26352727
2728+ if (retries ) {
2729+ if (!cfid ) {
2730+ smb2_set_replay (server , & rqst [0 ]);
2731+ smb2_set_replay (server , & rqst [2 ]);
2732+ }
2733+ smb2_set_replay (server , & rqst [1 ]);
2734+ }
2735+
26362736 if (cfid ) {
26372737 rc = compound_send_recv (xid , ses , server ,
26382738 flags , 1 , & rqst [1 ],
@@ -2665,6 +2765,11 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
26652765 kfree (vars );
26662766out_free_path :
26672767 kfree (utf16_path );
2768+
2769+ if (is_replayable_error (rc ) &&
2770+ smb2_should_replay (tcon , & retries , & cur_sleep ))
2771+ goto replay_again ;
2772+
26682773 return rc ;
26692774}
26702775
0 commit comments