qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Paolo Bonzini <pbonzini@redhat.com>
To: qemu-devel@nongnu.org
Cc: kwolf@redhat.com, jcody@redhat.com, eblake@redhat.com,
	stefanha@linux.vnet.ibm.com
Subject: [Qemu-devel] [PATCH 47/47] mirror: support arbitrarily-sized iterations
Date: Tue, 24 Jul 2012 13:04:25 +0200	[thread overview]
Message-ID: <1343127865-16608-48-git-send-email-pbonzini@redhat.com> (raw)
In-Reply-To: <1343127865-16608-1-git-send-email-pbonzini@redhat.com>

Yet another optimization is to extend the mirroring iteration to include more
adjacent dirty blocks.  This limits the number of I/O operations and makes
mirroring efficient even with a small granularity.  Most of the infrastructure
is already in place; we only need to put a loop around the computation of
the origin and sector count of the iteration.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 block/mirror.c |  100 ++++++++++++++++++++++++++++++++++++++------------------
 trace-events   |    1 +
 2 files changed, 69 insertions(+), 32 deletions(-)

diff --git a/block/mirror.c b/block/mirror.c
index 93e718f..87d97eb 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -127,7 +127,7 @@ static void coroutine_fn mirror_iteration(MirrorBlockJob *s)
 {
     BlockDriverState *source = s->common.bs;
     int nb_sectors, nb_sectors_chunk, nb_chunks;
-    int64_t end, sector_num, cluster_num, next_sector, hbitmap_next_sector;
+    int64_t end, sector_num, next_cluster, next_sector, hbitmap_next_sector;
     MirrorOp *op;
 
     s->sector_num = hbitmap_iter_next(&s->hbi);
@@ -139,47 +139,83 @@ static void coroutine_fn mirror_iteration(MirrorBlockJob *s)
     }
 
     hbitmap_next_sector = s->sector_num;
+    sector_num = s->sector_num;
+    nb_sectors_chunk = s->granularity >> BDRV_SECTOR_BITS;
+    end = s->common.len >> BDRV_SECTOR_BITS;
 
-    /* If we have no backing file yet in the destination, and the cluster size
-     * is very large, we need to do COW ourselves.  The first time a cluster is
-     * copied, copy it entirely.
+    /* Extend the QEMUIOVector to include all adjacent blocks that will
+     * be copied in this operation.
+     *
+     * We have to do this if we have no backing file yet in the destination,
+     * and the cluster size is very large.  Then we need to do COW ourselves.
+     * The first time a cluster is copied, copy it entirely.  Note that,
+     * because both the granularity and the cluster size are powers of two,
+     * the number of sectors to copy cannot exceed one cluster.
      *
-     * Because both the granularity and the cluster size are powers of two, the
-     * number of sectors to copy cannot exceed one cluster.
+     * We also want to extend the QEMUIOVector to include more adjacent
+     * dirty blocks if possible, to limit the number of I/O operations and
+     * run efficiently even with a small granularity.
      */
-    sector_num = s->sector_num;
-    nb_sectors_chunk = nb_sectors = s->granularity >> BDRV_SECTOR_BITS;
-    cluster_num = sector_num / nb_sectors_chunk;
-    if (s->cow_bitmap && !test_bit(cluster_num, s->cow_bitmap)) {
-        trace_mirror_cow(s, sector_num);
-        bdrv_round_to_clusters(s->target,
-                               sector_num, nb_sectors_chunk,
-                               &sector_num, &nb_sectors);
-
-        /* The rounding may make us copy sectors before the
-         * first dirty one.
-         */
-        cluster_num = sector_num / nb_sectors_chunk;
-    }
+    nb_chunks = 0;
+    nb_sectors = 0;
+    next_sector = sector_num;
+    next_cluster = sector_num / nb_sectors_chunk;
 
     /* Wait for I/O to this cluster (from a previous iteration) to be done.  */
