block: unify request timeout handling
Right now SCSI and others do their own command timeout handling. Move those bits to the block layer. Instead of having a timer per command, we try to be a bit more clever and simply have one per-queue. This avoids the overhead of having to tear down and setup a timer for each command, so it will result in a lot less timer fiddling. Signed-off-by: Mike Anderson <andmike@linux.vnet.ibm.com> Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
此提交包含在:
@@ -291,7 +291,6 @@ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask)
|
||||
unsigned long flags;
|
||||
|
||||
cmd->device = dev;
|
||||
init_timer(&cmd->eh_timeout);
|
||||
INIT_LIST_HEAD(&cmd->list);
|
||||
spin_lock_irqsave(&dev->list_lock, flags);
|
||||
list_add_tail(&cmd->list, &dev->cmd_list);
|
||||
@@ -652,14 +651,19 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
|
||||
unsigned long timeout;
|
||||
int rtn = 0;
|
||||
|
||||
/*
|
||||
* We will use a queued command if possible, otherwise we will
|
||||
* emulate the queuing and calling of completion function ourselves.
|
||||
*/
|
||||
atomic_inc(&cmd->device->iorequest_cnt);
|
||||
|
||||
/* check if the device is still usable */
|
||||
if (unlikely(cmd->device->sdev_state == SDEV_DEL)) {
|
||||
/* in SDEV_DEL we error all commands. DID_NO_CONNECT
|
||||
* returns an immediate error upwards, and signals
|
||||
* that the device is no longer present */
|
||||
cmd->result = DID_NO_CONNECT << 16;
|
||||
atomic_inc(&cmd->device->iorequest_cnt);
|
||||
__scsi_done(cmd);
|
||||
scsi_done(cmd);
|
||||
/* return 0 (because the command has been processed) */
|
||||
goto out;
|
||||
}
|
||||
@@ -672,6 +676,7 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
|
||||
* future requests should not occur until the device
|
||||
* transitions out of the suspend state.
|
||||
*/
|
||||
|
||||
scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
|
||||
|
||||
SCSI_LOG_MLQUEUE(3, printk("queuecommand : device blocked \n"));
|
||||
@@ -714,20 +719,8 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
|
||||
host->resetting = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* AK: unlikely race here: for some reason the timer could
|
||||
* expire before the serial number is set up below.
|
||||
*/
|
||||
scsi_add_timer(cmd, cmd->timeout_per_command, scsi_times_out);
|
||||
|
||||
scsi_log_send(cmd);
|
||||
|
||||
/*
|
||||
* We will use a queued command if possible, otherwise we will
|
||||
* emulate the queuing and calling of completion function ourselves.
|
||||
*/
|
||||
atomic_inc(&cmd->device->iorequest_cnt);
|
||||
|
||||
/*
|
||||
* Before we queue this command, check if the command
|
||||
* length exceeds what the host adapter can handle.
|
||||
@@ -744,6 +737,12 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
|
||||
}
|
||||
|
||||
spin_lock_irqsave(host->host_lock, flags);
|
||||
/*
|
||||
* AK: unlikely race here: for some reason the timer could
|
||||
* expire before the serial number is set up below.
|
||||
*
|
||||
* TODO: kill serial or move to blk layer
|
||||
*/
|
||||
scsi_cmd_get_serial(host, cmd);
|
||||
|
||||
if (unlikely(host->shost_state == SHOST_DEL)) {
|
||||
@@ -754,12 +753,8 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
|
||||
}
|
||||
spin_unlock_irqrestore(host->host_lock, flags);
|
||||
if (rtn) {
|
||||
if (scsi_delete_timer(cmd)) {
|
||||
atomic_inc(&cmd->device->iodone_cnt);
|
||||
scsi_queue_insert(cmd,
|
||||
(rtn == SCSI_MLQUEUE_DEVICE_BUSY) ?
|
||||
rtn : SCSI_MLQUEUE_HOST_BUSY);
|
||||
}
|
||||
scsi_queue_insert(cmd, (rtn == SCSI_MLQUEUE_DEVICE_BUSY) ?
|
||||
rtn : SCSI_MLQUEUE_HOST_BUSY);
|
||||
SCSI_LOG_MLQUEUE(3,
|
||||
printk("queuecommand : request rejected\n"));
|
||||
}
|
||||
@@ -769,24 +764,6 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
|
||||
return rtn;
|
||||
}
|
||||
|
||||
/**
|
||||
* scsi_req_abort_cmd -- Request command recovery for the specified command
|
||||
* @cmd: pointer to the SCSI command of interest
|
||||
*
|
||||
* This function requests that SCSI Core start recovery for the
|
||||
* command by deleting the timer and adding the command to the eh
|
||||
* queue. It can be called by either LLDDs or SCSI Core. LLDDs who
|
||||
* implement their own error recovery MAY ignore the timeout event if
|
||||
* they generated scsi_req_abort_cmd.
|
||||
*/
|
||||
void scsi_req_abort_cmd(struct scsi_cmnd *cmd)
|
||||
{
|
||||
if (!scsi_delete_timer(cmd))
|
||||
return;
|
||||
scsi_times_out(cmd);
|
||||
}
|
||||
EXPORT_SYMBOL(scsi_req_abort_cmd);
|
||||
|
||||
/**
|
||||
* scsi_done - Enqueue the finished SCSI command into the done queue.
|
||||
* @cmd: The SCSI Command for which a low-level device driver (LLDD) gives
|
||||
@@ -802,42 +779,7 @@ EXPORT_SYMBOL(scsi_req_abort_cmd);
|
||||
*/
|
||||
static void scsi_done(struct scsi_cmnd *cmd)
|
||||
{
|
||||
/*
|
||||
* We don't have to worry about this one timing out anymore.
|
||||
* If we are unable to remove the timer, then the command
|
||||
* has already timed out. In which case, we have no choice but to
|
||||
* let the timeout function run, as we have no idea where in fact
|
||||
* that function could really be. It might be on another processor,
|
||||
* etc, etc.
|
||||
*/
|
||||
if (!scsi_delete_timer(cmd))
|
||||
return;
|
||||
__scsi_done(cmd);
|
||||
}
|
||||
|
||||
/* Private entry to scsi_done() to complete a command when the timer
|
||||
* isn't running --- used by scsi_times_out */
|
||||
void __scsi_done(struct scsi_cmnd *cmd)
|
||||
{
|
||||
struct request *rq = cmd->request;
|
||||
|
||||
/*
|
||||
* Set the serial numbers back to zero
|
||||
*/
|
||||
cmd->serial_number = 0;
|
||||
|
||||
atomic_inc(&cmd->device->iodone_cnt);
|
||||
if (cmd->result)
|
||||
atomic_inc(&cmd->device->ioerr_cnt);
|
||||
|
||||
BUG_ON(!rq);
|
||||
|
||||
/*
|
||||
* The uptodate/nbytes values don't matter, as we allow partial
|
||||
* completes and thus will check this in the softirq callback
|
||||
*/
|
||||
rq->completion_data = cmd;
|
||||
blk_complete_request(rq);
|
||||
blk_complete_request(cmd->request);
|
||||
}
|
||||
|
||||
/* Move this to a header if it becomes more generally useful */
|
||||
|
新增問題並參考
封鎖使用者