Commit 8e670f77 authored by Rohith Surabattula's avatar Rohith Surabattula Committed by Steve French

Handle STATUS_IO_TIMEOUT gracefully

Currently STATUS_IO_TIMEOUT is not treated as retriable error.
It is currently mapped to ETIMEDOUT and returned to userspace
for most system calls. STATUS_IO_TIMEOUT is returned by server
in case of unavailability or throttling errors.

This patch will map the STATUS_IO_TIMEOUT to EAGAIN, so that it
can be retried. Also, added a check to drop the connection to
not overload the server in case of ongoing unavailability.
Signed-off-by: default avatarRohith Surabattula <rohiths@microsoft.com>
Reviewed-by: default avatarAurelien Aptel <aaptel@suse.com>
Reviewed-by: default avatarPavel Shilovsky <pshilov@microsoft.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent d1542cf6
...@@ -510,6 +510,8 @@ struct smb_version_operations { ...@@ -510,6 +510,8 @@ struct smb_version_operations {
struct fiemap_extent_info *, u64, u64); struct fiemap_extent_info *, u64, u64);
/* version specific llseek implementation */ /* version specific llseek implementation */
loff_t (*llseek)(struct file *, struct cifs_tcon *, loff_t, int); loff_t (*llseek)(struct file *, struct cifs_tcon *, loff_t, int);
/* Check for STATUS_IO_TIMEOUT */
bool (*is_status_io_timeout)(char *buf);
}; };
struct smb_version_values { struct smb_version_values {
......
...@@ -69,6 +69,9 @@ extern bool disable_legacy_dialects; ...@@ -69,6 +69,9 @@ extern bool disable_legacy_dialects;
#define TLINK_ERROR_EXPIRE (1 * HZ) #define TLINK_ERROR_EXPIRE (1 * HZ)
#define TLINK_IDLE_EXPIRE (600 * HZ) #define TLINK_IDLE_EXPIRE (600 * HZ)
/* Drop the connection to not overload the server */
#define NUM_STATUS_IO_TIMEOUT 5
enum { enum {
/* Mount options that take no arguments */ /* Mount options that take no arguments */
Opt_user_xattr, Opt_nouser_xattr, Opt_user_xattr, Opt_nouser_xattr,
...@@ -1117,7 +1120,7 @@ cifs_demultiplex_thread(void *p) ...@@ -1117,7 +1120,7 @@ cifs_demultiplex_thread(void *p)
struct task_struct *task_to_wake = NULL; struct task_struct *task_to_wake = NULL;
struct mid_q_entry *mids[MAX_COMPOUND]; struct mid_q_entry *mids[MAX_COMPOUND];
char *bufs[MAX_COMPOUND]; char *bufs[MAX_COMPOUND];
unsigned int noreclaim_flag; unsigned int noreclaim_flag, num_io_timeout = 0;
noreclaim_flag = memalloc_noreclaim_save(); noreclaim_flag = memalloc_noreclaim_save();
cifs_dbg(FYI, "Demultiplex PID: %d\n", task_pid_nr(current)); cifs_dbg(FYI, "Demultiplex PID: %d\n", task_pid_nr(current));
...@@ -1213,6 +1216,16 @@ cifs_demultiplex_thread(void *p) ...@@ -1213,6 +1216,16 @@ cifs_demultiplex_thread(void *p)
continue; continue;
} }
if (server->ops->is_status_io_timeout &&
server->ops->is_status_io_timeout(buf)) {
num_io_timeout++;
if (num_io_timeout > NUM_STATUS_IO_TIMEOUT) {
cifs_reconnect(server);
num_io_timeout = 0;
continue;
}
}
server->lstrp = jiffies; server->lstrp = jiffies;
for (i = 0; i < num_mids; i++) { for (i = 0; i < num_mids; i++) {
......
...@@ -488,7 +488,7 @@ static const struct status_to_posix_error smb2_error_map_table[] = { ...@@ -488,7 +488,7 @@ static const struct status_to_posix_error smb2_error_map_table[] = {
{STATUS_PIPE_CONNECTED, -EIO, "STATUS_PIPE_CONNECTED"}, {STATUS_PIPE_CONNECTED, -EIO, "STATUS_PIPE_CONNECTED"},
{STATUS_PIPE_LISTENING, -EIO, "STATUS_PIPE_LISTENING"}, {STATUS_PIPE_LISTENING, -EIO, "STATUS_PIPE_LISTENING"},
{STATUS_INVALID_READ_MODE, -EIO, "STATUS_INVALID_READ_MODE"}, {STATUS_INVALID_READ_MODE, -EIO, "STATUS_INVALID_READ_MODE"},
{STATUS_IO_TIMEOUT, -ETIMEDOUT, "STATUS_IO_TIMEOUT"}, {STATUS_IO_TIMEOUT, -EAGAIN, "STATUS_IO_TIMEOUT"},
{STATUS_FILE_FORCED_CLOSED, -EIO, "STATUS_FILE_FORCED_CLOSED"}, {STATUS_FILE_FORCED_CLOSED, -EIO, "STATUS_FILE_FORCED_CLOSED"},
{STATUS_PROFILING_NOT_STARTED, -EIO, "STATUS_PROFILING_NOT_STARTED"}, {STATUS_PROFILING_NOT_STARTED, -EIO, "STATUS_PROFILING_NOT_STARTED"},
{STATUS_PROFILING_NOT_STOPPED, -EIO, "STATUS_PROFILING_NOT_STOPPED"}, {STATUS_PROFILING_NOT_STOPPED, -EIO, "STATUS_PROFILING_NOT_STOPPED"},
......
...@@ -2354,6 +2354,17 @@ smb2_is_session_expired(char *buf) ...@@ -2354,6 +2354,17 @@ smb2_is_session_expired(char *buf)
return true; return true;
} }
static bool
smb2_is_status_io_timeout(char *buf)
{
struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf;
if (shdr->Status == STATUS_IO_TIMEOUT)
return true;
else
return false;
}
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)
...@@ -4817,6 +4828,7 @@ struct smb_version_operations smb20_operations = { ...@@ -4817,6 +4828,7 @@ struct smb_version_operations smb20_operations = {
.make_node = smb2_make_node, .make_node = smb2_make_node,
.fiemap = smb3_fiemap, .fiemap = smb3_fiemap,
.llseek = smb3_llseek, .llseek = smb3_llseek,
.is_status_io_timeout = smb2_is_status_io_timeout,
}; };
struct smb_version_operations smb21_operations = { struct smb_version_operations smb21_operations = {
...@@ -4917,6 +4929,7 @@ struct smb_version_operations smb21_operations = { ...@@ -4917,6 +4929,7 @@ struct smb_version_operations smb21_operations = {
.make_node = smb2_make_node, .make_node = smb2_make_node,
.fiemap = smb3_fiemap, .fiemap = smb3_fiemap,
.llseek = smb3_llseek, .llseek = smb3_llseek,
.is_status_io_timeout = smb2_is_status_io_timeout,
}; };
struct smb_version_operations smb30_operations = { struct smb_version_operations smb30_operations = {
...@@ -5027,6 +5040,7 @@ struct smb_version_operations smb30_operations = { ...@@ -5027,6 +5040,7 @@ struct smb_version_operations smb30_operations = {
.make_node = smb2_make_node, .make_node = smb2_make_node,
.fiemap = smb3_fiemap, .fiemap = smb3_fiemap,
.llseek = smb3_llseek, .llseek = smb3_llseek,
.is_status_io_timeout = smb2_is_status_io_timeout,
}; };
struct smb_version_operations smb311_operations = { struct smb_version_operations smb311_operations = {
...@@ -5138,6 +5152,7 @@ struct smb_version_operations smb311_operations = { ...@@ -5138,6 +5152,7 @@ struct smb_version_operations smb311_operations = {
.make_node = smb2_make_node, .make_node = smb2_make_node,
.fiemap = smb3_fiemap, .fiemap = smb3_fiemap,
.llseek = smb3_llseek, .llseek = smb3_llseek,
.is_status_io_timeout = smb2_is_status_io_timeout,
}; };
struct smb_version_values smb20_values = { struct smb_version_values smb20_values = {
......
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