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