From: Takahiro Yasui Date: Wed, 29 Apr 2009 16:13:02 +0000 (-0400) Subject: [SCSI] limit state transitions in scsi_internal_device_unblock X-Git-Tag: v2.6.31-rc1~365^2~127 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=5c10e63c943b4c67561ddc6bf61e01d4141f881f;p=karo-tx-linux.git [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 [matthew@wil.cx: supplied rewritten base for patch] Signed-off-by: Matthew Wilcox Signed-off-by: James Bottomley --- 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 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);