]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
CIFS: Reconnect expired SMB sessions
authorPavel Shilovsky <pshilov@microsoft.com>
Sat, 8 Jul 2017 21:32:00 +0000 (14:32 -0700)
committerKleber Sacilotto de Souza <kleber.souza@canonical.com>
Mon, 30 Oct 2017 13:47:56 +0000 (14:47 +0100)
BugLink: http://bugs.launchpad.net/bugs/1724836
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>
Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
fs/cifs/cifsglob.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/smb2ops.c

index ae275002a7bd8178eb36a8e8834af32d71f90fe4..9b0e1a0894ed5ca5d5654dfbcc062663e9269570 100644 (file)
@@ -367,6 +367,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 de35dbd5aabf24800e7187704cf8fd1800608172..055c8d3dc4d4f114b162e0d4e5930439f5b7a3c5 100644 (file)
@@ -1463,6 +1463,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)) {
                cifs_discard_remaining_data(server);
index 7c61e32ef7f937b4e385307c18a9dba9101d4897..e568481d466d71dc2035a76e3e0caf1e3e29ce3b 100644 (file)
@@ -806,6 +806,13 @@ cifs_handle_standard(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 df4274b61cebcfcafb36aed81a61d8201abf000d..c5cddb4838deb480ee7204c1a4f32ccd3e096b35 100644 (file)
@@ -976,6 +976,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_sync_hdr *shdr = get_sync_hdr(buf);
+
+       if (shdr->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)
@@ -2214,6 +2226,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,
@@ -2295,6 +2308,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,
@@ -2377,6 +2391,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,
@@ -2469,6 +2484,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,