From: Paolo Bonzini <pbonzini@redhat.com>
To: qemu-devel@nongnu.org
Cc: kwolf@redhat.com, jcody@redhat.com, stefanha@redhat.com
Subject: [Qemu-devel] [PATCH 12/20] mirror: support arbitrarily-sized iterations
Date: Wed, 12 Dec 2012 14:46:31 +0100 [thread overview]
Message-ID: <1355319999-30627-13-git-send-email-pbonzini@redhat.com> (raw)
In-Reply-To: <1355319999-30627-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 f9caaea..23f87d2 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -135,7 +135,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);
@@ -147,47 +147,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,
- §or_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 is not enough space for
+ * 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 42068dd..3632efc 100644
--- a/trace-events
+++ b/trace-events
@@ -89,6 +89,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.8.0.1
next prev parent reply other threads:[~2012-12-12 13:47 UTC|newest]
Thread overview: 53+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-12-12 13:46 [Qemu-devel] [PATCH 00/20] Block device mirroring enhancements, 12-12-12 edition Paolo Bonzini
2012-12-12 13:46 ` [Qemu-devel] [PATCH 01/20] host-utils: add ffsl Paolo Bonzini
2012-12-12 23:41 ` Eric Blake
2012-12-12 13:46 ` [Qemu-devel] [PATCH 02/20] add hierarchical bitmap data type and test cases Paolo Bonzini
2012-12-14 0:04 ` Eric Blake
2013-01-11 18:27 ` Stefan Hajnoczi
2012-12-12 13:46 ` [Qemu-devel] [PATCH 03/20] block: implement dirty bitmap using HBitmap Paolo Bonzini
2012-12-14 0:27 ` Eric Blake
2012-12-12 13:46 ` [Qemu-devel] [PATCH 04/20] block: make round_to_clusters public Paolo Bonzini
2012-12-14 20:13 ` Eric Blake
2012-12-12 13:46 ` [Qemu-devel] [PATCH 05/20] mirror: perform COW if the cluster size is bigger than the granularity Paolo Bonzini
2012-12-14 20:21 ` Eric Blake
2012-12-12 13:46 ` [Qemu-devel] [PATCH 06/20] block: return count of dirty sectors, not chunks Paolo Bonzini
2012-12-14 20:49 ` Eric Blake
2012-12-12 13:46 ` [Qemu-devel] [PATCH 07/20] block: allow customizing the granularity of the dirty bitmap Paolo Bonzini
2012-12-14 21:27 ` Eric Blake
2012-12-15 9:11 ` Paolo Bonzini
2012-12-12 13:46 ` [Qemu-devel] [PATCH 08/20] mirror: allow customizing the granularity Paolo Bonzini
2012-12-14 22:01 ` Eric Blake
2013-01-14 11:28 ` Stefan Hajnoczi
2012-12-12 13:46 ` [Qemu-devel] [PATCH 09/20] mirror: switch mirror_iteration to AIO Paolo Bonzini
2012-12-14 22:11 ` Eric Blake
2012-12-15 9:09 ` Paolo Bonzini
2012-12-15 13:05 ` Eric Blake
2012-12-12 13:46 ` [Qemu-devel] [PATCH 10/20] mirror: add buf-size argument to drive-mirror Paolo Bonzini
2012-12-14 22:22 ` Eric Blake
2012-12-15 9:09 ` Paolo Bonzini
2013-01-14 11:41 ` Stefan Hajnoczi
2012-12-12 13:46 ` [Qemu-devel] [PATCH 11/20] mirror: support more than one in-flight AIO operation Paolo Bonzini
2012-12-14 22:32 ` Eric Blake
2013-01-14 12:56 ` Stefan Hajnoczi
2013-01-14 13:28 ` Paolo Bonzini
2012-12-12 13:46 ` Paolo Bonzini [this message]
2012-12-14 22:39 ` [Qemu-devel] [PATCH 12/20] mirror: support arbitrarily-sized iterations Eric Blake
2012-12-12 13:46 ` [Qemu-devel] [PATCH 13/20] oslib: add a wrapper for mmap/munmap Paolo Bonzini
2012-12-14 22:54 ` Eric Blake
2012-12-15 9:06 ` Paolo Bonzini
2012-12-12 13:46 ` [Qemu-devel] [PATCH 14/20] hbitmap: add hbitmap_alloc_with_data and hbitmap_required_size Paolo Bonzini
2012-12-17 17:14 ` Eric Blake
2012-12-17 17:18 ` Paolo Bonzini
2012-12-12 13:46 ` [Qemu-devel] [PATCH 15/20] hbitmap: add hbitmap_copy Paolo Bonzini
2012-12-17 18:25 ` Eric Blake
2012-12-12 13:46 ` [Qemu-devel] [PATCH 16/20] block: split bdrv_enable_dirty_tracking and bdrv_disable_dirty_tracking Paolo Bonzini
2012-12-20 18:26 ` Eric Blake
2012-12-12 13:46 ` [Qemu-devel] [PATCH 17/20] block: support a persistent dirty bitmap Paolo Bonzini
2012-12-20 23:03 ` Eric Blake
2012-12-12 13:46 ` [Qemu-devel] [PATCH 18/20] mirror: add support for " Paolo Bonzini
2012-12-20 23:49 ` Eric Blake
2012-12-12 13:46 ` [Qemu-devel] [PATCH 19/20] block: choose the default dirty bitmap granularity in bdrv_enable_dirty_tracking Paolo Bonzini
2012-12-20 23:53 ` Eric Blake
2012-12-12 13:46 ` [Qemu-devel] [PATCH 20/20] monitor: add commands to start/stop dirty bitmap Paolo Bonzini
2012-12-21 18:30 ` Eric Blake
2013-01-14 13:02 ` [Qemu-devel] [PATCH 00/20] Block device mirroring enhancements, 12-12-12 edition Stefan Hajnoczi
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=1355319999-30627-13-git-send-email-pbonzini@redhat.com \
--to=pbonzini@redhat.com \
--cc=jcody@redhat.com \
--cc=kwolf@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=stefanha@redhat.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).