-    while (test_bit(cluster_num, s->in_flight_bitmap)) {
+    while (test_bit(next_cluster, s->in_flight_bitmap)) {
         trace_mirror_yield_in_flight(s, sector_num, s->in_flight);
         qemu_coroutine_yield();
     }
 
-    end = s->common.len >> BDRV_SECTOR_BITS;
-    nb_sectors = MIN(nb_sectors, end - sector_num);
-    nb_chunks = (nb_sectors + nb_sectors_chunk - 1) / nb_sectors_chunk;
-    while (s->buf_free_count < nb_chunks) {
-        trace_mirror_yield_buf_busy(s, nb_chunks, s->in_flight);
-        qemu_coroutine_yield();
-    }
+    do {
+        int added_sectors, added_chunks;
 
-    /* We have enough free space to copy these sectors.  */
-    if (s->cow_bitmap) {
-        bitmap_set(s->cow_bitmap, cluster_num, nb_chunks);
-    }
+        if (!bdrv_get_dirty(source, next_sector) ||
+            test_bit(next_cluster, s->in_flight_bitmap)) {
+            assert(nb_sectors > 0);
+            break;
+        }
+
+        added_sectors = nb_sectors_chunk;
+        if (s->cow_bitmap && !test_bit(next_cluster, s->cow_bitmap)) {
+            bdrv_round_to_clusters(s->target,
+                                   next_sector, added_sectors,
+                                   &next_sector, &added_sectors);
+
+            /* On the first iteration, the rounding may make us copy
+             * sectors before the first dirty one.
+             */
+            if (next_sector < sector_num) {
+                assert(nb_sectors == 0);
+                sector_num = next_sector;
+                next_cluster = next_sector / nb_sectors_chunk;
+            }
+        }
+
+        added_sectors = MIN(added_sectors, end - (sector_num + nb_sectors));
+        added_chunks = (added_sectors + nb_sectors_chunk - 1) / nb_sectors_chunk;
+
+        /* When doing COW, it may happen that there are not enough free
+         * buffers to copy a full cluster.  Wait if that is the case.
+         */
+        while (nb_chunks == 0 && s->buf_free_count < added_chunks) {
+            trace_mirror_yield_buf_busy(s, nb_chunks, s->in_flight);
+            qemu_coroutine_yield();
+        }
+        if (s->buf_free_count < nb_chunks + added_chunks) {
+            trace_mirror_break_buf_busy(s, nb_chunks, s->in_flight);
+            break;
+        }
+
+        /* We have enough free space to copy these sectors.  */
+        if (s->cow_bitmap) {
+            bitmap_set(s->cow_bitmap, next_cluster, added_chunks);
+        }
+        nb_sectors += added_sectors;
+        nb_chunks += added_chunks;
+        next_sector += added_sectors;
+        next_cluster += added_chunks;
+    } while (next_sector < end);
 
     /* Allocate a MirrorOp that is used as an AIO callback.  */
     op = g_slice_new(MirrorOp);
diff --git a/trace-events b/trace-events
index 7ae11e9..cd387fa 100644
--- a/trace-events
+++ b/trace-events
@@ -87,6 +87,7 @@ mirror_iteration_done(void *s, int64_t sector_num, int nb_sectors) "s %p sector_
 mirror_yield(void *s, int64_t cnt, int buf_free_count, int in_flight) "s %p dirty count %"PRId64" free buffers %d in_flight %d"
 mirror_yield_in_flight(void *s, int64_t sector_num, int in_flight) "s %p sector_num %"PRId64" in_flight %d"
 mirror_yield_buf_busy(void *s, int nb_chunks, int in_flight) "s %p requested chunks %d in_flight %d"
+mirror_break_buf_busy(void *s, int nb_chunks, int in_flight) "s %p requested chunks %d in_flight %d"
 
 # blockdev.c
 qmp_block_job_cancel(void *job) "job %p"
-- 
1.7.10.4

  parent reply	other threads:[~2012-07-24 11:07 UTC|newest]

Thread overview: 136+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-07-24 11:03 [Qemu-devel] [PATCH 00/47] Block job improvements for 1.2 Paolo Bonzini
2012-07-24 11:03 ` [Qemu-devel] [PATCH 01/47] qapi: generalize documentation of streaming commands Paolo Bonzini
2012-07-24 11:03 ` [Qemu-devel] [PATCH 02/47] qerror/block: introduce QERR_BLOCK_JOB_NOT_ACTIVE Paolo Bonzini
2012-07-26 15:26   ` Kevin Wolf
2012-07-26 15:41     ` Paolo Bonzini
2012-07-26 16:49       ` Luiz Capitulino
2012-07-26 16:59         ` Paolo Bonzini
2012-07-26 17:02           ` Luiz Capitulino
2012-07-24 11:03 ` [Qemu-devel] [PATCH 03/47] block: move job APIs to separate files Paolo Bonzini
2012-07-26 15:50   ` Kevin Wolf
2012-07-24 11:03 ` [Qemu-devel] [PATCH 04/47] block: add block_job_query Paolo Bonzini
2012-07-30 14:47   ` Kevin Wolf
2012-07-30 15:05     ` Paolo Bonzini
2012-07-31  8:47       ` Kevin Wolf
2012-07-31  8:50         ` Paolo Bonzini
2012-08-02 19:28           ` Jeff Cody
2012-07-24 11:03 ` [Qemu-devel] [PATCH 05/47] block: add support for job pause/resume Paolo Bonzini
2012-07-24 11:03 ` [Qemu-devel] [PATCH 06/47] qmp: add block-job-pause and block-job-resume Paolo Bonzini
2012-08-01  7:42   ` Kevin Wolf
2012-07-24 11:03 ` [Qemu-devel] [PATCH 07/47] qemu-iotests: add test for pausing a streaming operation Paolo Bonzini
2012-07-24 11:03 ` [Qemu-devel] [PATCH 08/47] block: rename block_job_complete to block_job_completed Paolo Bonzini
2012-07-24 11:03 ` [Qemu-devel] [PATCH 09/47] block: rename BlockErrorAction, BlockQMPEventAction Paolo Bonzini
2012-07-24 11:03 ` [Qemu-devel] [PATCH 10/47] block: move BlockdevOnError declaration to QAPI Paolo Bonzini
2012-07-24 11:03 ` [Qemu-devel] [PATCH 11/47] block: reorganize io error code Paolo Bonzini
2012-08-01  9:30   ` Kevin Wolf
2012-08-01  9:46     ` Paolo Bonzini
2012-07-24 11:03 ` [Qemu-devel] [PATCH 12/47] block: sort BlockDeviceIoStatus errors by severity Paolo Bonzini
2012-08-01  9:44   ` Paolo Bonzini
2012-08-01  9:44   ` Kevin Wolf
2012-07-24 11:03 ` [Qemu-devel] [PATCH 13/47] block: introduce block job error Paolo Bonzini
2012-07-25 17:40   ` Eric Blake
2012-08-01 10:14   ` Kevin Wolf
2012-08-01 11:17     ` Paolo Bonzini
2012-08-01 11:49       ` Kevin Wolf
2012-08-01 12:09         ` Paolo Bonzini
2012-08-01 12:23           ` Kevin Wolf
2012-08-01 12:30             ` Paolo Bonzini
2012-08-01 13:09               ` Kevin Wolf
2012-08-01 13:21                 ` Paolo Bonzini
2012-08-01 14:01                   ` Kevin Wolf
2012-08-01 14:34                     ` Paolo Bonzini
2012-08-01 14:59                       ` Kevin Wolf
2012-08-01 15:15                         ` Paolo Bonzini
2012-08-06  9:29                           ` Kevin Wolf
2012-08-06  9:44                             ` Paolo Bonzini
2012-08-06 10:45                               ` Kevin Wolf
2012-08-06 10:58                                 ` Paolo Bonzini
2012-07-24 11:03 ` [Qemu-devel] [PATCH 14/47] stream: add on-error argument Paolo Bonzini
2012-07-31 18:40   ` Eric Blake
2012-08-01 10:29   ` Kevin Wolf
2012-08-01 11:11     ` Paolo Bonzini
2012-08-01 11:45       ` Kevin Wolf
2012-07-24 11:03 ` [Qemu-devel] [PATCH 15/47] blkdebug: process all set_state rules in the old state Paolo Bonzini
2012-07-24 20:06   ` Blue Swirl
2012-07-24 11:03 ` [Qemu-devel] [PATCH 16/47] qemu-iotests: map underscore to dash in QMP argument names Paolo Bonzini
2012-07-24 11:03 ` [Qemu-devel] [PATCH 17/47] qemu-iotests: add tests for streaming error handling Paolo Bonzini
2012-08-01 10:43   ` Kevin Wolf
2012-08-01 11:09     ` Paolo Bonzini
2012-07-24 11:03 ` [Qemu-devel] [PATCH 18/47] block: live snapshot documentation tweaks Paolo Bonzini
2012-07-24 11:03 ` [Qemu-devel] [PATCH 19/47] block: add bdrv_query_info Paolo Bonzini
2012-09-11 13:07   ` Kevin Wolf
2012-09-11 13:12     ` Paolo Bonzini
2012-07-24 11:03 ` [Qemu-devel] [PATCH 20/47] block: add bdrv_query_stats Paolo Bonzini
2012-07-24 11:03 ` [Qemu-devel] [PATCH 21/47] block: add bdrv_ensure_backing_file Paolo Bonzini
2012-09-11 13:32   ` Kevin Wolf
2012-09-11 13:46     ` Paolo Bonzini
2012-09-11 13:58       ` Kevin Wolf
2012-09-11 14:10         ` Paolo Bonzini
2012-09-11 15:38           ` Kevin Wolf
2012-07-24 11:04 ` [Qemu-devel] [PATCH 22/47] block: make device optional in BlockInfo Paolo Bonzini
2012-09-11 13:38   ` Kevin Wolf
2012-09-11 13:49     ` Paolo Bonzini
2012-09-11 14:02       ` Kevin Wolf
2012-09-11 14:14         ` Paolo Bonzini
2012-07-24 11:04 ` [Qemu-devel] [PATCH 23/47] block: add target info to QMP query-blockjobs command Paolo Bonzini
2012-07-24 11:04 ` [Qemu-devel] [PATCH 24/47] block: introduce new dirty bitmap functionality Paolo Bonzini
2012-09-11 14:57   ` Kevin Wolf
2012-09-11 16:17     ` Paolo Bonzini
2012-07-24 11:04 ` [Qemu-devel] [PATCH 25/47] block: add block-job-complete Paolo Bonzini
2012-07-24 11:04 ` [Qemu-devel] [PATCH 26/47] block: introduce BLOCK_JOB_READY event Paolo Bonzini
2012-07-24 11:04 ` [Qemu-devel] [PATCH 27/47] block: introduce mirror job Paolo Bonzini
2012-07-25 23:02   ` Eric Blake
2012-09-13 12:54   ` Kevin Wolf
2012-09-13 14:07     ` Paolo Bonzini
2012-07-24 11:04 ` [Qemu-devel] [PATCH 28/47] qmp: add drive-mirror command Paolo Bonzini
2012-07-26 23:42   ` Eric Blake
2012-07-27  7:04     ` Paolo Bonzini
2012-07-31  9:26   ` Kevin Wolf
2012-07-31  9:33     ` Paolo Bonzini
2012-07-31  9:46       ` Kevin Wolf
2012-07-31 10:02         ` Paolo Bonzini
2012-07-31 10:25           ` Kevin Wolf
2012-07-31 10:51             ` Paolo Bonzini
2012-07-31 11:13               ` Kevin Wolf
2012-07-31 11:25                 ` Paolo Bonzini
2012-07-31 12:17                   ` Kevin Wolf
2012-07-31 12:52                     ` Paolo Bonzini
2012-09-13 13:15   ` Kevin Wolf
2012-09-13 13:24     ` Paolo Bonzini
2012-09-13 13:26       ` Kevin Wolf
2012-09-13 13:38         ` Paolo Bonzini
2012-07-24 11:04 ` [Qemu-devel] [PATCH 29/47] mirror: support querying target file Paolo Bonzini
2012-07-24 11:04 ` [Qemu-devel] [PATCH 30/47] mirror: implement completion Paolo Bonzini
2012-07-24 11:04 ` [Qemu-devel] [PATCH 31/47] qemu-iotests: add mirroring test case Paolo Bonzini
2012-07-26 23:46   ` Eric Blake
2012-07-27  7:04     ` Paolo Bonzini
2012-07-24 11:04 ` [Qemu-devel] [PATCH 32/47] block: forward bdrv_iostatus_reset to block job Paolo Bonzini
2012-07-24 11:04 ` [Qemu-devel] [PATCH 33/47] mirror: add support for on-source-error/on-target-error Paolo Bonzini
2012-07-27 15:26   ` Eric Blake
2012-07-30 13:29     ` Paolo Bonzini
2012-07-24 11:04 ` [Qemu-devel] [PATCH 34/47] qmp: add pull_event function Paolo Bonzini
2012-07-24 11:04 ` [Qemu-devel] [PATCH 35/47] qemu-iotests: add testcases for mirroring on-source-error/on-target-error Paolo Bonzini
2012-07-24 11:04 ` [Qemu-devel] [PATCH 36/47] host-utils: add ffsl and flsl Paolo Bonzini
2012-07-27 16:05   ` Eric Blake
2012-07-30 13:30     ` Paolo Bonzini
2012-07-24 11:04 ` [Qemu-devel] [PATCH 37/47] add hierarchical bitmap data type and test cases Paolo Bonzini
2012-07-28 13:26   ` Eric Blake
2012-07-30 13:39     ` Paolo Bonzini
2012-07-30 14:18       ` Paolo Bonzini
2012-07-24 11:04 ` [Qemu-devel] [PATCH 38/47] block: implement dirty bitmap using HBitmap Paolo Bonzini
2012-07-24 11:04 ` [Qemu-devel] [PATCH 39/47] block: make round_to_clusters public Paolo Bonzini
2012-07-24 11:04 ` [Qemu-devel] [PATCH 40/47] mirror: perform COW if the cluster size is bigger than the granularity Paolo Bonzini
2012-07-24 11:04 ` [Qemu-devel] [PATCH 41/47] block: return count of dirty sectors, not chunks Paolo Bonzini
2012-07-24 11:04 ` [Qemu-devel] [PATCH 42/47] block: allow customizing the granularity of the dirty bitmap Paolo Bonzini
2012-07-24 11:04 ` [Qemu-devel] [PATCH 43/47] mirror: allow customizing the granularity Paolo Bonzini
2012-07-28 13:43   ` Eric Blake
2012-07-30 13:40     ` Paolo Bonzini
2012-07-30 13:53       ` Eric Blake
2012-07-30 14:03         ` Paolo Bonzini
2012-07-24 11:04 ` [Qemu-devel] [PATCH 44/47] mirror: switch mirror_iteration to AIO Paolo Bonzini
2012-07-28 13:46   ` Eric Blake
2012-07-30 13:41     ` Paolo Bonzini
2012-07-24 11:04 ` [Qemu-devel] [PATCH 45/47] mirror: add buf-size argument to drive-mirror Paolo Bonzini
2012-07-24 11:04 ` [Qemu-devel] [PATCH 46/47] mirror: support more than one in-flight AIO operation Paolo Bonzini
2012-07-24 11:04 ` Paolo Bonzini [this message]
2012-07-28 13:51 ` [Qemu-devel] [PATCH 00/47] Block job improvements for 1.2 Eric Blake

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1343127865-16608-48-git-send-email-pbonzini@redhat.com \
    --to=pbonzini@redhat.com \
    --cc=eblake@redhat.com \
    --cc=jcody@redhat.com \
    --cc=kwolf@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@linux.vnet.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).