Commit 86cbfb5607d4b81b1a993ff689bbd2addd5d3a9b

Authored by James Bottomley
1 parent 0b8393578c

[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