dm: do not use waitqueue for request-based DM
authorMing Lei <ming.lei@redhat.com>
Wed, 24 Jun 2020 20:00:58 +0000 (16:00 -0400)
committerMike Snitzer <snitzer@redhat.com>
Tue, 7 Jul 2020 16:00:01 +0000 (12:00 -0400)
Given request-based DM now uses blk-mq's blk_mq_queue_inflight() to
determine if outstanding IO has completed (and DM has no control over
the blk-mq state machine used to track outstanding IO) it is unsafe to
wakeup waiter (dm_wait_for_completion) before blk-mq has cleared a
request's state bits (e.g. MQ_RQ_IN_FLIGHT or MQ_RQ_COMPLETE).  As
such dm_wait_for_completion() could be left to wait indefinitely if no
other requests complete.

Fix this by eliminating request-based DM's use of waitqueue to wait
for blk-mq requests to complete in dm_wait_for_completion.

Signed-off-by: Ming Lei <ming.lei@redhat.com>
Depends-on: 3c94d83cb3526 ("blk-mq: change blk_mq_queue_busy() to blk_mq_queue_inflight()")
Cc: stable@vger.kernel.org
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
drivers/md/dm-rq.c
drivers/md/dm.c

index f60c025..85e0daa 100644 (file)
@@ -146,10 +146,6 @@ static void rq_end_stats(struct mapped_device *md, struct request *orig)
  */
 static void rq_completed(struct mapped_device *md)
 {
-       /* nudge anyone waiting on suspend queue */
-       if (unlikely(wq_has_sleeper(&md->wait)))
-               wake_up(&md->wait);
-
        /*
         * dm_put() must be at the end of this function. See the comment above
         */
index e680779..446aff5 100644 (file)
@@ -654,28 +654,6 @@ static void free_tio(struct dm_target_io *tio)
        bio_put(&tio->clone);
 }
 
-static bool md_in_flight_bios(struct mapped_device *md)
-{
-       int cpu;
-       struct hd_struct *part = &dm_disk(md)->part0;
-       long sum = 0;
-
-       for_each_possible_cpu(cpu) {
-               sum += part_stat_local_read_cpu(part, in_flight[0], cpu);
-               sum += part_stat_local_read_cpu(part, in_flight[1], cpu);
-       }
-
-       return sum != 0;
-}
-
-static bool md_in_flight(struct mapped_device *md)
-{
-       if (queue_is_mq(md->queue))
-               return blk_mq_queue_inflight(md->queue);
-       else
-               return md_in_flight_bios(md);
-}
-
 u64 dm_start_time_ns_from_clone(struct bio *bio)
 {
        struct dm_target_io *tio = container_of(bio, struct dm_target_io, clone);
@@ -2470,15 +2448,29 @@ void dm_put(struct mapped_device *md)
 }
 EXPORT_SYMBOL_GPL(dm_put);
 
-static int dm_wait_for_completion(struct mapped_device *md, long task_state)
+static bool md_in_flight_bios(struct mapped_device *md)
+{
+       int cpu;
+       struct hd_struct *part = &dm_disk(md)->part0;
+       long sum = 0;
+
+       for_each_possible_cpu(cpu) {
+               sum += part_stat_local_read_cpu(part, in_flight[0], cpu);
+               sum += part_stat_local_read_cpu(part, in_flight[1], cpu);
+       }
+
+       return sum != 0;
+}
+
+static int dm_wait_for_bios_completion(struct mapped_device *md, long task_state)
 {
        int r = 0;
        DEFINE_WAIT(wait);
 
-       while (1) {
+       while (true) {
                prepare_to_wait(&md->wait, &wait, task_state);
 
-               if (!md_in_flight(md))
+               if (!md_in_flight_bios(md))
                        break;
 
                if (signal_pending_state(task_state, current)) {
@@ -2493,6 +2485,28 @@ static int dm_wait_for_completion(struct mapped_device *md, long task_state)
        return r;
 }
 
+static int dm_wait_for_completion(struct mapped_device *md, long task_state)
+{
+       int r = 0;
+
+       if (!queue_is_mq(md->queue))
+               return dm_wait_for_bios_completion(md, task_state);
+
+       while (true) {
+               if (!blk_mq_queue_inflight(md->queue))
+                       break;
+
+               if (signal_pending_state(task_state, current)) {
+                       r = -EINTR;
+                       break;
+               }
+
+               msleep(5);
+       }
+
+       return r;
+}
+
 /*
  * Process the deferred bios
  */