* [PATCH] cifs: prevent data race in smb2_reconnect()
@ 2023-01-30 23:33 Paulo Alcantara
2023-01-31 6:03 ` Steve French
0 siblings, 1 reply; 2+ messages in thread
From: Paulo Alcantara @ 2023-01-30 23:33 UTC (permalink / raw)
To: smfrench; +Cc: linux-cifs, Paulo Alcantara
Make sure to get an up-to-date TCP_Server_Info::nr_targets value prior
to waiting the server to be reconnected in smb2_reconnect(). It is
set in cifs_tcp_ses_needs_reconnect() and protected by
TCP_Server_Info::srv_lock.
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
---
fs/cifs/smb2pdu.c | 119 +++++++++++++++++++++++++---------------------
1 file changed, 64 insertions(+), 55 deletions(-)
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 2c9ffa921e6f..2d5c3df2277d 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -139,6 +139,66 @@ smb2_hdr_assemble(struct smb2_hdr *shdr, __le16 smb2_cmd,
return;
}
+static int wait_for_server_reconnect(struct TCP_Server_Info *server,
+ __le16 smb2_command, 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);
+
+ /*
+ * Return to caller for TREE_DISCONNECT and LOGOFF and CLOSE
+ * here since they are implicitly done when session drops.
+ */
+ switch (smb2_command) {
+ /*
+ * BB Should we keep oplock break and add flush to exceptions?
+ */
+ case SMB2_TREE_DISCONNECT:
+ case SMB2_CANCEL:
+ case SMB2_CLOSE:
+ case SMB2_OPLOCK_BREAK:
+ return -EAGAIN;
+ }
+
+ /*
+ * 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;
+}
+
static int
smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
struct TCP_Server_Info *server)
@@ -146,7 +206,6 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
int rc = 0;
struct nls_table *nls_codepage;
struct cifs_ses *ses;
- int retries;
/*
* SMB2s NegProt, SessSetup, Logoff do not have tcon yet so
@@ -184,61 +243,11 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
(!tcon->ses->server) || !server)
return -EIO;
+ rc = wait_for_server_reconnect(server, smb2_command, tcon->retry);
+ if (rc)
+ return rc;
+
ses = tcon->ses;
- retries = server->nr_targets;
-
- /*
- * Give demultiplex thread up to 10 seconds to each target available for
- * reconnect -- should be greater than cifs socket timeout which is 7
- * seconds.
- */
- while (server->tcpStatus == CifsNeedReconnect) {
- /*
- * Return to caller for TREE_DISCONNECT and LOGOFF and CLOSE
- * here since they are implicitly done when session drops.
- */
- switch (smb2_command) {
- /*
- * BB Should we keep oplock break and add flush to exceptions?
- */
- case SMB2_TREE_DISCONNECT:
- case SMB2_CANCEL:
- case SMB2_CLOSE:
- case SMB2_OPLOCK_BREAK:
- return -EAGAIN;
- }
-
- rc = wait_event_interruptible_timeout(server->response_q,
- (server->tcpStatus != CifsNeedReconnect),
- 10 * HZ);
- if (rc < 0) {
- cifs_dbg(FYI, "%s: aborting reconnect due to a received signal by the process\n",
- __func__);
- return -ERESTARTSYS;
- }
-
- /* are we still trying to reconnect? */
- spin_lock(&server->srv_lock);
- if (server->tcpStatus != CifsNeedReconnect) {
- spin_unlock(&server->srv_lock);
- break;
- }
- spin_unlock(&server->srv_lock);
-
- if (retries && --retries)
- continue;
-
- /*
- * on "soft" mounts we wait once. Hard mounts keep
- * retrying until process is killed or server comes
- * back on-line
- */
- if (!tcon->retry) {
- cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
- return -EHOSTDOWN;
- }
- retries = server->nr_targets;
- }
spin_lock(&ses->chan_lock);
if (!cifs_chan_needs_reconnect(ses, server) && !tcon->need_reconnect) {
--
2.39.1
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH] cifs: prevent data race in smb2_reconnect()
2023-01-30 23:33 [PATCH] cifs: prevent data race in smb2_reconnect() Paulo Alcantara
@ 2023-01-31 6:03 ` Steve French
0 siblings, 0 replies; 2+ messages in thread
From: Steve French @ 2023-01-31 6:03 UTC (permalink / raw)
To: Paulo Alcantara; +Cc: linux-cifs
tentatively merged into cifs-2.6.git for-next pending review/testing
On Mon, Jan 30, 2023 at 5:33 PM Paulo Alcantara <pc@cjr.nz> wrote:
>
> Make sure to get an up-to-date TCP_Server_Info::nr_targets value prior
> to waiting the server to be reconnected in smb2_reconnect(). It is
> set in cifs_tcp_ses_needs_reconnect() and protected by
> TCP_Server_Info::srv_lock.
>
> Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
> ---
> fs/cifs/smb2pdu.c | 119 +++++++++++++++++++++++++---------------------
> 1 file changed, 64 insertions(+), 55 deletions(-)
>
> diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
> index 2c9ffa921e6f..2d5c3df2277d 100644
> --- a/fs/cifs/smb2pdu.c
> +++ b/fs/cifs/smb2pdu.c
> @@ -139,6 +139,66 @@ smb2_hdr_assemble(struct smb2_hdr *shdr, __le16 smb2_cmd,
> return;
> }
>
> +static int wait_for_server_reconnect(struct TCP_Server_Info *server,
> + __le16 smb2_command, 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);
> +
> + /*
> + * Return to caller for TREE_DISCONNECT and LOGOFF and CLOSE
> + * here since they are implicitly done when session drops.
> + */
> + switch (smb2_command) {
> + /*
> + * BB Should we keep oplock break and add flush to exceptions?
> + */
> + case SMB2_TREE_DISCONNECT:
> + case SMB2_CANCEL:
> + case SMB2_CLOSE:
> + case SMB2_OPLOCK_BREAK:
> + return -EAGAIN;
> + }
> +
> + /*
> + * 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;
> +}
> +
> static int
> smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
> struct TCP_Server_Info *server)
> @@ -146,7 +206,6 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
> int rc = 0;
> struct nls_table *nls_codepage;
> struct cifs_ses *ses;
> - int retries;
>
> /*
> * SMB2s NegProt, SessSetup, Logoff do not have tcon yet so
> @@ -184,61 +243,11 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
> (!tcon->ses->server) || !server)
> return -EIO;
>
> + rc = wait_for_server_reconnect(server, smb2_command, tcon->retry);
> + if (rc)
> + return rc;
> +
> ses = tcon->ses;
> - retries = server->nr_targets;
> -
> - /*
> - * Give demultiplex thread up to 10 seconds to each target available for
> - * reconnect -- should be greater than cifs socket timeout which is 7
> - * seconds.
> - */
> - while (server->tcpStatus == CifsNeedReconnect) {
> - /*
> - * Return to caller for TREE_DISCONNECT and LOGOFF and CLOSE
> - * here since they are implicitly done when session drops.
> - */
> - switch (smb2_command) {
> - /*
> - * BB Should we keep oplock break and add flush to exceptions?
> - */
> - case SMB2_TREE_DISCONNECT:
> - case SMB2_CANCEL:
> - case SMB2_CLOSE:
> - case SMB2_OPLOCK_BREAK:
> - return -EAGAIN;
> - }
> -
> - rc = wait_event_interruptible_timeout(server->response_q,
> - (server->tcpStatus != CifsNeedReconnect),
> - 10 * HZ);
> - if (rc < 0) {
> - cifs_dbg(FYI, "%s: aborting reconnect due to a received signal by the process\n",
> - __func__);
> - return -ERESTARTSYS;
> - }
> -
> - /* are we still trying to reconnect? */
> - spin_lock(&server->srv_lock);
> - if (server->tcpStatus != CifsNeedReconnect) {
> - spin_unlock(&server->srv_lock);
> - break;
> - }
> - spin_unlock(&server->srv_lock);
> -
> - if (retries && --retries)
> - continue;
> -
> - /*
> - * on "soft" mounts we wait once. Hard mounts keep
> - * retrying until process is killed or server comes
> - * back on-line
> - */
> - if (!tcon->retry) {
> - cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
> - return -EHOSTDOWN;
> - }
> - retries = server->nr_targets;
> - }
>
> spin_lock(&ses->chan_lock);
> if (!cifs_chan_needs_reconnect(ses, server) && !tcon->need_reconnect) {
> --
> 2.39.1
>
--
Thanks,
Steve
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2023-01-31 6:03 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-01-30 23:33 [PATCH] cifs: prevent data race in smb2_reconnect() Paulo Alcantara
2023-01-31 6:03 ` Steve French
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox