@@ -212,31 +212,42 @@ cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server,
212212 cifs_chan_update_iface (ses , server );
213213
214214 spin_lock (& ses -> chan_lock );
215- if (!mark_smb_session && cifs_chan_needs_reconnect (ses , server ))
216- goto next_session ;
215+ if (!mark_smb_session && cifs_chan_needs_reconnect (ses , server )) {
216+ spin_unlock (& ses -> chan_lock );
217+ continue ;
218+ }
217219
218220 if (mark_smb_session )
219221 CIFS_SET_ALL_CHANS_NEED_RECONNECT (ses );
220222 else
221223 cifs_chan_set_need_reconnect (ses , server );
222224
225+ cifs_dbg (FYI , "%s: channel connect bitmap: 0x%lx\n" ,
226+ __func__ , ses -> chans_need_reconnect );
227+
223228 /* If all channels need reconnect, then tcon needs reconnect */
224- if (!mark_smb_session && !CIFS_ALL_CHANS_NEED_RECONNECT (ses ))
225- goto next_session ;
229+ if (!mark_smb_session && !CIFS_ALL_CHANS_NEED_RECONNECT (ses )) {
230+ spin_unlock (& ses -> chan_lock );
231+ continue ;
232+ }
233+ spin_unlock (& ses -> chan_lock );
226234
235+ spin_lock (& ses -> ses_lock );
227236 ses -> ses_status = SES_NEED_RECON ;
237+ spin_unlock (& ses -> ses_lock );
228238
229239 list_for_each_entry (tcon , & ses -> tcon_list , tcon_list ) {
230240 tcon -> need_reconnect = true;
241+ spin_lock (& tcon -> tc_lock );
231242 tcon -> status = TID_NEED_RECON ;
243+ spin_unlock (& tcon -> tc_lock );
232244 }
233245 if (ses -> tcon_ipc ) {
234246 ses -> tcon_ipc -> need_reconnect = true;
247+ spin_lock (& ses -> tcon_ipc -> tc_lock );
235248 ses -> tcon_ipc -> status = TID_NEED_RECON ;
249+ spin_unlock (& ses -> tcon_ipc -> tc_lock );
236250 }
237-
238- next_session :
239- spin_unlock (& ses -> chan_lock );
240251 }
241252 spin_unlock (& cifs_tcp_ses_lock );
242253}
@@ -1721,7 +1732,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,
17211732 return ERR_PTR (rc );
17221733}
17231734
1724- /* this function must be called with ses_lock held */
1735+ /* this function must be called with ses_lock and chan_lock held */
17251736static int match_session (struct cifs_ses * ses , struct smb3_fs_context * ctx )
17261737{
17271738 if (ctx -> sectype != Unspecified &&
@@ -1732,12 +1743,8 @@ static int match_session(struct cifs_ses *ses, struct smb3_fs_context *ctx)
17321743 * If an existing session is limited to less channels than
17331744 * requested, it should not be reused
17341745 */
1735- spin_lock (& ses -> chan_lock );
1736- if (ses -> chan_max < ctx -> max_channels ) {
1737- spin_unlock (& ses -> chan_lock );
1746+ if (ses -> chan_max < ctx -> max_channels )
17381747 return 0 ;
1739- }
1740- spin_unlock (& ses -> chan_lock );
17411748
17421749 switch (ses -> sectype ) {
17431750 case Kerberos :
@@ -1865,10 +1872,13 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
18651872 spin_unlock (& ses -> ses_lock );
18661873 continue ;
18671874 }
1875+ spin_lock (& ses -> chan_lock );
18681876 if (!match_session (ses , ctx )) {
1877+ spin_unlock (& ses -> chan_lock );
18691878 spin_unlock (& ses -> ses_lock );
18701879 continue ;
18711880 }
1881+ spin_unlock (& ses -> chan_lock );
18721882 spin_unlock (& ses -> ses_lock );
18731883
18741884 ++ ses -> ses_count ;
@@ -2314,6 +2324,7 @@ cifs_put_tcon(struct cifs_tcon *tcon)
23142324 WARN_ON (tcon -> tc_count < 0 );
23152325
23162326 list_del_init (& tcon -> tcon_list );
2327+ tcon -> status = TID_EXITING ;
23172328 spin_unlock (& tcon -> tc_lock );
23182329 spin_unlock (& cifs_tcp_ses_lock );
23192330
@@ -2693,6 +2704,7 @@ cifs_match_super(struct super_block *sb, void *data)
26932704
26942705 spin_lock (& tcp_srv -> srv_lock );
26952706 spin_lock (& ses -> ses_lock );
2707+ spin_lock (& ses -> chan_lock );
26962708 spin_lock (& tcon -> tc_lock );
26972709 if (!match_server (tcp_srv , ctx , dfs_super_cmp ) ||
26982710 !match_session (ses , ctx ) ||
@@ -2705,6 +2717,7 @@ cifs_match_super(struct super_block *sb, void *data)
27052717 rc = compare_mount_options (sb , mnt_data );
27062718out :
27072719 spin_unlock (& tcon -> tc_lock );
2720+ spin_unlock (& ses -> chan_lock );
27082721 spin_unlock (& ses -> ses_lock );
27092722 spin_unlock (& tcp_srv -> srv_lock );
27102723
@@ -3652,11 +3665,19 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses,
36523665
36533666 /* only send once per connect */
36543667 spin_lock (& server -> srv_lock );
3655- if (!server -> ops -> need_neg (server ) ||
3668+ if (server -> tcpStatus != CifsGood &&
3669+ server -> tcpStatus != CifsNew &&
36563670 server -> tcpStatus != CifsNeedNegotiate ) {
3671+ spin_unlock (& server -> srv_lock );
3672+ return - EHOSTDOWN ;
3673+ }
3674+
3675+ if (!server -> ops -> need_neg (server ) &&
3676+ server -> tcpStatus == CifsGood ) {
36573677 spin_unlock (& server -> srv_lock );
36583678 return 0 ;
36593679 }
3680+
36603681 server -> tcpStatus = CifsInNegotiate ;
36613682 spin_unlock (& server -> srv_lock );
36623683
@@ -3690,23 +3711,28 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
36903711 bool is_binding = false;
36913712
36923713 spin_lock (& ses -> ses_lock );
3714+ cifs_dbg (FYI , "%s: channel connect bitmap: 0x%lx\n" ,
3715+ __func__ , ses -> chans_need_reconnect );
3716+
36933717 if (ses -> ses_status != SES_GOOD &&
36943718 ses -> ses_status != SES_NEW &&
36953719 ses -> ses_status != SES_NEED_RECON ) {
36963720 spin_unlock (& ses -> ses_lock );
3697- return 0 ;
3721+ return - EHOSTDOWN ;
36983722 }
36993723
37003724 /* only send once per connect */
37013725 spin_lock (& ses -> chan_lock );
3702- if (CIFS_ALL_CHANS_GOOD (ses ) ||
3703- cifs_chan_in_reconnect (ses , server )) {
3726+ if (CIFS_ALL_CHANS_GOOD (ses )) {
3727+ if (ses -> ses_status == SES_NEED_RECON )
3728+ ses -> ses_status = SES_GOOD ;
37043729 spin_unlock (& ses -> chan_lock );
37053730 spin_unlock (& ses -> ses_lock );
37063731 return 0 ;
37073732 }
3708- is_binding = ! CIFS_ALL_CHANS_NEED_RECONNECT ( ses );
3733+
37093734 cifs_chan_set_in_reconnect (ses , server );
3735+ is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT (ses );
37103736 spin_unlock (& ses -> chan_lock );
37113737
37123738 if (!is_binding )
@@ -4036,9 +4062,13 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru
40364062
40374063 /* only send once per connect */
40384064 spin_lock (& tcon -> tc_lock );
4039- if (tcon -> ses -> ses_status != SES_GOOD ||
4040- (tcon -> status != TID_NEW &&
4041- tcon -> status != TID_NEED_TCON )) {
4065+ if (tcon -> status != TID_NEW &&
4066+ tcon -> status != TID_NEED_TCON ) {
4067+ spin_unlock (& tcon -> tc_lock );
4068+ return - EHOSTDOWN ;
4069+ }
4070+
4071+ if (tcon -> status == TID_GOOD ) {
40424072 spin_unlock (& tcon -> tc_lock );
40434073 return 0 ;
40444074 }
0 commit comments