diff options
author | Aaron Lu <aaron.lu@intel.com> | 2013-10-10 01:22:36 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2013-10-23 09:09:18 -0400 |
commit | 10c580e4239df5c3344ca00322eca86ab2de880b (patch) | |
tree | 81425dadc373bb8dd7299d81c736e78f3bb87c62 /drivers/scsi | |
parent | 36008cf118235cee49b6753455f33b6f2c3a7543 (diff) |
[SCSI] sd: call blk_pm_runtime_init before add_disk
Sujit has found a race condition that would make q->nr_pending
unbalanced, it occurs as Sujit explained:
"
sd_probe_async() ->
add_disk() ->
disk_add_event() ->
schedule(disk_events_workfn)
sd_revalidate_disk()
blk_pm_runtime_init()
return;
Let's say the disk_events_workfn() calls sd_check_events() which tries
to send test_unit_ready() and because of sd_revalidate_disk() trying to
send another commands the test_unit_ready() might be re-queued as the
tagged command queuing is disabled.
So the race condition is -
Thread 1 | Thread 2
sd_revalidate_disk() | sd_check_events()
...nr_pending = 0 as q->dev = NULL| scsi_queue_insert()
blk_runtime_pm_init() | blk_pm_requeue_request() ->
| nr_pending = -1 since
| q->dev != NULL
"
The problem is, the test_unit_ready request doesn't get counted the
first time it is queued, so the later decrement of q->nr_pending in
blk_pm_requeue_request makes it unbalanced.
Fix this by calling blk_pm_runtime_init before add_disk so that all
requests initiated there will all be counted.
Signed-off-by: Aaron Lu <aaron.lu@intel.com>
Reported-and-tested-by: Sujit Reddy Thumma <sthumma@codeaurora.org>
Cc: stable@vger.kernel.org
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/sd.c | 2 |
1 files changed, 1 insertions, 1 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index e62d17d41d4e..5693f6d7eddb 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c | |||
@@ -2854,6 +2854,7 @@ static void sd_probe_async(void *data, async_cookie_t cookie) | |||
2854 | gd->events |= DISK_EVENT_MEDIA_CHANGE; | 2854 | gd->events |= DISK_EVENT_MEDIA_CHANGE; |
2855 | } | 2855 | } |
2856 | 2856 | ||
2857 | blk_pm_runtime_init(sdp->request_queue, dev); | ||
2857 | add_disk(gd); | 2858 | add_disk(gd); |
2858 | if (sdkp->capacity) | 2859 | if (sdkp->capacity) |
2859 | sd_dif_config_host(sdkp); | 2860 | sd_dif_config_host(sdkp); |
@@ -2862,7 +2863,6 @@ static void sd_probe_async(void *data, async_cookie_t cookie) | |||
2862 | 2863 | ||
2863 | sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n", | 2864 | sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n", |
2864 | sdp->removable ? "removable " : ""); | 2865 | sdp->removable ? "removable " : ""); |
2865 | blk_pm_runtime_init(sdp->request_queue, dev); | ||
2866 | scsi_autopm_put_device(sdp); | 2866 | scsi_autopm_put_device(sdp); |
2867 | put_device(&sdkp->dev); | 2867 | put_device(&sdkp->dev); |
2868 | } | 2868 | } |