lkml.org 
[lkml]   [2011]   [Aug]   [5]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[27/50] [SCSI] fix crash in scsi_dispatch_cmd()
    2.6.33-longterm review patch.  If anyone has any objections, please let us know.

    ------------------

    From: James Bottomley <James.Bottomley@HansenPartnership.com>

    commit bfe159a51203c15d23cb3158fffdc25ec4b4dda1 upstream.

    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.

    Signed-off-by: James Bottomley <JBottomley@Parallels.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

    ---
    block/blk-core.c | 3 +++
    block/blk-exec.c | 7 +++++++
    drivers/scsi/scsi_lib.c | 2 ++
    3 files changed, 12 insertions(+)

    --- a/block/blk-core.c
    +++ b/block/blk-core.c
    @@ -865,6 +865,9 @@ struct request *blk_get_request(struct r
    {
    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);
    --- a/block/blk-exec.c
    +++ b/block/blk-exec.c
    @@ -50,6 +50,13 @@ void blk_execute_rq_nowait(struct reques
    {
    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());
    --- a/drivers/scsi/scsi_lib.c
    +++ b/drivers/scsi/scsi_lib.c
    @@ -215,6 +215,8 @@ int scsi_execute(struct scsi_device *sde
    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))



    \
     
     \ /
      Last update: 2011-08-06 02:21    [W:6.084 / U:0.052 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site