提交 bb3b621a 编写于 作者: R Ren Mingxin 提交者: James Bottomley

[SCSI] Set the minimum valid value of 'eh_deadline' as 0

The former minimum valid value of 'eh_deadline' is 1s, which means
the earliest occasion to shorten EH is 1 second later since a
command is failed or timed out. But if we want to skip EH steps
ASAP, we have to wait until the first EH step is finished. If the
duration of the first EH step is long, this waiting time is
excruciating. So, it is necessary to accept 0 as the minimum valid
value for 'eh_deadline'.

According to my test, with Hannes' patchset 'New EH command timeout
handler' as well, the minimum IO time is improved from 73s
(eh_deadline = 1) to 43s(eh_deadline = 0) when commands are timed
out by disabling RSCN and target port.
Signed-off-by: NRen Mingxin <renmx@cn.fujitsu.com>
Signed-off-by: NHannes Reinecke <hare@suse.de>
Signed-off-by: NJames Bottomley <JBottomley@Parallels.com>
上级 76ad3e59
...@@ -319,11 +319,11 @@ static void scsi_host_dev_release(struct device *dev) ...@@ -319,11 +319,11 @@ static void scsi_host_dev_release(struct device *dev)
kfree(shost); kfree(shost);
} }
static unsigned int shost_eh_deadline; static int shost_eh_deadline = -1;
module_param_named(eh_deadline, shost_eh_deadline, uint, S_IRUGO|S_IWUSR); module_param_named(eh_deadline, shost_eh_deadline, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(eh_deadline, MODULE_PARM_DESC(eh_deadline,
"SCSI EH timeout in seconds (should be between 1 and 2^32-1)"); "SCSI EH timeout in seconds (should be between 0 and 2^31-1)");
static struct device_type scsi_host_type = { static struct device_type scsi_host_type = {
.name = "scsi_host", .name = "scsi_host",
...@@ -396,9 +396,18 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) ...@@ -396,9 +396,18 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
shost->unchecked_isa_dma = sht->unchecked_isa_dma; shost->unchecked_isa_dma = sht->unchecked_isa_dma;
shost->use_clustering = sht->use_clustering; shost->use_clustering = sht->use_clustering;
shost->ordered_tag = sht->ordered_tag; shost->ordered_tag = sht->ordered_tag;
shost->eh_deadline = shost_eh_deadline * HZ;
shost->no_write_same = sht->no_write_same; shost->no_write_same = sht->no_write_same;
if (shost_eh_deadline == -1)
shost->eh_deadline = -1;
else if ((ulong) shost_eh_deadline * HZ > INT_MAX) {
shost_printk(KERN_WARNING, shost,
"eh_deadline %u too large, setting to %u\n",
shost_eh_deadline, INT_MAX / HZ);
shost->eh_deadline = INT_MAX;
} else
shost->eh_deadline = shost_eh_deadline * HZ;
if (sht->supported_mode == MODE_UNKNOWN) if (sht->supported_mode == MODE_UNKNOWN)
/* means we didn't set it ... default to INITIATOR */ /* means we didn't set it ... default to INITIATOR */
shost->active_mode = MODE_INITIATOR; shost->active_mode = MODE_INITIATOR;
......
...@@ -91,18 +91,18 @@ EXPORT_SYMBOL_GPL(scsi_schedule_eh); ...@@ -91,18 +91,18 @@ EXPORT_SYMBOL_GPL(scsi_schedule_eh);
static int scsi_host_eh_past_deadline(struct Scsi_Host *shost) static int scsi_host_eh_past_deadline(struct Scsi_Host *shost)
{ {
if (!shost->last_reset || !shost->eh_deadline) if (!shost->last_reset || shost->eh_deadline == -1)
return 0; return 0;
/* /*
* 32bit accesses are guaranteed to be atomic * 32bit accesses are guaranteed to be atomic
* (on all supported architectures), so instead * (on all supported architectures), so instead
* of using a spinlock we can as well double check * of using a spinlock we can as well double check
* if eh_deadline has been unset during the * if eh_deadline has been set to 'off' during the
* time_before call. * time_before call.
*/ */
if (time_before(jiffies, shost->last_reset + shost->eh_deadline) && if (time_before(jiffies, shost->last_reset + shost->eh_deadline) &&
shost->eh_deadline != 0) shost->eh_deadline > -1)
return 0; return 0;
return 1; return 1;
...@@ -132,26 +132,34 @@ scmd_eh_abort_handler(struct work_struct *work) ...@@ -132,26 +132,34 @@ scmd_eh_abort_handler(struct work_struct *work)
rtn = scsi_try_to_abort_cmd(sdev->host->hostt, scmd); rtn = scsi_try_to_abort_cmd(sdev->host->hostt, scmd);
if (rtn == SUCCESS) { if (rtn == SUCCESS) {
scmd->result |= DID_TIME_OUT << 16; scmd->result |= DID_TIME_OUT << 16;
if (!scsi_noretry_cmd(scmd) && if (scsi_host_eh_past_deadline(sdev->host)) {
SCSI_LOG_ERROR_RECOVERY(3,
scmd_printk(KERN_INFO, scmd,
"scmd %p eh timeout, "
"not retrying aborted "
"command\n", scmd));
} else if (!scsi_noretry_cmd(scmd) &&
(++scmd->retries <= scmd->allowed)) { (++scmd->retries <= scmd->allowed)) {
SCSI_LOG_ERROR_RECOVERY(3, SCSI_LOG_ERROR_RECOVERY(3,
scmd_printk(KERN_WARNING, scmd, scmd_printk(KERN_WARNING, scmd,
"scmd %p retry " "scmd %p retry "
"aborted command\n", scmd)); "aborted command\n", scmd));
scsi_queue_insert(scmd, SCSI_MLQUEUE_EH_RETRY); scsi_queue_insert(scmd, SCSI_MLQUEUE_EH_RETRY);
return;
} else { } else {
SCSI_LOG_ERROR_RECOVERY(3, SCSI_LOG_ERROR_RECOVERY(3,
scmd_printk(KERN_WARNING, scmd, scmd_printk(KERN_WARNING, scmd,
"scmd %p finish " "scmd %p finish "
"aborted command\n", scmd)); "aborted command\n", scmd));
scsi_finish_command(scmd); scsi_finish_command(scmd);
return;
} }
return; } else {
SCSI_LOG_ERROR_RECOVERY(3,
scmd_printk(KERN_INFO, scmd,
"scmd %p abort failed, rtn %d\n",
scmd, rtn));
} }
SCSI_LOG_ERROR_RECOVERY(3,
scmd_printk(KERN_INFO, scmd,
"scmd %p abort failed, rtn %d\n",
scmd, rtn));
} }
if (!scsi_eh_scmd_add(scmd, 0)) { if (!scsi_eh_scmd_add(scmd, 0)) {
...@@ -202,7 +210,7 @@ scsi_abort_command(struct scsi_cmnd *scmd) ...@@ -202,7 +210,7 @@ scsi_abort_command(struct scsi_cmnd *scmd)
return FAILED; return FAILED;
} }
if (shost->eh_deadline && !shost->last_reset) if (shost->eh_deadline != -1 && !shost->last_reset)
shost->last_reset = jiffies; shost->last_reset = jiffies;
spin_unlock_irqrestore(shost->host_lock, flags); spin_unlock_irqrestore(shost->host_lock, flags);
...@@ -236,7 +244,7 @@ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag) ...@@ -236,7 +244,7 @@ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag)
if (scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY)) if (scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY))
goto out_unlock; goto out_unlock;
if (shost->eh_deadline && !shost->last_reset) if (shost->eh_deadline != -1 && !shost->last_reset)
shost->last_reset = jiffies; shost->last_reset = jiffies;
ret = 1; ret = 1;
...@@ -270,7 +278,7 @@ enum blk_eh_timer_return scsi_times_out(struct request *req) ...@@ -270,7 +278,7 @@ enum blk_eh_timer_return scsi_times_out(struct request *req)
trace_scsi_dispatch_cmd_timeout(scmd); trace_scsi_dispatch_cmd_timeout(scmd);
scsi_log_completion(scmd, TIMEOUT_ERROR); scsi_log_completion(scmd, TIMEOUT_ERROR);
if (host->eh_deadline && !host->last_reset) if (host->eh_deadline != -1 && !host->last_reset)
host->last_reset = jiffies; host->last_reset = jiffies;
if (host->transportt->eh_timed_out) if (host->transportt->eh_timed_out)
...@@ -2106,7 +2114,7 @@ static void scsi_unjam_host(struct Scsi_Host *shost) ...@@ -2106,7 +2114,7 @@ static void scsi_unjam_host(struct Scsi_Host *shost)
scsi_eh_ready_devs(shost, &eh_work_q, &eh_done_q); scsi_eh_ready_devs(shost, &eh_work_q, &eh_done_q);
spin_lock_irqsave(shost->host_lock, flags); spin_lock_irqsave(shost->host_lock, flags);
if (shost->eh_deadline) if (shost->eh_deadline != -1)
shost->last_reset = 0; shost->last_reset = 0;
spin_unlock_irqrestore(shost->host_lock, flags); spin_unlock_irqrestore(shost->host_lock, flags);
scsi_eh_flush_done_q(&eh_done_q); scsi_eh_flush_done_q(&eh_done_q);
......
...@@ -287,7 +287,9 @@ show_shost_eh_deadline(struct device *dev, ...@@ -287,7 +287,9 @@ show_shost_eh_deadline(struct device *dev,
{ {
struct Scsi_Host *shost = class_to_shost(dev); struct Scsi_Host *shost = class_to_shost(dev);
return sprintf(buf, "%d\n", shost->eh_deadline / HZ); if (shost->eh_deadline == -1)
return snprintf(buf, strlen("off") + 2, "off\n");
return sprintf(buf, "%u\n", shost->eh_deadline / HZ);
} }
static ssize_t static ssize_t
...@@ -296,22 +298,34 @@ store_shost_eh_deadline(struct device *dev, struct device_attribute *attr, ...@@ -296,22 +298,34 @@ store_shost_eh_deadline(struct device *dev, struct device_attribute *attr,
{ {
struct Scsi_Host *shost = class_to_shost(dev); struct Scsi_Host *shost = class_to_shost(dev);
int ret = -EINVAL; int ret = -EINVAL;
int deadline; unsigned long deadline, flags;
unsigned long flags;
if (shost->transportt && shost->transportt->eh_strategy_handler) if (shost->transportt && shost->transportt->eh_strategy_handler)
return ret; return ret;
if (sscanf(buf, "%d\n", &deadline) == 1) { if (!strncmp(buf, "off", strlen("off")))
spin_lock_irqsave(shost->host_lock, flags); deadline = -1;
if (scsi_host_in_recovery(shost)) else {
ret = -EBUSY; ret = kstrtoul(buf, 10, &deadline);
else { if (ret)
return ret;
if (deadline * HZ > UINT_MAX)
return -EINVAL;
}
spin_lock_irqsave(shost->host_lock, flags);
if (scsi_host_in_recovery(shost))
ret = -EBUSY;
else {
if (deadline == -1)
shost->eh_deadline = -1;
else
shost->eh_deadline = deadline * HZ; shost->eh_deadline = deadline * HZ;
ret = count;
} ret = count;
spin_unlock_irqrestore(shost->host_lock, flags);
} }
spin_unlock_irqrestore(shost->host_lock, flags);
return ret; return ret;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册