aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRen Mingxin <renmx@cn.fujitsu.com>2013-11-11 07:44:56 -0500
committerJames Bottomley <JBottomley@Parallels.com>2013-12-19 10:39:02 -0500
commitbb3b621a33d60fc2baddf31597ade01243e00a2c (patch)
tree73fae0429ce43ce37845e207cb36da2e8f54d42c
parent76ad3e5956bf0bc8871ebd19ebda03f2287c966a (diff)
[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: Ren Mingxin <renmx@cn.fujitsu.com> Signed-off-by: Hannes Reinecke <hare@suse.de> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
-rw-r--r--drivers/scsi/hosts.c17
-rw-r--r--drivers/scsi/scsi_error.c34
-rw-r--r--drivers/scsi/scsi_sysfs.c36
3 files changed, 59 insertions, 28 deletions
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index c3ab093dd8a7..f28ea070d3df 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -319,11 +319,11 @@ static void scsi_host_dev_release(struct device *dev)
319 kfree(shost); 319 kfree(shost);
320} 320}
321 321
322static unsigned int shost_eh_deadline; 322static int shost_eh_deadline = -1;
323 323
324module_param_named(eh_deadline, shost_eh_deadline, uint, S_IRUGO|S_IWUSR); 324module_param_named(eh_deadline, shost_eh_deadline, int, S_IRUGO|S_IWUSR);
325MODULE_PARM_DESC(eh_deadline, 325MODULE_PARM_DESC(eh_deadline,
326 "SCSI EH timeout in seconds (should be between 1 and 2^32-1)"); 326 "SCSI EH timeout in seconds (should be between 0 and 2^31-1)");
327 327
328static struct device_type scsi_host_type = { 328static struct device_type scsi_host_type = {
329 .name = "scsi_host", 329 .name = "scsi_host",
@@ -396,9 +396,18 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
396 shost->unchecked_isa_dma = sht->unchecked_isa_dma; 396 shost->unchecked_isa_dma = sht->unchecked_isa_dma;
397 shost->use_clustering = sht->use_clustering; 397 shost->use_clustering = sht->use_clustering;
398 shost->ordered_tag = sht->ordered_tag; 398 shost->ordered_tag = sht->ordered_tag;
399 shost->eh_deadline = shost_eh_deadline * HZ;
400 shost->no_write_same = sht->no_write_same; 399 shost->no_write_same = sht->no_write_same;
401 400
401 if (shost_eh_deadline == -1)
402 shost->eh_deadline = -1;
403 else if ((ulong) shost_eh_deadline * HZ > INT_MAX) {
404 shost_printk(KERN_WARNING, shost,
405 "eh_deadline %u too large, setting to %u\n",
406 shost_eh_deadline, INT_MAX / HZ);
407 shost->eh_deadline = INT_MAX;
408 } else
409 shost->eh_deadline = shost_eh_deadline * HZ;
410
402 if (sht->supported_mode == MODE_UNKNOWN) 411 if (sht->supported_mode == MODE_UNKNOWN)
403 /* means we didn't set it ... default to INITIATOR */ 412 /* means we didn't set it ... default to INITIATOR */
404 shost->active_mode = MODE_INITIATOR; 413 shost->active_mode = MODE_INITIATOR;
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 4e4824beefe4..78b004da2885 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -91,18 +91,18 @@ EXPORT_SYMBOL_GPL(scsi_schedule_eh);
91 91
92static int scsi_host_eh_past_deadline(struct Scsi_Host *shost) 92static int scsi_host_eh_past_deadline(struct Scsi_Host *shost)
93{ 93{
94 if (!shost->last_reset || !shost->eh_deadline) 94 if (!shost->last_reset || shost->eh_deadline == -1)
95 return 0; 95 return 0;
96 96
97 /* 97 /*
98 * 32bit accesses are guaranteed to be atomic 98 * 32bit accesses are guaranteed to be atomic
99 * (on all supported architectures), so instead 99 * (on all supported architectures), so instead
100 * of using a spinlock we can as well double check 100 * of using a spinlock we can as well double check
101 * if eh_deadline has been unset during the 101 * if eh_deadline has been set to 'off' during the
102 * time_before call. 102 * time_before call.
103 */ 103 */
104 if (time_before(jiffies, shost->last_reset + shost->eh_deadline) && 104 if (time_before(jiffies, shost->last_reset + shost->eh_deadline) &&
105 shost->eh_deadline != 0) 105 shost->eh_deadline > -1)
106 return 0; 106 return 0;
107 107
108 return 1; 108 return 1;
@@ -132,26 +132,34 @@ scmd_eh_abort_handler(struct work_struct *work)
132 rtn = scsi_try_to_abort_cmd(sdev->host->hostt, scmd); 132 rtn = scsi_try_to_abort_cmd(sdev->host->hostt, scmd);
133 if (rtn == SUCCESS) { 133 if (rtn == SUCCESS) {
134 scmd->result |= DID_TIME_OUT << 16; 134 scmd->result |= DID_TIME_OUT << 16;
135 if (!scsi_noretry_cmd(scmd) && 135 if (scsi_host_eh_past_deadline(sdev->host)) {
136 SCSI_LOG_ERROR_RECOVERY(3,
137 scmd_printk(KERN_INFO, scmd,
138 "scmd %p eh timeout, "
139 "not retrying aborted "
140 "command\n", scmd));
141 } else if (!scsi_noretry_cmd(scmd) &&
136 (++scmd->retries <= scmd->allowed)) { 142 (++scmd->retries <= scmd->allowed)) {
137 SCSI_LOG_ERROR_RECOVERY(3, 143 SCSI_LOG_ERROR_RECOVERY(3,
138 scmd_printk(KERN_WARNING, scmd, 144 scmd_printk(KERN_WARNING, scmd,
139 "scmd %p retry " 145 "scmd %p retry "
140 "aborted command\n", scmd)); 146 "aborted command\n", scmd));
141 scsi_queue_insert(scmd, SCSI_MLQUEUE_EH_RETRY); 147 scsi_queue_insert(scmd, SCSI_MLQUEUE_EH_RETRY);
148 return;
142 } else { 149 } else {
143 SCSI_LOG_ERROR_RECOVERY(3, 150 SCSI_LOG_ERROR_RECOVERY(3,
144 scmd_printk(KERN_WARNING, scmd, 151 scmd_printk(KERN_WARNING, scmd,
145 "scmd %p finish " 152 "scmd %p finish "
146 "aborted command\n", scmd)); 153 "aborted command\n", scmd));
147 scsi_finish_command(scmd); 154 scsi_finish_command(scmd);
155 return;
148 } 156 }
149 return; 157 } else {
158 SCSI_LOG_ERROR_RECOVERY(3,
159 scmd_printk(KERN_INFO, scmd,
160 "scmd %p abort failed, rtn %d\n",
161 scmd, rtn));
150 } 162 }
151 SCSI_LOG_ERROR_RECOVERY(3,
152 scmd_printk(KERN_INFO, scmd,
153 "scmd %p abort failed, rtn %d\n",
154 scmd, rtn));
155 } 163 }
156 164
157 if (!scsi_eh_scmd_add(scmd, 0)) { 165 if (!scsi_eh_scmd_add(scmd, 0)) {
@@ -202,7 +210,7 @@ scsi_abort_command(struct scsi_cmnd *scmd)
202 return FAILED; 210 return FAILED;
203 } 211 }
204 212
205 if (shost->eh_deadline && !shost->last_reset) 213 if (shost->eh_deadline != -1 && !shost->last_reset)
206 shost->last_reset = jiffies; 214 shost->last_reset = jiffies;
207 spin_unlock_irqrestore(shost->host_lock, flags); 215 spin_unlock_irqrestore(shost->host_lock, flags);
208 216
@@ -236,7 +244,7 @@ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag)
236 if (scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY)) 244 if (scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY))
237 goto out_unlock; 245 goto out_unlock;
238 246
239 if (shost->eh_deadline && !shost->last_reset) 247 if (shost->eh_deadline != -1 && !shost->last_reset)
240 shost->last_reset = jiffies; 248 shost->last_reset = jiffies;
241 249
242 ret = 1; 250 ret = 1;
@@ -270,7 +278,7 @@ enum blk_eh_timer_return scsi_times_out(struct request *req)
270 trace_scsi_dispatch_cmd_timeout(scmd); 278 trace_scsi_dispatch_cmd_timeout(scmd);
271 scsi_log_completion(scmd, TIMEOUT_ERROR); 279 scsi_log_completion(scmd, TIMEOUT_ERROR);
272 280
273 if (host->eh_deadline && !host->last_reset) 281 if (host->eh_deadline != -1 && !host->last_reset)
274 host->last_reset = jiffies; 282 host->last_reset = jiffies;
275 283
276 if (host->transportt->eh_timed_out) 284 if (host->transportt->eh_timed_out)
@@ -2106,7 +2114,7 @@ static void scsi_unjam_host(struct Scsi_Host *shost)
2106 scsi_eh_ready_devs(shost, &eh_work_q, &eh_done_q); 2114 scsi_eh_ready_devs(shost, &eh_work_q, &eh_done_q);
2107 2115
2108 spin_lock_irqsave(shost->host_lock, flags); 2116 spin_lock_irqsave(shost->host_lock, flags);
2109 if (shost->eh_deadline) 2117 if (shost->eh_deadline != -1)
2110 shost->last_reset = 0; 2118 shost->last_reset = 0;
2111 spin_unlock_irqrestore(shost->host_lock, flags); 2119 spin_unlock_irqrestore(shost->host_lock, flags);
2112 scsi_eh_flush_done_q(&eh_done_q); 2120 scsi_eh_flush_done_q(&eh_done_q);
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 8ff62c26a41c..9117d0bf408e 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -287,7 +287,9 @@ show_shost_eh_deadline(struct device *dev,
287{ 287{
288 struct Scsi_Host *shost = class_to_shost(dev); 288 struct Scsi_Host *shost = class_to_shost(dev);
289 289
290 return sprintf(buf, "%d\n", shost->eh_deadline / HZ); 290 if (shost->eh_deadline == -1)
291 return snprintf(buf, strlen("off") + 2, "off\n");
292 return sprintf(buf, "%u\n", shost->eh_deadline / HZ);
291} 293}
292 294
293static ssize_t 295static ssize_t
@@ -296,22 +298,34 @@ store_shost_eh_deadline(struct device *dev, struct device_attribute *attr,
296{ 298{
297 struct Scsi_Host *shost = class_to_shost(dev); 299 struct Scsi_Host *shost = class_to_shost(dev);
298 int ret = -EINVAL; 300 int ret = -EINVAL;
299 int deadline; 301 unsigned long deadline, flags;
300 unsigned long flags;
301 302
302 if (shost->transportt && shost->transportt->eh_strategy_handler) 303 if (shost->transportt && shost->transportt->eh_strategy_handler)
303 return ret; 304 return ret;
304 305
305 if (sscanf(buf, "%d\n", &deadline) == 1) { 306 if (!strncmp(buf, "off", strlen("off")))
306 spin_lock_irqsave(shost->host_lock, flags); 307 deadline = -1;
307 if (scsi_host_in_recovery(shost)) 308 else {
308 ret = -EBUSY; 309 ret = kstrtoul(buf, 10, &deadline);
309 else { 310 if (ret)
311 return ret;
312 if (deadline * HZ > UINT_MAX)
313 return -EINVAL;
314 }
315
316 spin_lock_irqsave(shost->host_lock, flags);
317 if (scsi_host_in_recovery(shost))
318 ret = -EBUSY;
319 else {
320 if (deadline == -1)
321 shost->eh_deadline = -1;
322 else
310 shost->eh_deadline = deadline * HZ; 323 shost->eh_deadline = deadline * HZ;
311 ret = count; 324
312 } 325 ret = count;
313 spin_unlock_irqrestore(shost->host_lock, flags);
314 } 326 }
327 spin_unlock_irqrestore(shost->host_lock, flags);
328
315 return ret; 329 return ret;
316} 330}
317 331