Commit 511c54a2 authored by Pavel Shilovsky's avatar Pavel Shilovsky Committed by Steve French

CIFS: Reconnect expired SMB sessions

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.

Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarPavel Shilovsky <pshilov@microsoft.com>
Signed-off-by: default avatarSteve French <smfrench@gmail.com>
parent 4395d484
...@@ -367,6 +367,8 @@ struct smb_version_operations { ...@@ -367,6 +367,8 @@ struct smb_version_operations {
unsigned int (*calc_smb_size)(void *); unsigned int (*calc_smb_size)(void *);
/* check for STATUS_PENDING and process it in a positive case */ /* check for STATUS_PENDING and process it in a positive case */
bool (*is_status_pending)(char *, struct TCP_Server_Info *, int); 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 */ /* send oplock break response */
int (*oplock_response)(struct cifs_tcon *, struct cifs_fid *, int (*oplock_response)(struct cifs_tcon *, struct cifs_fid *,
struct cifsInodeInfo *); struct cifsInodeInfo *);
......
...@@ -1460,6 +1460,13 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) ...@@ -1460,6 +1460,13 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
return length; return length;
server->total_read += 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 && if (server->ops->is_status_pending &&
server->ops->is_status_pending(buf, server, 0)) { server->ops->is_status_pending(buf, server, 0)) {
cifs_discard_remaining_data(server); cifs_discard_remaining_data(server);
......
...@@ -812,6 +812,13 @@ cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid) ...@@ -812,6 +812,13 @@ cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
cifs_dump_mem("Bad SMB: ", buf, cifs_dump_mem("Bad SMB: ", buf,
min_t(unsigned int, server->total_read, 48)); 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 && if (server->ops->is_status_pending &&
server->ops->is_status_pending(buf, server, length)) server->ops->is_status_pending(buf, server, length))
return -1; return -1;
......
...@@ -1036,6 +1036,18 @@ smb2_is_status_pending(char *buf, struct TCP_Server_Info *server, int length) ...@@ -1036,6 +1036,18 @@ smb2_is_status_pending(char *buf, struct TCP_Server_Info *server, int length)
return true; 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 static int
smb2_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid, smb2_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid,
struct cifsInodeInfo *cinode) struct cifsInodeInfo *cinode)
...@@ -2217,6 +2229,13 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid, ...@@ -2217,6 +2229,13 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
return -ENOTSUPP; return -ENOTSUPP;
} }
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 && if (server->ops->is_status_pending &&
server->ops->is_status_pending(buf, server, 0)) server->ops->is_status_pending(buf, server, 0))
return -1; return -1;
...@@ -2534,6 +2553,7 @@ struct smb_version_operations smb20_operations = { ...@@ -2534,6 +2553,7 @@ struct smb_version_operations smb20_operations = {
.close_dir = smb2_close_dir, .close_dir = smb2_close_dir,
.calc_smb_size = smb2_calc_size, .calc_smb_size = smb2_calc_size,
.is_status_pending = smb2_is_status_pending, .is_status_pending = smb2_is_status_pending,
.is_session_expired = smb2_is_session_expired,
.oplock_response = smb2_oplock_response, .oplock_response = smb2_oplock_response,
.queryfs = smb2_queryfs, .queryfs = smb2_queryfs,
.mand_lock = smb2_mand_lock, .mand_lock = smb2_mand_lock,
...@@ -2622,6 +2642,7 @@ struct smb_version_operations smb21_operations = { ...@@ -2622,6 +2642,7 @@ struct smb_version_operations smb21_operations = {
.close_dir = smb2_close_dir, .close_dir = smb2_close_dir,
.calc_smb_size = smb2_calc_size, .calc_smb_size = smb2_calc_size,
.is_status_pending = smb2_is_status_pending, .is_status_pending = smb2_is_status_pending,
.is_session_expired = smb2_is_session_expired,
.oplock_response = smb2_oplock_response, .oplock_response = smb2_oplock_response,
.queryfs = smb2_queryfs, .queryfs = smb2_queryfs,
.mand_lock = smb2_mand_lock, .mand_lock = smb2_mand_lock,
...@@ -2712,6 +2733,7 @@ struct smb_version_operations smb30_operations = { ...@@ -2712,6 +2733,7 @@ struct smb_version_operations smb30_operations = {
.close_dir = smb2_close_dir, .close_dir = smb2_close_dir,
.calc_smb_size = smb2_calc_size, .calc_smb_size = smb2_calc_size,
.is_status_pending = smb2_is_status_pending, .is_status_pending = smb2_is_status_pending,
.is_session_expired = smb2_is_session_expired,
.oplock_response = smb2_oplock_response, .oplock_response = smb2_oplock_response,
.queryfs = smb2_queryfs, .queryfs = smb2_queryfs,
.mand_lock = smb2_mand_lock, .mand_lock = smb2_mand_lock,
...@@ -2812,6 +2834,7 @@ struct smb_version_operations smb311_operations = { ...@@ -2812,6 +2834,7 @@ struct smb_version_operations smb311_operations = {
.close_dir = smb2_close_dir, .close_dir = smb2_close_dir,
.calc_smb_size = smb2_calc_size, .calc_smb_size = smb2_calc_size,
.is_status_pending = smb2_is_status_pending, .is_status_pending = smb2_is_status_pending,
.is_session_expired = smb2_is_session_expired,
.oplock_response = smb2_oplock_response, .oplock_response = smb2_oplock_response,
.queryfs = smb2_queryfs, .queryfs = smb2_queryfs,
.mand_lock = smb2_mand_lock, .mand_lock = smb2_mand_lock,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment