Commit 5c10e63c943b4c67561ddc6bf61e01d4141f881f

Authored by Takahiro Yasui
Committed by James Bottomley
1 parent b0d428adeb

[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>

Showing 1 changed file with 6 additions and 8 deletions Side-by-side Diff

drivers/scsi/scsi_lib.c
... ... @@ -2441,20 +2441,18 @@
2441 2441 scsi_internal_device_unblock(struct scsi_device *sdev)
2442 2442 {
2443 2443 struct request_queue *q = sdev->request_queue;
2444   - int err;
2445 2444 unsigned long flags;
2446 2445  
2447 2446 /*
2448 2447 * Try to transition the scsi device to SDEV_RUNNING
2449 2448 * and goose the device queue if successful.
2450 2449 */
2451   - err = scsi_device_set_state(sdev, SDEV_RUNNING);
2452   - if (err) {
2453   - err = scsi_device_set_state(sdev, SDEV_CREATED);
2454   -
2455   - if (err)
2456   - return err;
2457   - }
  2450 + if (sdev->sdev_state == SDEV_BLOCK)
  2451 + sdev->sdev_state = SDEV_RUNNING;
  2452 + else if (sdev->sdev_state == SDEV_CREATED_BLOCK)
  2453 + sdev->sdev_state = SDEV_CREATED;
  2454 + else
  2455 + return -EINVAL;
2458 2456  
2459 2457 spin_lock_irqsave(q->queue_lock, flags);
2460 2458 blk_start_queue(q);