elevator: Fix a race in elevator switching
authorJianpeng Ma <majianpeng@gmail.com>
Wed, 3 Jul 2013 11:25:24 +0000 (13:25 +0200)
committerJens Axboe <axboe@kernel.dk>
Wed, 3 Jul 2013 11:25:24 +0000 (13:25 +0200)
commitd50235b7bc3ee0a0427984d763ea7534149531b4
treeacf1916e7926c1a0dddbe08db11ca2426a3816cc
parenta6b3f7614ca690e49e934c291f707b0c19312194
elevator: Fix a race in elevator switching

There's a race between elevator switching and normal io operation.
    Because the allocation of struct elevator_queue and struct elevator_data
    don't in a atomic operation.So there are have chance to use NULL
    ->elevator_data.
    For example:
        Thread A:                               Thread B
        blk_queu_bio                            elevator_switch
        spin_lock_irq(q->queue_block)           elevator_alloc
        elv_merge                               elevator_init_fn

    Because call elevator_alloc, it can't hold queue_lock and the
    ->elevator_data is NULL.So at the same time, threadA call elv_merge and
    nedd some info of elevator_data.So the crash happened.

    Move the elevator_alloc into func elevator_init_fn, it make the
    operations in a atomic operation.

    Using the follow method can easy reproduce this bug
    1:dd if=/dev/sdb of=/dev/null
    2:while true;do echo noop > scheduler;echo deadline > scheduler;done

    The test method also use this method.

Signed-off-by: Jianpeng Ma <majianpeng@gmail.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
block/cfq-iosched.c
block/deadline-iosched.c
block/elevator.c
block/noop-iosched.c
include/linux/elevator.h