summaryrefslogtreecommitdiff
path: root/fs/smb/client/connect.c
diff options
context:
space:
mode:
authorShyam Prasad N <sprasad@microsoft.com>2023-10-13 14:43:09 +0300
committerSteve French <stfrench@microsoft.com>2023-11-09 19:25:32 +0300
commit19a4b9d6c372cab6a3b2c9a061a236136fe95274 (patch)
tree26cd88d594bf7b33c64e58b7efd5837614cf0c65 /fs/smb/client/connect.c
parent9599d59eb8fc0c0fd9480c4f22901533d08965ee (diff)
downloadlinux-19a4b9d6c372cab6a3b2c9a061a236136fe95274.tar.xz
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>
Diffstat (limited to 'fs/smb/client/connect.c')
-rw-r--r--fs/smb/client/connect.c27
1 files changed, 21 insertions, 6 deletions
diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
index 947e3c362beb..b514b41cc9f0 100644
--- a/fs/smb/client/connect.c
+++ b/fs/smb/client/connect.c
@@ -389,7 +389,13 @@ static int __cifs_reconnect(struct TCP_Server_Info *server,
spin_unlock(&server->srv_lock);
cifs_swn_reset_server_dstaddr(server);
cifs_server_unlock(server);
- mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
+
+ /* increase ref count which reconnect work will drop */
+ spin_lock(&cifs_tcp_ses_lock);
+ server->srv_count++;
+ spin_unlock(&cifs_tcp_ses_lock);
+ if (mod_delayed_work(cifsiod_wq, &server->reconnect, 0))
+ cifs_put_tcp_session(server, false);
}
} while (server->tcpStatus == CifsNeedReconnect);
@@ -519,7 +525,13 @@ static int reconnect_dfs_server(struct TCP_Server_Info *server)
spin_unlock(&server->srv_lock);
cifs_swn_reset_server_dstaddr(server);
cifs_server_unlock(server);
- mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
+
+ /* increase ref count which reconnect work will drop */
+ spin_lock(&cifs_tcp_ses_lock);
+ server->srv_count++;
+ spin_unlock(&cifs_tcp_ses_lock);
+ if (mod_delayed_work(cifsiod_wq, &server->reconnect, 0))
+ cifs_put_tcp_session(server, false);
} while (server->tcpStatus == CifsNeedReconnect);
mutex_lock(&server->refpath_lock);
@@ -1601,16 +1613,19 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
cancel_delayed_work_sync(&server->echo);
- if (from_reconnect)
+ if (from_reconnect) {
/*
* Avoid deadlock here: reconnect work calls
* cifs_put_tcp_session() at its end. Need to be sure
* that reconnect work does nothing with server pointer after
* that step.
*/
- cancel_delayed_work(&server->reconnect);
- else
- cancel_delayed_work_sync(&server->reconnect);
+ if (cancel_delayed_work(&server->reconnect))
+ cifs_put_tcp_session(server, from_reconnect);
+ } else {
+ if (cancel_delayed_work_sync(&server->reconnect))
+ cifs_put_tcp_session(server, from_reconnect);
+ }
spin_lock(&server->srv_lock);
server->tcpStatus = CifsExiting;