Skip to content

Commit 19a4b9d

Browse files
sprasad-microsoftSteve French
authored andcommitted
cifs: reconnect work should have reference on server struct
The delayed work for reconnect takes server struct as a parameter. But it does so without holding a ref to it. Normally, this may not show a problem as the reconnect work is only cancelled on umount. However, since we now plan to support scaling down of channels, and the scale down can happen from reconnect work itself, we need to fix it. This change takes a reference on the server struct before it is passed to the delayed work. And drops the reference in the delayed work itself. Or if the delayed work is successfully cancelled, by the process that cancels it. Signed-off-by: Shyam Prasad N <sprasad@microsoft.com> Signed-off-by: Steve French <stfrench@microsoft.com>
1 parent 9599d59 commit 19a4b9d

File tree

2 files changed

+34
-16
lines changed

2 files changed

+34
-16
lines changed

fs/smb/client/connect.c

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,13 @@ static int __cifs_reconnect(struct TCP_Server_Info *server,
389389
spin_unlock(&server->srv_lock);
390390
cifs_swn_reset_server_dstaddr(server);
391391
cifs_server_unlock(server);
392-
mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
392+
393+
/* increase ref count which reconnect work will drop */
394+
spin_lock(&cifs_tcp_ses_lock);
395+
server->srv_count++;
396+
spin_unlock(&cifs_tcp_ses_lock);
397+
if (mod_delayed_work(cifsiod_wq, &server->reconnect, 0))
398+
cifs_put_tcp_session(server, false);
393399
}
394400
} while (server->tcpStatus == CifsNeedReconnect);
395401

@@ -519,7 +525,13 @@ static int reconnect_dfs_server(struct TCP_Server_Info *server)
519525
spin_unlock(&server->srv_lock);
520526
cifs_swn_reset_server_dstaddr(server);
521527
cifs_server_unlock(server);
522-
mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
528+
529+
/* increase ref count which reconnect work will drop */
530+
spin_lock(&cifs_tcp_ses_lock);
531+
server->srv_count++;
532+
spin_unlock(&cifs_tcp_ses_lock);
533+
if (mod_delayed_work(cifsiod_wq, &server->reconnect, 0))
534+
cifs_put_tcp_session(server, false);
523535
} while (server->tcpStatus == CifsNeedReconnect);
524536

525537
mutex_lock(&server->refpath_lock);
@@ -1601,16 +1613,19 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
16011613

16021614
cancel_delayed_work_sync(&server->echo);
16031615

1604-
if (from_reconnect)
1616+
if (from_reconnect) {
16051617
/*
16061618
* Avoid deadlock here: reconnect work calls
16071619
* cifs_put_tcp_session() at its end. Need to be sure
16081620
* that reconnect work does nothing with server pointer after
16091621
* that step.
16101622
*/
1611-
cancel_delayed_work(&server->reconnect);
1612-
else
1613-
cancel_delayed_work_sync(&server->reconnect);
1623+
if (cancel_delayed_work(&server->reconnect))
1624+
cifs_put_tcp_session(server, from_reconnect);
1625+
} else {
1626+
if (cancel_delayed_work_sync(&server->reconnect))
1627+
cifs_put_tcp_session(server, from_reconnect);
1628+
}
16141629

16151630
spin_lock(&server->srv_lock);
16161631
server->tcpStatus = CifsExiting;

fs/smb/client/smb2pdu.c

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3852,12 +3852,6 @@ void smb2_reconnect_server(struct work_struct *work)
38523852
}
38533853
spin_unlock(&ses->chan_lock);
38543854
}
3855-
/*
3856-
* Get the reference to server struct to be sure that the last call of
3857-
* cifs_put_tcon() in the loop below won't release the server pointer.
3858-
*/
3859-
if (tcon_exist || ses_exist)
3860-
server->srv_count++;
38613855

38623856
spin_unlock(&cifs_tcp_ses_lock);
38633857

@@ -3905,13 +3899,17 @@ void smb2_reconnect_server(struct work_struct *work)
39053899

39063900
done:
39073901
cifs_dbg(FYI, "Reconnecting tcons and channels finished\n");
3908-
if (resched)
3902+
if (resched) {
39093903
queue_delayed_work(cifsiod_wq, &server->reconnect, 2 * HZ);
3904+
mutex_unlock(&pserver->reconnect_mutex);
3905+
3906+
/* no need to put tcp session as we're retrying */
3907+
return;
3908+
}
39103909
mutex_unlock(&pserver->reconnect_mutex);
39113910

39123911
/* now we can safely release srv struct */
3913-
if (tcon_exist || ses_exist)
3914-
cifs_put_tcp_session(server, 1);
3912+
cifs_put_tcp_session(server, true);
39153913
}
39163914

39173915
int
@@ -3931,7 +3929,12 @@ SMB2_echo(struct TCP_Server_Info *server)
39313929
server->ops->need_neg(server)) {
39323930
spin_unlock(&server->srv_lock);
39333931
/* No need to send echo on newly established connections */
3934-
mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
3932+
spin_lock(&cifs_tcp_ses_lock);
3933+
server->srv_count++;
3934+
spin_unlock(&cifs_tcp_ses_lock);
3935+
if (mod_delayed_work(cifsiod_wq, &server->reconnect, 0))
3936+
cifs_put_tcp_session(server, false);
3937+
39353938
return rc;
39363939
}
39373940
spin_unlock(&server->srv_lock);

0 commit comments

Comments
 (0)