mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-21 08:19:28 +00:00
[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
1 changed files with 6 additions and 8 deletions
|
@ -2441,20 +2441,18 @@ int
|
|||
scsi_internal_device_unblock(struct scsi_device *sdev)
|
||||
{
|
||||
struct request_queue *q = sdev->request_queue;
|
||||
int err;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* Try to transition the scsi device to SDEV_RUNNING
|
||||
* and goose the device queue if successful.
|
||||
*/
|
||||
err = scsi_device_set_state(sdev, SDEV_RUNNING);
|
||||
if (err) {
|
||||
err = scsi_device_set_state(sdev, SDEV_CREATED);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
if (sdev->sdev_state == SDEV_BLOCK)
|
||||
sdev->sdev_state = SDEV_RUNNING;
|
||||
else if (sdev->sdev_state == SDEV_CREATED_BLOCK)
|
||||
sdev->sdev_state = SDEV_CREATED;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(q->queue_lock, flags);
|
||||
blk_start_queue(q);
|
||||
|
|
Loading…
Reference in a new issue