block: queue lock must be acquired when iterating over rls
authorTahsin Erdogan <tahsin@google.com>
Wed, 1 Feb 2017 06:36:50 +0000 (22:36 -0800)
committerJens Axboe <axboe@fb.com>
Wed, 1 Feb 2017 22:31:22 +0000 (15:31 -0700)
blk_set_queue_dying() does not acquire queue lock before it calls
blk_queue_for_each_rl(). This allows a racing blkg_destroy() to
remove blkg->q_node from the linked list and have
blk_queue_for_each_rl() loop infitely over the removed blkg->q_node
list node.

Signed-off-by: Tahsin Erdogan <tahsin@google.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
block/blk-core.c

index 02833ce5664ea4e59209a93ad82ff0d1f62e8f74..b2df55a6525019efc7c0d566da196f7e283e81e3 100644 (file)
@@ -527,12 +527,14 @@ void blk_set_queue_dying(struct request_queue *q)
        else {
                struct request_list *rl;
 
+               spin_lock_irq(q->queue_lock);
                blk_queue_for_each_rl(rl, q) {
                        if (rl->rq_pool) {
                                wake_up(&rl->wait[BLK_RW_SYNC]);
                                wake_up(&rl->wait[BLK_RW_ASYNC]);
                        }
                }
+               spin_unlock_irq(q->queue_lock);
        }
 }
 EXPORT_SYMBOL_GPL(blk_set_queue_dying);