diff options
author | Paulo Alcantara <pc@manguebit.com> | 2023-02-28 23:01:55 +0100 |
---|---|---|
committer | Steve French <stfrench@microsoft.com> | 2023-03-02 01:18:25 +0100 |
commit | 1bcd548d935a33c6fc58331405eb1b82fd6150de (patch) | |
tree | a6c80c6ffc0436c6ff39153eae0502d99e4f9ba9 /fs/cifs/misc.c | |
parent | cifs: improve checking of DFS links over STATUS_OBJECT_NAME_INVALID (diff) | |
download | linux-1bcd548d935a33c6fc58331405eb1b82fd6150de.tar.xz linux-1bcd548d935a33c6fc58331405eb1b82fd6150de.zip |
cifs: prevent data race in cifs_reconnect_tcon()
Make sure to get an up-to-date TCP_Server_Info::nr_targets value prior
to waiting the server to be reconnected in cifs_reconnect_tcon(). It
is set in cifs_tcp_ses_needs_reconnect() and protected by
TCP_Server_Info::srv_lock.
Create a new cifs_wait_for_server_reconnect() helper that can be used
by both SMB2+ and CIFS reconnect code.
Signed-off-by: Paulo Alcantara (SUSE) <pc@manguebit.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Diffstat (limited to 'fs/cifs/misc.c')
-rw-r--r-- | fs/cifs/misc.c | 44 |
1 files changed, 44 insertions, 0 deletions
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 0c6c1fc8dae9..a0d286ee723d 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -1266,3 +1266,47 @@ int cifs_inval_name_dfs_link_error(const unsigned int xid, return 0; } #endif + +int cifs_wait_for_server_reconnect(struct TCP_Server_Info *server, bool retry) +{ + int timeout = 10; + int rc; + + spin_lock(&server->srv_lock); + if (server->tcpStatus != CifsNeedReconnect) { + spin_unlock(&server->srv_lock); + return 0; + } + timeout *= server->nr_targets; + spin_unlock(&server->srv_lock); + + /* + * Give demultiplex thread up to 10 seconds to each target available for + * reconnect -- should be greater than cifs socket timeout which is 7 + * seconds. + * + * On "soft" mounts we wait once. Hard mounts keep retrying until + * process is killed or server comes back on-line. + */ + do { + rc = wait_event_interruptible_timeout(server->response_q, + (server->tcpStatus != CifsNeedReconnect), + timeout * HZ); + if (rc < 0) { + cifs_dbg(FYI, "%s: aborting reconnect due to received signal\n", + __func__); + return -ERESTARTSYS; + } + + /* are we still trying to reconnect? */ + spin_lock(&server->srv_lock); + if (server->tcpStatus != CifsNeedReconnect) { + spin_unlock(&server->srv_lock); + return 0; + } + spin_unlock(&server->srv_lock); + } while (retry); + + cifs_dbg(FYI, "%s: gave up waiting on reconnect\n", __func__); + return -EHOSTDOWN; +} |