Skip to content

Commit

Permalink
[SCSI] put stricter guards on queue dead checks
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
James Bottomley authored and James Bottomley committed Apr 24, 2011
1 parent 0b83935 commit 86cbfb5
Showing 1 changed file with 8 additions and 8 deletions.
16 changes: 8 additions & 8 deletions drivers/scsi/scsi_sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -322,14 +322,8 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work)
kfree(evt);
}

if (sdev->request_queue) {
sdev->request_queue->queuedata = NULL;
/* user context needed to free queue */
scsi_free_queue(sdev->request_queue);
/* temporary expedient, try to catch use of queue lock
* after free of sdev */
sdev->request_queue = NULL;
}
/* NULL queue means the device can't be used */
sdev->request_queue = NULL;

scsi_target_reap(scsi_target(sdev));

Expand Down Expand Up @@ -937,6 +931,12 @@ void __scsi_remove_device(struct scsi_device *sdev)
if (sdev->host->hostt->slave_destroy)
sdev->host->hostt->slave_destroy(sdev);
transport_destroy_device(dev);

/* cause the request function to reject all I/O requests */
sdev->request_queue->queuedata = NULL;

/* Freeing the queue signals to block that we're done */
scsi_free_queue(sdev->request_queue);
put_device(dev);
}

Expand Down

0 comments on commit 86cbfb5

Please sign in to comment.