bf143f
From 192f956f2b0761f270070555f8feb1f0544e5558 Mon Sep 17 00:00:00 2001
bf143f
From: Hanna Reitz <hreitz@redhat.com>
bf143f
Date: Wed, 9 Nov 2022 17:54:48 +0100
bf143f
Subject: [PATCH 01/11] block/mirror: Do not wait for active writes
bf143f
bf143f
RH-Author: Hanna Czenczek <hreitz@redhat.com>
bf143f
RH-MergeRequest: 246: block/mirror: Make active mirror progress even under full load
bf143f
RH-Bugzilla: 2125119
bf143f
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
bf143f
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
bf143f
RH-Acked-by: Stefano Garzarella <sgarzare@redhat.com>
bf143f
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
bf143f
RH-Commit: [1/3] 652d1e55b954f13eaec2c86f58735d4942837e16
bf143f
bf143f
Waiting for all active writes to settle before daring to create a
bf143f
background copying operation means that we will never do background
bf143f
operations while the guest does anything (in write-blocking mode), and
bf143f
therefore cannot converge.  Yes, we also will not diverge, but actually
bf143f
converging would be even nicer.
bf143f
bf143f
It is unclear why we did decide to wait for all active writes to settle
bf143f
before creating a background operation, but it just does not seem
bf143f
necessary.  Active writes will put themselves into the in_flight bitmap
bf143f
and thus properly block actually conflicting background requests.
bf143f
bf143f
It is important for active requests to wait on overlapping background
bf143f
requests, which we do in active_write_prepare().  However, so far it was
bf143f
not documented why it is important.  Add such documentation now, and
bf143f
also to the other call of mirror_wait_on_conflicts(), so that it becomes
bf143f
more clear why and when requests need to actively wait for other
bf143f
requests to settle.
bf143f
bf143f
Another thing to note is that of course we need to ensure that there are
bf143f
no active requests when the job completes, but that is done by virtue of
bf143f
the BDS being drained anyway, so there cannot be any active requests at
bf143f
that point.
bf143f
bf143f
With this change, we will need to explicitly keep track of how many
bf143f
bytes are in flight in active requests so that
bf143f
job_progress_set_remaining() in mirror_run() can set the correct number
bf143f
of remaining bytes.
bf143f
bf143f
Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2123297
bf143f
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
bf143f
Message-Id: <20221109165452.67927-2-hreitz@redhat.com>
bf143f
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
bf143f
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
bf143f
(cherry picked from commit d69a879bdf1aed586478eaa161ee064fe1b92f1a)
bf143f
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
bf143f
---
bf143f
 block/mirror.c | 37 ++++++++++++++++++++++++++++++-------
bf143f
 1 file changed, 30 insertions(+), 7 deletions(-)
bf143f
bf143f
diff --git a/block/mirror.c b/block/mirror.c
bf143f
index efec2c7674..282f428cb7 100644
bf143f
--- a/block/mirror.c
bf143f
+++ b/block/mirror.c
bf143f
@@ -81,6 +81,7 @@ typedef struct MirrorBlockJob {
bf143f
     int max_iov;
bf143f
     bool initial_zeroing_ongoing;
bf143f
     int in_active_write_counter;
bf143f
+    int64_t active_write_bytes_in_flight;
bf143f
     bool prepared;
bf143f
     bool in_drain;
bf143f
 } MirrorBlockJob;
bf143f
@@ -493,6 +494,13 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
bf143f
     }
bf143f
     bdrv_dirty_bitmap_unlock(s->dirty_bitmap);
bf143f
 
bf143f
+    /*
bf143f
+     * Wait for concurrent requests to @offset.  The next loop will limit the
bf143f
+     * copied area based on in_flight_bitmap so we only copy an area that does
bf143f
+     * not overlap with concurrent in-flight requests.  Still, we would like to
bf143f
+     * copy something, so wait until there are at least no more requests to the
bf143f
+     * very beginning of the area.
bf143f
+     */
bf143f
     mirror_wait_on_conflicts(NULL, s, offset, 1);
