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: Pavel Shilovsky <pshilov@microsoft.com> Signed-off-by: Steve French <smfrench@gmail.com>
This commit is contained in:
Родитель
4395d484b9
Коммит
511c54a2f6
|
@ -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 *);
|
||||
|
|
|
@ -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)) {
|
||||
cifs_discard_remaining_data(server);
|
||||
|
|
|
@ -812,6 +812,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;
|
||||
|
|
|
@ -1036,6 +1036,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)
|
||||
|
@ -2217,6 +2229,13 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
|
|||
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 &&
|
||||
server->ops->is_status_pending(buf, server, 0))
|
||||
return -1;
|
||||
|
@ -2534,6 +2553,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,
|
||||
|
@ -2622,6 +2642,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,
|
||||
|
@ -2712,6 +2733,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,
|
||||
|
@ -2812,6 +2834,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,
|
||||
|
|
Загрузка…
Ссылка в новой задаче