Skip to content

Commit 0490919

Browse files
sprasad-microsoftsmfrench
authored andcommitted
cifs: reconnect worker should take reference on server struct unconditionally
Reconnect worker currently assumes that the server struct is alive and only takes reference on the server if it needs to call smb2_reconnect. With the new ability to disable channels based on whether the server has multichannel disabled, this becomes a problem when we need to disable established channels. While disabling the channels and deallocating the server, there could be reconnect work that could not be cancelled (because it started). This change forces the reconnect worker to unconditionally take a reference on the server when it runs. Also, this change now allows smb2_reconnect to know if it was called by the reconnect worker. Based on this, the cifs_put_tcp_session can decide whether it can cancel the reconnect work synchronously or not. Signed-off-by: Shyam Prasad N <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent 8233425 commit 0490919

File tree

2 files changed

+19
-18
lines changed

2 files changed

+19
-18
lines changed

fs/smb/client/connect.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1608,10 +1608,6 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
16081608
list_del_init(&server->tcp_ses_list);
16091609
spin_unlock(&cifs_tcp_ses_lock);
16101610

1611-
/* For secondary channels, we pick up ref-count on the primary server */
1612-
if (SERVER_IS_CHAN(server))
1613-
cifs_put_tcp_session(server->primary_server, from_reconnect);
1614-
16151611
cancel_delayed_work_sync(&server->echo);
16161612

16171613
if (from_reconnect)
@@ -1625,6 +1621,10 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
16251621
else
16261622
cancel_delayed_work_sync(&server->reconnect);
16271623

1624+
/* For secondary channels, we pick up ref-count on the primary server */
1625+
if (SERVER_IS_CHAN(server))
1626+
cifs_put_tcp_session(server->primary_server, from_reconnect);
1627+
16281628
spin_lock(&server->srv_lock);
16291629
server->tcpStatus = CifsExiting;
16301630
spin_unlock(&server->srv_lock);

fs/smb/client/smb2pdu.c

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ smb2_hdr_assemble(struct smb2_hdr *shdr, __le16 smb2_cmd,
158158

159159
static int
160160
smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
161-
struct TCP_Server_Info *server)
161+
struct TCP_Server_Info *server, bool from_reconnect)
162162
{
163163
int rc = 0;
164164
struct nls_table *nls_codepage = NULL;
@@ -331,7 +331,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
331331
* as cifs_put_tcp_session takes a higher lock
332332
* i.e. cifs_tcp_ses_lock
333333
*/
334-
cifs_put_tcp_session(server, 1);
334+
cifs_put_tcp_session(server, from_reconnect);
335335

336336
server->terminate = true;
337337
cifs_signal_cifsd_for_reconnect(server, false);
@@ -499,7 +499,7 @@ static int smb2_plain_req_init(__le16 smb2_command, struct cifs_tcon *tcon,
499499
{
500500
int rc;
501501

502-
rc = smb2_reconnect(smb2_command, tcon, server);
502+
rc = smb2_reconnect(smb2_command, tcon, server, false);
503503
if (rc)
504504
return rc;
505505

@@ -3895,6 +3895,15 @@ void smb2_reconnect_server(struct work_struct *work)
38953895
int rc;
38963896
bool resched = false;
38973897

3898+
/* first check if ref count has reached 0, if not inc ref count */
3899+
spin_lock(&cifs_tcp_ses_lock);
3900+
if (!server->srv_count) {
3901+
spin_unlock(&cifs_tcp_ses_lock);
3902+
return;
3903+
}
3904+
server->srv_count++;
3905+
spin_unlock(&cifs_tcp_ses_lock);
3906+
38983907
/* If server is a channel, select the primary channel */
38993908
pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
39003909

@@ -3952,17 +3961,10 @@ void smb2_reconnect_server(struct work_struct *work)
39523961
}
39533962
spin_unlock(&ses->chan_lock);
39543963
}
3955-
/*
3956-
* Get the reference to server struct to be sure that the last call of
3957-
* cifs_put_tcon() in the loop below won't release the server pointer.
3958-
*/
3959-
if (tcon_exist || ses_exist)
3960-
server->srv_count++;
3961-
39623964
spin_unlock(&cifs_tcp_ses_lock);
39633965

39643966
list_for_each_entry_safe(tcon, tcon2, &tmp_list, rlist) {
3965-
rc = smb2_reconnect(SMB2_INTERNAL_CMD, tcon, server);
3967+
rc = smb2_reconnect(SMB2_INTERNAL_CMD, tcon, server, true);
39663968
if (!rc)
39673969
cifs_reopen_persistent_handles(tcon);
39683970
else
@@ -3995,7 +3997,7 @@ void smb2_reconnect_server(struct work_struct *work)
39953997
/* now reconnect sessions for necessary channels */
39963998
list_for_each_entry_safe(ses, ses2, &tmp_ses_list, rlist) {
39973999
tcon->ses = ses;
3998-
rc = smb2_reconnect(SMB2_INTERNAL_CMD, tcon, server);
4000+
rc = smb2_reconnect(SMB2_INTERNAL_CMD, tcon, server, true);
39994001
if (rc)
40004002
resched = true;
40014003
list_del_init(&ses->rlist);
@@ -4010,8 +4012,7 @@ void smb2_reconnect_server(struct work_struct *work)
40104012
mutex_unlock(&pserver->reconnect_mutex);
40114013

40124014
/* now we can safely release srv struct */
4013-
if (tcon_exist || ses_exist)
4014-
cifs_put_tcp_session(server, 1);
4015+
cifs_put_tcp_session(server, true);
40154016
}
40164017

40174018
int

0 commit comments

Comments
 (0)