bf143f
 
bf143f
     job_pause_point(&s->common.job);
bf143f
@@ -993,12 +1001,6 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
bf143f
         int64_t cnt, delta;
bf143f
         bool should_complete;
bf143f
 
bf143f
-        /* Do not start passive operations while there are active
bf143f
-         * writes in progress */
bf143f
-        while (s->in_active_write_counter) {
bf143f
-            mirror_wait_for_any_operation(s, true);
bf143f
-        }
bf143f
-
bf143f
         if (s->ret < 0) {
bf143f
             ret = s->ret;
bf143f
             goto immediate_exit;
bf143f
@@ -1015,7 +1017,9 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
bf143f
         /* cnt is the number of dirty bytes remaining and s->bytes_in_flight is
bf143f
          * the number of bytes currently being processed; together those are
bf143f
          * the current remaining operation length */
bf143f
-        job_progress_set_remaining(&s->common.job, s->bytes_in_flight + cnt);
bf143f
+        job_progress_set_remaining(&s->common.job,
bf143f
+                                   s->bytes_in_flight + cnt +
bf143f
+                                   s->active_write_bytes_in_flight);
bf143f
 
bf143f
         /* Note that even when no rate limit is applied we need to yield
bf143f
          * periodically with no pending I/O so that bdrv_drain_all() returns.
bf143f
@@ -1073,6 +1077,10 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
bf143f
 
bf143f
             s->in_drain = true;
bf143f
             bdrv_drained_begin(bs);
bf143f
+
bf143f
+            /* Must be zero because we are drained */
bf143f
+            assert(s->in_active_write_counter == 0);
bf143f
+
bf143f
             cnt = bdrv_get_dirty_count(s->dirty_bitmap);
bf143f
             if (cnt > 0 || mirror_flush(s) < 0) {
bf143f
                 bdrv_drained_end(bs);
bf143f
@@ -1306,6 +1314,7 @@ do_sync_target_write(MirrorBlockJob *job, MirrorMethod method,
bf143f
     }
bf143f
 
bf143f
     job_progress_increase_remaining(&job->common.job, bytes);
bf143f
+    job->active_write_bytes_in_flight += bytes;
bf143f
 
bf143f
     switch (method) {
bf143f
     case MIRROR_METHOD_COPY:
bf143f
@@ -1327,6 +1336,7 @@ do_sync_target_write(MirrorBlockJob *job, MirrorMethod method,
bf143f
         abort();
bf143f
     }
bf143f
 
bf143f
+    job->active_write_bytes_in_flight -= bytes;
bf143f
     if (ret >= 0) {
bf143f
         job_progress_update(&job->common.job, bytes);
bf143f
     } else {
bf143f
@@ -1375,6 +1385,19 @@ static MirrorOp *coroutine_fn active_write_prepare(MirrorBlockJob *s,
bf143f
 
bf143f
     s->in_active_write_counter++;
bf143f
 
bf143f
+    /*
bf143f
+     * Wait for concurrent requests affecting the area.  If there are already
bf143f
+     * running requests that are copying off now-to-be stale data in the area,
bf143f
+     * we must wait for them to finish before we begin writing fresh data to the
bf143f
+     * target so that the write operations appear in the correct order.
bf143f
+     * Note that background requests (see mirror_iteration()) in contrast only
bf143f
+     * wait for conflicting requests at the start of the dirty area, and then
bf143f
+     * (based on the in_flight_bitmap) truncate the area to copy so it will not
bf143f
+     * conflict with any requests beyond that.  For active writes, however, we
bf143f
+     * cannot truncate that area.  The request from our parent must be blocked
bf143f
+     * until the area is copied in full.  Therefore, we must wait for the whole
bf143f
+     * area to become free of concurrent requests.
bf143f
+     */
bf143f
     mirror_wait_on_conflicts(op, s, offset, bytes);
bf143f
 
bf143f
     bitmap_set(s->in_flight_bitmap, start_chunk, end_chunk - start_chunk);
bf143f
-- 
bf143f
2.37.3
bf143f