| From 4fcd1813e6404dd4420c7d12fb483f9320f0bf93 Mon Sep 17 00:00:00 2001 |
| From: Steve French <smfrench@gmail.com> |
| Date: Wed, 22 Jun 2016 20:12:05 -0500 |
| Subject: Fix reconnect to not defer smb3 session reconnect long after socket reconnect |
| |
| From: Steve French <smfrench@gmail.com> |
| |
| 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> |
| |
| --- |
| fs/cifs/connect.c | 4 +++- |
| fs/cifs/smb2pdu.c | 27 +++++++++++++++++++++++++++ |
| 2 files changed, 30 insertions(+), 1 deletion(-) |
| |
| --- a/fs/cifs/connect.c |
| +++ b/fs/cifs/connect.c |
| @@ -425,7 +425,9 @@ cifs_echo_request(struct work_struct *wo |
| * 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; |
| --- a/fs/cifs/smb2pdu.c |
| +++ b/fs/cifs/smb2pdu.c |
| @@ -1820,6 +1820,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; |