Commit 86cbfb5607d4b81b1a993ff689bbd2addd5d3a9b
1 parent
0b8393578c
Exists in
master
and in
4 other branches
[SCSI] put stricter guards on queue dead checks
SCSI uses request_queue->queuedata == NULL as a signal that the queue is dying. We set this state in the sdev release function. However, this allows a small window where we release the last reference but haven't quite got to this stage yet and so something will try to take a reference in scsi_request_fn and oops. It's very rare, but we had a report here, so we're pushing this as a bug fix The actual fix is to set request_queue->queuedata to NULL in scsi_remove_device() before we drop the reference. This causes correct automatic rejects from scsi_request_fn as people who hold additional references try to submit work and prevents anything from getting a new reference to the sdev that way. Cc: stable@kernel.org Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Showing 1 changed file with 8 additions and 8 deletions Side-by-side Diff
drivers/scsi/scsi_sysfs.c
... | ... | @@ -322,14 +322,8 @@ |
322 | 322 | kfree(evt); |
323 | 323 | } |
324 | 324 | |
325 | - if (sdev->request_queue) { | |
326 | - sdev->request_queue->queuedata = NULL; | |
327 | - /* user context needed to free queue */ | |
328 | - scsi_free_queue(sdev->request_queue); | |
329 | - /* temporary expedient, try to catch use of queue lock | |
330 | - * after free of sdev */ | |
331 | - sdev->request_queue = NULL; | |
332 | - } | |
325 | + /* NULL queue means the device can't be used */ | |
326 | + sdev->request_queue = NULL; | |
333 | 327 | |
334 | 328 | scsi_target_reap(scsi_target(sdev)); |
335 | 329 | |
... | ... | @@ -937,6 +931,12 @@ |
937 | 931 | if (sdev->host->hostt->slave_destroy) |
938 | 932 | sdev->host->hostt->slave_destroy(sdev); |
939 | 933 | transport_destroy_device(dev); |
934 | + | |
935 | + /* cause the request function to reject all I/O requests */ | |
936 | + sdev->request_queue->queuedata = NULL; | |
937 | + | |
938 | + /* Freeing the queue signals to block that we're done */ | |
939 | + scsi_free_queue(sdev->request_queue); | |
940 | 940 | put_device(dev); |
941 | 941 | } |
942 | 942 |