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

+8 -8
+8 -8
drivers/scsi/scsi_sysfs.c
··· 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 ··· 931 937 if (sdev->host->hostt->slave_destroy) 932 938 sdev->host->hostt->slave_destroy(sdev); 933 939 transport_destroy_device(dev); 940 + 941 + /* cause the request function to reject all I/O requests */ 942 + sdev->request_queue->queuedata = NULL; 943 + 944 + /* Freeing the queue signals to block that we're done */ 945 + scsi_free_queue(sdev->request_queue); 934 946 put_device(dev); 935 947 } 936 948