• Tejun Heo's avatar
    block: add timer on blkdev_dequeue_request() not elv_next_request() · 2920ebbd
    Tejun Heo authored
    Block queue supports two usage models - one where block driver peeks
    at the front of queue using elv_next_request(), processes it and
    finishes it and the other where block driver peeks at the front of
    queue, dequeue the request using blkdev_dequeue_request() and finishes
    it.  The latter is more flexible as it allows the driver to process
    multiple commands concurrently.
    
    These two inconsistent usage models affect the block layer
    implementation confusing.  For some, elv_next_request() is considered
    the issue point while others consider blkdev_dequeue_request() the
    issue point.
    
    Till now the inconsistency mostly affect only accounting, so it didn't
    really break anything seriously; however, with block layer timeout,
    this inconsistency hits hard.  Block layer considers
    elv_next_request() the issue point and adds timer but SCSI layer
    thinks it was just peeking and when the request can't process the
    command right away, it's just left there without further processing.
    This makes the request dangling on the timer list and, when the timer
    goes off, the request which the SCSI layer and below think is still on
    the block queue ends up in the EH queue, causing various problems - EH
    hang (failed count goes over busy count and EH never wakes up),
    WARN_ON() and oopses as low level driver trying to handle the unknown
    command, etc. depending on the timing.
    
    As SCSI midlayer is the only user of block layer timer at the moment,
    moving blk_add_timer() to elv_dequeue_request() fixes the problem;
    however, this two usage models definitely need to be cleaned up in the
    future.
    Signed-off-by: default avatarTejun Heo <tj@kernel.org>
    Signed-off-by: default avatarJens Axboe <jens.axboe@oracle.com>
    2920ebbd
elevator.c 26.8 KB