summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve French <smfrench@gmail.com>2016-06-22 20:12:05 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-07-27 09:55:51 -0700
commit599fe1409085059ba12a2c3897c853be9fa9e7cf (patch)
tree9337e37f200f72bc33baefcaf194aec17e2cdc05
parent44df69e75e1c6b8e4f3e55d4b7977726392d511e (diff)
downloadlwn-599fe1409085059ba12a2c3897c853be9fa9e7cf.tar.gz
lwn-599fe1409085059ba12a2c3897c853be9fa9e7cf.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: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--fs/cifs/connect.c4
-rw-r--r--fs/cifs/smb2pdu.c27
2 files changed, 30 insertions, 1 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 8813ff776ba3..7522829b29ef 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 fc656bc5d6cb..e83f7d2b585b 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;