diff options
author | Steve French <smfrench@gmail.com> | 2016-06-22 20:12:05 -0500 |
---|---|---|
committer | Ben Hutchings <ben@decadent.org.uk> | 2016-08-22 22:38:20 +0100 |
commit | 2e4378ee60049b752c9dce16f62ce6fbd11b379a (patch) | |
tree | 46fdec6379bd1829580389482a1979208f2eca36 /fs | |
parent | 24ae40c98daa6519d3c900788f7076490cf56f59 (diff) | |
download | linux-stable-2e4378ee60049b752c9dce16f62ce6fbd11b379a.tar.gz linux-stable-2e4378ee60049b752c9dce16f62ce6fbd11b379a.tar.bz2 linux-stable-2e4378ee60049b752c9dce16f62ce6fbd11b379a.zip |
Fix reconnect to not defer smb3 session reconnect long after socket reconnect
commit 4fcd1813e6404dd4420c7d12fb483f9320f0bf93 upstream.
Azure server blocks clients that open a socket and don't do anything on it.
In our reconnect scenarios, we can reconnect the tcp session and
detect the socket is available but we defer the negprot and SMB3 session
setup and tree connect reconnection until the next i/o is requested, but
this looks suspicous to some servers who expect SMB3 negprog and session
setup soon after a socket is created.
In the echo thread, reconnect SMB3 sessions and tree connections
that are disconnected. A later patch will replay persistent (and
resilient) handle opens.
Signed-off-by: Steve French <steve.french@primarydata.com>
Acked-by: Pavel Shilovsky <pshilovsky@samba.org>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/cifs/connect.c | 4 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.c | 27 |
2 files changed, 30 insertions, 1 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 3a4fc1bcde43..3c393b9759d8 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -410,7 +410,9 @@ cifs_echo_request(struct work_struct *work) * server->ops->need_neg() == true. Also, no need to ping if * we got a response recently. */ - if (!server->ops->need_neg || server->ops->need_neg(server) || + + if (server->tcpStatus == CifsNeedReconnect || + server->tcpStatus == CifsExiting || server->tcpStatus == CifsNew || (server->ops->can_echo && !server->ops->can_echo(server)) || time_before(jiffies, server->lstrp + SMB_ECHO_INTERVAL - HZ)) goto requeue_echo; diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 87d1e97e0b61..aa49aaa417be 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -1590,6 +1590,33 @@ SMB2_echo(struct TCP_Server_Info *server) cifs_dbg(FYI, "In echo request\n"); + if (server->tcpStatus == CifsNeedNegotiate) { + struct list_head *tmp, *tmp2; + struct cifs_ses *ses; + struct cifs_tcon *tcon; + + cifs_dbg(FYI, "Need negotiate, reconnecting tcons\n"); + spin_lock(&cifs_tcp_ses_lock); + list_for_each(tmp, &server->smb_ses_list) { + ses = list_entry(tmp, struct cifs_ses, smb_ses_list); + list_for_each(tmp2, &ses->tcon_list) { + tcon = list_entry(tmp2, struct cifs_tcon, + tcon_list); + /* add check for persistent handle reconnect */ + if (tcon && tcon->need_reconnect) { + spin_unlock(&cifs_tcp_ses_lock); + rc = smb2_reconnect(SMB2_ECHO, tcon); + spin_lock(&cifs_tcp_ses_lock); + } + } + } + spin_unlock(&cifs_tcp_ses_lock); + } + + /* if no session, renegotiate failed above */ + if (server->tcpStatus == CifsNeedNegotiate) + return -EIO; + rc = small_smb2_init(SMB2_ECHO, NULL, (void **)&req); if (rc) return rc; |