forked from luck/tmp_suning_uos_patched
[SCSI] limit state transitions in scsi_internal_device_unblock
scsi timeout on two or more devices may cause extremely long execution time for user applications because SDEV_OFFLINE state is changed to SDEV_RUNNING state during scsi error recovery procedures triggered by a bus reset or a host reset of scsi LLD, and scsi timeout can happens on the same devices many times. This happens because scsi_internal_device_unblock() changes device's state to SDEV_RUNNING even if a device in other states than SDEV_BLOCK, while the following two transitions are required in this function. SDEV_BLOCK -> SDEV_RUNNING SDEV_CREATED_BLOCK -> SDEV_CREATED Otherwise, it returns -EINVAL. Signed-off-by: Takahiro Yasui <tyasui@redhat.com> [matthew@wil.cx: supplied rewritten base for patch] Signed-off-by: Matthew Wilcox <matthew@wil.cx> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
This commit is contained in:
parent
b0d428adeb
commit
5c10e63c94
|
@ -2441,20 +2441,18 @@ int
|
||||||
scsi_internal_device_unblock(struct scsi_device *sdev)
|
scsi_internal_device_unblock(struct scsi_device *sdev)
|
||||||
{
|
{
|
||||||
struct request_queue *q = sdev->request_queue;
|
struct request_queue *q = sdev->request_queue;
|
||||||
int err;
|
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Try to transition the scsi device to SDEV_RUNNING
|
* Try to transition the scsi device to SDEV_RUNNING
|
||||||
* and goose the device queue if successful.
|
* and goose the device queue if successful.
|
||||||
*/
|
*/
|
||||||
err = scsi_device_set_state(sdev, SDEV_RUNNING);
|
if (sdev->sdev_state == SDEV_BLOCK)
|
||||||
if (err) {
|
sdev->sdev_state = SDEV_RUNNING;
|
||||||
err = scsi_device_set_state(sdev, SDEV_CREATED);
|
else if (sdev->sdev_state == SDEV_CREATED_BLOCK)
|
||||||
|
sdev->sdev_state = SDEV_CREATED;
|
||||||
if (err)
|
else
|
||||||
return err;
|
return -EINVAL;
|
||||||
}
|
|
||||||
|
|
||||||
spin_lock_irqsave(q->queue_lock, flags);
|
spin_lock_irqsave(q->queue_lock, flags);
|
||||||
blk_start_queue(q);
|
blk_start_queue(q);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user