From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754671AbdJPQMg (ORCPT ); Mon, 16 Oct 2017 12:12:36 -0400 Received: from mail.linuxfoundation.org ([140.211.169.12]:33472 "EHLO mail.linuxfoundation.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754657AbdJPQMd (ORCPT ); Mon, 16 Oct 2017 12:12:33 -0400 From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Pavel Shilovsky , Steve French Subject: [PATCH 3.18 02/19] CIFS: Reconnect expired SMB sessions Date: Mon, 16 Oct 2017 18:11:53 +0200 Message-Id: <20171016160922.129385972@linuxfoundation.org> X-Mailer: git-send-email 2.14.2 In-Reply-To: <20171016160922.020176454@linuxfoundation.org> References: <20171016160922.020176454@linuxfoundation.org> User-Agent: quilt/0.65 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 3.18-stable review patch. If anyone has any objections, please let me know. ------------------ From: Pavel Shilovsky commit 511c54a2f69195b28afb9dd119f03787b1625bb4 upstream. According to the MS-SMB2 spec (3.2.5.1.6) once the client receives STATUS_NETWORK_SESSION_EXPIRED error code from a server it should reconnect the current SMB session. Currently the client doesn't do that. This can result in subsequent client requests failing by the server. The patch adds an additional logic to the demultiplex thread to identify expired sessions and reconnect them. Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/cifs/cifsglob.h | 2 ++ fs/cifs/cifssmb.c | 7 +++++++ fs/cifs/connect.c | 7 +++++++ fs/cifs/smb2ops.c | 15 +++++++++++++++ 4 files changed, 31 insertions(+) --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -347,6 +347,8 @@ struct smb_version_operations { unsigned int (*calc_smb_size)(void *); /* check for STATUS_PENDING and process it in a positive case */ bool (*is_status_pending)(char *, struct TCP_Server_Info *, int); + /* check for STATUS_NETWORK_SESSION_EXPIRED */ + bool (*is_session_expired)(char *); /* send oplock break response */ int (*oplock_response)(struct cifs_tcon *, struct cifs_fid *, struct cifsInodeInfo *); --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1458,6 +1458,13 @@ cifs_readv_receive(struct TCP_Server_Inf return length; server->total_read += length; + if (server->ops->is_session_expired && + server->ops->is_session_expired(buf)) { + cifs_reconnect(server); + wake_up(&server->response_q); + return -1; + } + if (server->ops->is_status_pending && server->ops->is_status_pending(buf, server, 0)) { discard_remaining_data(server); --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -839,6 +839,13 @@ standard_receive3(struct TCP_Server_Info cifs_dump_mem("Bad SMB: ", buf, min_t(unsigned int, server->total_read, 48)); + if (server->ops->is_session_expired && + server->ops->is_session_expired(buf)) { + cifs_reconnect(server); + wake_up(&server->response_q); + return -1; + } + if (server->ops->is_status_pending && server->ops->is_status_pending(buf, server, length)) return -1; --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -896,6 +896,18 @@ smb2_is_status_pending(char *buf, struct return true; } +static bool +smb2_is_session_expired(char *buf) +{ + struct smb2_hdr *hdr = (struct smb2_hdr *)buf; + + if (hdr->Status != STATUS_NETWORK_SESSION_EXPIRED) + return false; + + cifs_dbg(FYI, "Session expired\n"); + return true; +} + static int smb2_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid, struct cifsInodeInfo *cinode) @@ -1424,6 +1436,7 @@ struct smb_version_operations smb20_oper .close_dir = smb2_close_dir, .calc_smb_size = smb2_calc_size, .is_status_pending = smb2_is_status_pending, + .is_session_expired = smb2_is_session_expired, .oplock_response = smb2_oplock_response, .queryfs = smb2_queryfs, .mand_lock = smb2_mand_lock, @@ -1505,6 +1518,7 @@ struct smb_version_operations smb21_oper .close_dir = smb2_close_dir, .calc_smb_size = smb2_calc_size, .is_status_pending = smb2_is_status_pending, + .is_session_expired = smb2_is_session_expired, .oplock_response = smb2_oplock_response, .queryfs = smb2_queryfs, .mand_lock = smb2_mand_lock, @@ -1587,6 +1601,7 @@ struct smb_version_operations smb30_oper .close_dir = smb2_close_dir, .calc_smb_size = smb2_calc_size, .is_status_pending = smb2_is_status_pending, + .is_session_expired = smb2_is_session_expired, .oplock_response = smb2_oplock_response, .queryfs = smb2_queryfs, .mand_lock = smb2_mand_lock,