22c213
From bddf389330e11fb0ce17413c1bfa2264a281ded2 Mon Sep 17 00:00:00 2001
22c213
From: Kevin Wolf <kwolf@redhat.com>
22c213
Date: Mon, 30 Mar 2020 11:19:24 +0100
22c213
Subject: [PATCH 4/4] mirror: Wait only for in-flight operations
22c213
22c213
RH-Author: Kevin Wolf <kwolf@redhat.com>
22c213
Message-id: <20200330111924.22938-3-kwolf@redhat.com>
22c213
Patchwork-id: 94463
22c213
O-Subject: [RHEL-AV-8.2.0 qemu-kvm PATCH 2/2] mirror: Wait only for in-flight operations
22c213
Bugzilla: 1794692
22c213
RH-Acked-by: Maxim Levitsky <mlevitsk@redhat.com>
22c213
RH-Acked-by: Danilo de Paula <ddepaula@redhat.com>
22c213
RH-Acked-by: Max Reitz <mreitz@redhat.com>
22c213
22c213
mirror_wait_for_free_in_flight_slot() just picks a random operation to
22c213
wait for. However, a MirrorOp is already in s->ops_in_flight when
22c213
mirror_co_read() waits for free slots, so if not enough slots are
22c213
immediately available, an operation can end up waiting for itself, or
22c213
two or more operations can wait for each other to complete, which
22c213
results in a hang.
22c213
22c213
Fix this by adding a flag to MirrorOp that tells us if the request is
22c213
already in flight (and therefore occupies slots that it will later
22c213
free), and picking only such operations for waiting.
22c213
22c213
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1794692
22c213
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
22c213
Message-Id: <20200326153628.4869-3-kwolf@redhat.com>
22c213
Reviewed-by: Eric Blake <eblake@redhat.com>
22c213
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
22c213
(cherry picked from commit ce8cabbd17cf738ddfc68384440c38e5dd2fdf97)
22c213
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
22c213
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
22c213
---
22c213
 block/mirror.c | 9 ++++++++-
22c213
 1 file changed, 8 insertions(+), 1 deletion(-)
22c213
22c213
diff --git a/block/mirror.c b/block/mirror.c
22c213
index 8959e42..5e5a521 100644
22c213
--- a/block/mirror.c
22c213
+++ b/block/mirror.c
22c213
@@ -102,6 +102,7 @@ struct MirrorOp {
22c213
 
22c213
     bool is_pseudo_op;
22c213
     bool is_active_write;
22c213
+    bool is_in_flight;
22c213
     CoQueue waiting_requests;
22c213
     Coroutine *co;
22c213
 
22c213
@@ -293,7 +294,9 @@ mirror_wait_for_any_operation(MirrorBlockJob *s, bool active)
22c213
          * caller of this function.  Since there is only one pseudo op
22c213
          * at any given time, we will always find some real operation
22c213
          * to wait on. */
22c213
-        if (!op->is_pseudo_op && op->is_active_write == active) {
22c213
+        if (!op->is_pseudo_op && op->is_in_flight &&
22c213
+            op->is_active_write == active)
22c213
+        {
22c213
             qemu_co_queue_wait(&op->waiting_requests, NULL);
22c213
             return;
22c213
         }
22c213
@@ -367,6 +370,7 @@ static void coroutine_fn mirror_co_read(void *opaque)
22c213
     /* Copy the dirty cluster.  */
22c213
     s->in_flight++;
22c213
     s->bytes_in_flight += op->bytes;
22c213
+    op->is_in_flight = true;
22c213
     trace_mirror_one_iteration(s, op->offset, op->bytes);
22c213
 
22c213
     ret = bdrv_co_preadv(s->mirror_top_bs->backing, op->offset, op->bytes,
22c213
@@ -382,6 +386,7 @@ static void coroutine_fn mirror_co_zero(void *opaque)
22c213
     op->s->in_flight++;
22c213
     op->s->bytes_in_flight += op->bytes;
22c213
     *op->bytes_handled = op->bytes;
22c213
+    op->is_in_flight = true;
22c213
 
22c213
     ret = blk_co_pwrite_zeroes(op->s->target, op->offset, op->bytes,
22c213
                                op->s->unmap ? BDRV_REQ_MAY_UNMAP : 0);
22c213
@@ -396,6 +401,7 @@ static void coroutine_fn mirror_co_discard(void *opaque)
22c213
     op->s->in_flight++;
22c213
     op->s->bytes_in_flight += op->bytes;
22c213
     *op->bytes_handled = op->bytes;
22c213
+    op->is_in_flight = true;
22c213
 
22c213
     ret = blk_co_pdiscard(op->s->target, op->offset, op->bytes);
22c213
     mirror_write_complete(op, ret);
22c213
@@ -1306,6 +1312,7 @@ static MirrorOp *coroutine_fn active_write_prepare(MirrorBlockJob *s,
22c213
         .offset             = offset,
22c213
         .bytes              = bytes,
22c213
         .is_active_write    = true,
22c213
+        .is_in_flight       = true,
22c213
     };
22c213
     qemu_co_queue_init(&op->waiting_requests);
22c213
     QTAILQ_INSERT_TAIL(&s->ops_in_flight, op, next);
22c213
-- 
22c213
1.8.3.1
22c213