On Wed, 2013-10-09 at 15:43 +0800, Ren Mingxin wrote:
> 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.
> 
> Another thing: scsi_finish_command() should be invoked if
> scsi_eh_scmd_add() is returned on failure - let EH finish those
> commands.
> 
> Signed-off-by: Ren Mingxin <re...@cn.fujitsu.com>
> ---
>  drivers/scsi/hosts.c      |   14 +++++++++++---
>  drivers/scsi/scsi_error.c |   40 +++++++++++++++++++++++++++-------------
>  drivers/scsi/scsi_sysfs.c |   36 +++++++++++++++++++++++++-----------
>  include/scsi/scsi_host.h  |    2 +-
>  4 files changed, 64 insertions(+), 28 deletions(-)
> 
> diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
> index f334859..e84123a 100644
> --- a/drivers/scsi/hosts.c
> +++ b/drivers/scsi/hosts.c
> @@ -316,11 +316,11 @@ static void scsi_host_dev_release(struct device *dev)
>       kfree(shost);
>  }
>  
> -static unsigned int shost_eh_deadline;
> +static unsigned int shost_eh_deadline = -1;

This should probably be "static int shost_eh_deadline = -1;".
And the range tests in scsi_host_alloc() and store_shost_eh_deadline()
below should probably use INT_MAX rather than UINT_MAX.

