dm rq: take request_queue lock while clearing QUEUE_FLAG_STOPPED
authorMike Snitzer <snitzer@redhat.com>
Thu, 1 Sep 2016 15:59:33 +0000 (11:59 -0400)
committerMike Snitzer <snitzer@redhat.com>
Wed, 14 Sep 2016 17:56:38 +0000 (13:56 -0400)
Every call of queue_flag_clear_unlocked() after block device
initialization has finished is wrong if blk_cleanup_queue() can be
called concurrently.  Convert queue_flag_clear_unlocked() into
queue_flag_clear() and protect it by the block layer queue lock.

Also, factor out dm_mq_start_queue().

Reported-by: Bart Van Assche <bart.vanassche@sandisk.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Cc: stable@vger.kernel.org
drivers/md/dm-rq.c

index 2f605f62e47d6e61dc0f8338c8da81c4031e0e43..bd3ba97d44a236cc0862b227ce1101cf0d28e4d2 100644 (file)
@@ -73,15 +73,24 @@ static void dm_old_start_queue(struct request_queue *q)
        spin_unlock_irqrestore(q->queue_lock, flags);
 }
 
+static void dm_mq_start_queue(struct request_queue *q)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(q->queue_lock, flags);
+       queue_flag_clear(QUEUE_FLAG_STOPPED, q);
+       spin_unlock_irqrestore(q->queue_lock, flags);
+
+       blk_mq_start_stopped_hw_queues(q, true);
+       blk_mq_kick_requeue_list(q);
+}
+
 void dm_start_queue(struct request_queue *q)
 {
        if (!q->mq_ops)
                dm_old_start_queue(q);
-       else {
-               queue_flag_clear_unlocked(QUEUE_FLAG_STOPPED, q);
-               blk_mq_start_stopped_hw_queues(q, true);
-               blk_mq_kick_requeue_list(q);
-       }
+       else
+               dm_mq_start_queue(q);
 }
 
 static void dm_old_stop_queue(struct request_queue *q)