Skip to content

Commit

Permalink
[SCSI] fix crash in scsi_dispatch_cmd()
Browse files Browse the repository at this point in the history
USB surprise removal of sr is triggering an oops in
scsi_dispatch_command().  What seems to be happening is that USB is
hanging on to a queue reference until the last close of the upper
device, so the crash is caused by surprise remove of a mounted CD
followed by attempted unmount.

The problem is that USB doesn't issue its final commands as part of
the SCSI teardown path, but on last close when the block queue is long
gone.  The long term fix is probably to make sr do the teardown in the
same way as sd (so remove all the lower bits on ejection, but keep the
upper disk alive until last close of user space).  However, the
current oops can be simply fixed by not allowing any commands to be
sent to a dead queue.

Cc: [email protected]
Signed-off-by: James Bottomley <[email protected]>
  • Loading branch information
James Bottomley authored and James Bottomley committed Jul 21, 2011
1 parent 79b9677 commit bfe159a
Show file tree
Hide file tree
Showing 3 changed files with 12 additions and 0 deletions.
3 changes: 3 additions & 0 deletions block/blk-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -839,6 +839,9 @@ struct request *blk_get_request(struct request_queue *q, int rw, gfp_t gfp_mask)
{
struct request *rq;

if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags)))
return NULL;

BUG_ON(rw != READ && rw != WRITE);

spin_lock_irq(q->queue_lock);
Expand Down
7 changes: 7 additions & 0 deletions block/blk-exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk,
{
int where = at_head ? ELEVATOR_INSERT_FRONT : ELEVATOR_INSERT_BACK;

if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags))) {
rq->errors = -ENXIO;
if (rq->end_io)
rq->end_io(rq, rq->errors);
return;
}

rq->rq_disk = bd_disk;
rq->end_io = done;
WARN_ON(irqs_disabled());
Expand Down
2 changes: 2 additions & 0 deletions drivers/scsi/scsi_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,8 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
int ret = DRIVER_ERROR << 24;

req = blk_get_request(sdev->request_queue, write, __GFP_WAIT);
if (!req)
return ret;

if (bufflen && blk_rq_map_kern(sdev->request_queue, req,
buffer, bufflen, __GFP_WAIT))
Expand Down

0 comments on commit bfe159a

Please sign in to comment.