>  
>  module_param_named(eh_deadline, shost_eh_deadline, uint, S_IRUGO|S_IWUSR);
>  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^32-1)");
>  
>  static struct device_type scsi_host_type = {
>       .name =         "scsi_host",
> @@ -394,7 +394,15 @@ struct Scsi_Host *scsi_host_alloc(struct 
> scsi_host_template *sht, int privsize)
>       shost->unchecked_isa_dma = sht->unchecked_isa_dma;
>       shost->use_clustering = sht->use_clustering;
>       shost->ordered_tag = sht->ordered_tag;
> -     shost->eh_deadline = shost_eh_deadline * HZ;
> +     if (shost_eh_deadline == -1)
> +             shost->eh_deadline = -1;
> +     else if ((ulong) shost_eh_deadline * HZ > UINT_MAX) {
> +             printk(KERN_WARNING "scsi%d: eh_deadline %u exceeds the "
> +                    "maximum, setting to %u\n",
> +                    shost->host_no, shost_eh_deadline, UINT_MAX / HZ);
> +             shost->eh_deadline = UINT_MAX / HZ * HZ;

Just use "shost->eh_deadline = INT_MAX" here, leave off the "/ HZ * HZ".

> +     } else
> +             shost->eh_deadline = shost_eh_deadline * HZ;
>  
>       if (sht->supported_mode == MODE_UNKNOWN)
>               /* means we didn't set it ... default to INITIATOR */
> diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
> index adb4cbe..c2f9431 100644
> --- a/drivers/scsi/scsi_error.c
> +++ b/drivers/scsi/scsi_error.c
> @@ -90,7 +90,7 @@ EXPORT_SYMBOL_GPL(scsi_schedule_eh);
>  
>  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;
>  
>       if (time_before(jiffies,
> @@ -127,29 +127,43 @@ scmd_eh_abort_handler(struct work_struct *work)
>               rtn = scsi_try_to_abort_cmd(sdev->host->hostt, scmd);
>               if (rtn == SUCCESS) {
>                       scmd->result |= DID_TIME_OUT << 16;
> -                     if (!scsi_noretry_cmd(scmd) &&
> +                     spin_lock_irqsave(sdev->host->host_lock, flags);
> +                     if (scsi_host_eh_past_deadline(sdev->host)) {
> +                             spin_unlock_irqrestore(sdev->host->host_lock,
> +                                                    flags);
> +                             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)) {
> +                             spin_unlock_irqrestore(sdev->host->host_lock,
> +                                                    flags);
>                               SCSI_LOG_ERROR_RECOVERY(3,
>                                       scmd_printk(KERN_WARNING, scmd,
>                                                   "scmd %p retry "
>                                                   "aborted command\n", scmd));
>                               scsi_queue_insert(scmd, SCSI_MLQUEUE_EH_RETRY);
> +                             return;
>                       } else {
> +                             spin_unlock_irqrestore(sdev->host->host_lock,
> +                                                    flags);
>                               SCSI_LOG_ERROR_RECOVERY(3,
>                                       scmd_printk(KERN_WARNING, scmd,
>                                                   "scmd %p finish "
>                                                   "aborted command\n", scmd));
>                               scsi_finish_command(scmd);
> +                             return;
>                       }
> -                     return;
> -             }
> -             SCSI_LOG_ERROR_RECOVERY(3,
> -                     scmd_printk(KERN_INFO, scmd,
> -                                 "scmd %p abort failed, rtn %d\n",
> -                                 scmd, rtn));
> +             } else
> +                     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)) {
>               SCSI_LOG_ERROR_RECOVERY(3,
>                       scmd_printk(KERN_WARNING, scmd,
>                                   "scmd %p terminate "
> @@ -197,7 +211,7 @@ scsi_abort_command(struct scsi_cmnd *scmd)
>               return FAILED;
>       }
>  
> -     if (shost->eh_deadline && !shost->last_reset)
> +     if (shost->eh_deadline != -1 && !shost->last_reset)
>               shost->last_reset = jiffies;
>       spin_unlock_irqrestore(shost->host_lock, flags);
>  
> @@ -231,7 +245,7 @@ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag)
>               if (scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY))
>                       goto out_unlock;
>  
> -     if (shost->eh_deadline && !shost->last_reset)
> +     if (shost->eh_deadline != -1 && !shost->last_reset)
>               shost->last_reset = jiffies;
>  
>       ret = 1;
> @@ -265,7 +279,7 @@ enum blk_eh_timer_return scsi_times_out(struct request 
> *req)
>       trace_scsi_dispatch_cmd_timeout(scmd);
>       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;
>  
>       if (host->transportt->eh_timed_out)
> @@ -2130,7 +2144,7 @@ static void scsi_unjam_host(struct Scsi_Host *shost)
>                       scsi_eh_ready_devs(shost, &eh_work_q, &eh_done_q);
>  
>       spin_lock_irqsave(shost->host_lock, flags);
> -     if (shost->eh_deadline)
> +     if (shost->eh_deadline != -1)
>               shost->last_reset = 0;
>       spin_unlock_irqrestore(shost->host_lock, flags);
>       scsi_eh_flush_done_q(&eh_done_q);
> diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
> index 57c78ef..b0591aa 100644
> --- a/drivers/scsi/scsi_sysfs.c
> +++ b/drivers/scsi/scsi_sysfs.c
> @@ -287,7 +287,9 @@ show_shost_eh_deadline(struct device *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
> @@ -296,22 +298,34 @@ store_shost_eh_deadline(struct device *dev, struct 
> device_attribute *attr,
>  {
>       struct Scsi_Host *shost = class_to_shost(dev);
>       int ret = -EINVAL;
> -     int deadline;
> -     unsigned long flags;
> +     unsigned long deadline, flags;
> +     char *cp;
>  
>       if (shost->transportt && shost->transportt->eh_strategy_handler)
>               return ret;
>  
> -     if (sscanf(buf, "%d\n", &deadline) == 1) {
> -             spin_lock_irqsave(shost->host_lock, flags);
> -             if (scsi_host_in_recovery(shost))
> -                     ret = -EBUSY;
> -             else {
> +     if (!strncmp(buf, "off", strlen("off")))
> +             deadline = -1;
> +     else {
> +             deadline = simple_strtoul(buf, &cp, 0);
> +             if ((*cp && (*cp != '\n')) ||
> +                 deadline * HZ > UINT_MAX)
> +                     return ret;
> +     }
> +
> +     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;
> -                     ret = count;
> -             }
> -             spin_unlock_irqrestore(shost->host_lock, flags);
> +
> +             ret = count;
>       }
> +     spin_unlock_irqrestore(shost->host_lock, flags);
> +
>       return ret;
>  }
>  
> diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
> index 6ca9174..b50355c 100644
> --- a/include/scsi/scsi_host.h
> +++ b/include/scsi/scsi_host.h
> @@ -603,7 +603,7 @@ struct Scsi_Host {
>       unsigned int host_eh_scheduled;    /* EH scheduled without command */
>  
>       unsigned int host_no;  /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */
> -     int eh_deadline;
> +     unsigned int eh_deadline;
>       unsigned long last_reset;
>  
>       /*


--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to