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: Rohith Surabattula <rohiths@microsoft.com> Reviewed-by: Aurelien Aptel <aaptel@suse.com> Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com> Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
parent
d1542cf616
commit
8e670f77c4
4 changed files with 32 additions and 2 deletions
|
@ -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;
|
||||||
#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)
|
||||||
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 @@ next_pdu:
|
||||||
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[] = {
|
||||||
{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)
|
||||||
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 = {
|
||||||
.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 = {
|
||||||
.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 = {
|
||||||
.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 = {
|
||||||
.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 = {
|
||||||
|
|
Loading…
Add table
Reference in a new issue