]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
CIFS: Reconnect expired SMB sessions
authorPavel Shilovsky <pshilov@microsoft.com>
Sat, 8 Jul 2017 21:32:00 +0000 (14:32 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 18 Oct 2017 07:20:40 +0000 (09:20 +0200)
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 <pshilov@microsoft.com>
Signed-off-by: Steve French <smfrench@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/cifs/cifsglob.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/smb2ops.c

index e2f6a79e9b012d695a33c90b684b3eaafa1cb6b2..8225de3c9743110a2bf996d53ae7585aab273928 100644 (file)
@@ -351,6 +351,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 *);
index b60150e5b5ceaab72954b82b1519bf4792fa1589..0c92af11f4f45e54af416652ee1a0ebce3e0aefe 100644 (file)
@@ -1460,6 +1460,13 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
                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);
index b377aa8f266f99aa4df7b960ba930ae174ef91d0..0a2bf9462637993fef2479618df5e02136bf3dd0 100644 (file)
@@ -850,6 +850,13 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
                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;
index 1d125d3d0d898653faba501bba132bca84423b8e..e6b1795fbf2a36e930a1a1a52701ebb07468ef81 100644 (file)
@@ -963,6 +963,18 @@ smb2_is_status_pending(char *buf, struct TCP_Server_Info *server, int length)
        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)
@@ -1552,6 +1564,7 @@ struct smb_version_operations smb20_operations = {
        .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,
@@ -1633,6 +1646,7 @@ struct smb_version_operations smb21_operations = {
        .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,
@@ -1715,6 +1729,7 @@ struct smb_version_operations smb30_operations = {
        .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,
@@ -1803,6 +1818,7 @@ struct smb_version_operations smb311_operations = {
        .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,