diff options
author | Takahiro Yasui <tyasui@redhat.com> | 2009-04-29 12:13:02 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2009-05-23 16:44:05 -0400 |
commit | 5c10e63c943b4c67561ddc6bf61e01d4141f881f (patch) | |
tree | 7b71f601bcf852159bae15a2cf6caa038d74e27d /drivers/scsi/scsi_lib.c | |
parent | b0d428adebe9f1232c72bf4c686a6f0eed047cc2 (diff) |
[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>
Diffstat (limited to 'drivers/scsi/scsi_lib.c')
-rw-r--r-- | drivers/scsi/scsi_lib.c | 14 |
1 files changed, 6 insertions, 8 deletions
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index bb218c8b6e98..27dbf2e8e34a 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c | |||
@@ -2441,20 +2441,18 @@ int | |||
2441 | scsi_internal_device_unblock(struct scsi_device *sdev) | 2441 | scsi_internal_device_unblock(struct scsi_device *sdev) |
2442 | { | 2442 | { |
2443 | struct request_queue *q = sdev->request_queue; | 2443 | struct request_queue *q = sdev->request_queue; |
2444 | int err; | ||
2445 | unsigned long flags; | 2444 | unsigned long flags; |
2446 | 2445 | ||
2447 | /* | 2446 | /* |
2448 | * Try to transition the scsi device to SDEV_RUNNING | 2447 | * Try to transition the scsi device to SDEV_RUNNING |
2449 | * and goose the device queue if successful. | 2448 | * and goose the device queue if successful. |
2450 | */ | 2449 | */ |
2451 | err = scsi_device_set_state(sdev, SDEV_RUNNING); | 2450 | if (sdev->sdev_state == SDEV_BLOCK) |
2452 | if (err) { | 2451 | sdev->sdev_state = SDEV_RUNNING; |
2453 | err = scsi_device_set_state(sdev, SDEV_CREATED); | 2452 | else if (sdev->sdev_state == SDEV_CREATED_BLOCK) |
2454 | 2453 | sdev->sdev_state = SDEV_CREATED; | |
2455 | if (err) | 2454 | else |
2456 | return err; | 2455 | return -EINVAL; |
2457 | } | ||
2458 | 2456 | ||
2459 | spin_lock_irqsave(q->queue_lock, flags); | 2457 | spin_lock_irqsave(q->queue_lock, flags); |
2460 | blk_start_queue(q); | 2458 | blk_start_queue(q); |