]> git.proxmox.com Git - pve-qemu-kvm.git/commitdiff
update backup patches to v5
authorDietmar Maurer <dietmar@proxmox.com>
Thu, 21 Feb 2013 11:29:39 +0000 (12:29 +0100)
committerDietmar Maurer <dietmar@proxmox.com>
Thu, 21 Feb 2013 11:29:39 +0000 (12:29 +0100)
debian/patches/0000-cover-letter.patch
debian/patches/0001-add-documenation-for-new-backup-framework.patch
debian/patches/0002-add-basic-backup-support-to-block-driver.patch
debian/patches/0003-add-backup-related-monitor-commands.patch
debian/patches/0004-introduce-new-vma-archive-format.patch
debian/patches/0005-add-regression-tests-for-backup.patch
debian/patches/0006-add-vm-state-to-backups.patch

index ec5059198f2b8f2870e16c1621c9b14626501d70..2c2f0066f43cbda4f2e44ee89a6c15ef483d7ccc 100644 (file)
@@ -1,7 +1,7 @@
-From de76a5c6306d782733217668f3f55c92aa2be36a Mon Sep 17 00:00:00 2001
+From aa580be154923056a52fdeec429f7e80f04b456e Mon Sep 17 00:00:00 2001
 From: Dietmar Maurer <dietmar@proxmox.com>
-Date: Wed, 20 Feb 2013 10:26:23 +0100
-Subject: [PATCH v4 0/6] Efficient VM backup for qemu
+Date: Thu, 21 Feb 2013 12:22:41 +0100
+Subject: [PATCH v5 0/6] Efficient VM backup for qemu
 
 This series provides a way to efficiently backup VMs.
 
@@ -41,6 +41,16 @@ Changes since v3:
 * add documentation for 'devlist' parameter.
 * rename backup_cancel to backup-cancel
 
+Changes since v4:
+
+* vma create: write verbose output to stderr (not stdout)
+* backup.c: use rwlock instead of sleep, remove backup_in_progress_count
+* BackupDriver: remove '_cb' suffix
+* include cleanups suggested by Stefan
+* use CHAR_BIT instead of magic number '8'
+* implemented bdrv_co_is_allocated_above() - disabled for now because
+  it actually slows down backup speed by 15%
+* extend regression tests to test unallocated regions
 
 Dietmar Maurer (6):
   add documenation for new backup framework
@@ -52,7 +62,7 @@ Dietmar Maurer (6):
 
  Makefile                 |    3 +-
  Makefile.objs            |    1 +
- backup.c                 |  338 +++++++++++++++++
+ backup.c                 |  355 +++++++++++++++++
  backup.h                 |   45 +++
  block.c                  |   71 ++++-
  blockdev.c               |  617 ++++++++++++++++++++++++++++++
@@ -67,12 +77,12 @@ Dietmar Maurer (6):
  qapi-schema.json         |   98 +++++
  qmp-commands.hx          |   27 ++
  tests/Makefile           |   11 +-
- tests/backup-test.c      |  517 +++++++++++++++++++++++++
+ tests/backup-test.c      |  529 ++++++++++++++++++++++++++
  vma-reader.c             |  799 +++++++++++++++++++++++++++++++++++++++
- vma-writer.c             |  932 ++++++++++++++++++++++++++++++++++++++++++++++
- vma.c                    |  559 +++++++++++++++++++++++++++
+ vma-writer.c             |  940 ++++++++++++++++++++++++++++++++++++++++++++++
+ vma.c                    |  561 +++++++++++++++++++++++++++
  vma.h                    |  145 +++++++
- 22 files changed, 4411 insertions(+), 9 deletions(-)
+ 22 files changed, 4450 insertions(+), 9 deletions(-)
  create mode 100644 backup.c
  create mode 100644 backup.h
  create mode 100644 docs/backup.txt
index a811415f862c89f525012ddb0b4426598cbb0f9e..bb3b9bfe07ffb0bfbb1078404363a914aad23760 100644 (file)
@@ -1,7 +1,7 @@
 From 2f0dcd89a0de8b656d33ce6997c09879bd287af7 Mon Sep 17 00:00:00 2001
 From: Dietmar Maurer <dietmar@proxmox.com>
 Date: Tue, 13 Nov 2012 09:24:50 +0100
-Subject: [PATCH v4 1/6] add documenation for new backup framework
+Subject: [PATCH v5 1/6] add documenation for new backup framework
 
 
 Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>
index 8714e9fdbb321e41aeca0beebc07e85453c5ccc0..a178c591a7cd2130fbf356ea377296d19c9e393a 100644 (file)
@@ -1,7 +1,7 @@
-From 940afda26b17f3d5776e4809e6dfce5cee44c102 Mon Sep 17 00:00:00 2001
+From 1d0c6dfc9616c0dd17986cab6744c10cb748de1e Mon Sep 17 00:00:00 2001
 From: Dietmar Maurer <dietmar@proxmox.com>
 Date: Tue, 13 Nov 2012 10:03:52 +0100
-Subject: [PATCH v4 2/6] add basic backup support to block driver
+Subject: [PATCH v5 2/6] add basic backup support to block driver
 
 Function backup_job_create() creates a block job to backup a block device.
 The coroutine is started with backup_job_start().
@@ -16,12 +16,12 @@ Currently backup cluster size is hardcoded to 65536 bytes.
 Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>
 ---
  Makefile.objs            |    1 +
- backup.c                 |  338 ++++++++++++++++++++++++++++++++++++++++++++++
- backup.h                 |   32 +++++
+ backup.c                 |  355 ++++++++++++++++++++++++++++++++++++++++++++++
+ backup.h                 |   3++++
  block.c                  |   71 +++++++++-
  include/block/block.h    |    2 +
  include/block/blockjob.h |   10 ++
- 6 files changed, 448 insertions(+), 6 deletions(-)
+ 6 files changed, 463 insertions(+), 6 deletions(-)
  create mode 100644 backup.c
  create mode 100644 backup.h
 
@@ -39,10 +39,10 @@ index a68cdac..df64f70 100644
  block-obj-y += qemu-coroutine-sleep.o
 diff --git a/backup.c b/backup.c
 new file mode 100644
-index 0000000..c9576d5
+index 0000000..8955e1a
 --- /dev/null
 +++ b/backup.c
-@@ -0,0 +1,338 @@
+@@ -0,0 +1,355 @@
 +/*
 + * QEMU backup
 + *
@@ -68,6 +68,8 @@ index 0000000..c9576d5
 +
 +#define DEBUG_BACKUP 0
 +
++#define USE_ALLOCATION_CHECK 0
++
 +#define DPRINTF(fmt, ...) \
 +    do { if (DEBUG_BACKUP) { printf("backup: " fmt, ## __VA_ARGS__); } } \
 +    while (0)
@@ -78,6 +80,7 @@ index 0000000..c9576d5
 +typedef struct BackupBlockJob {
 +    BlockJob common;
 +    RateLimit limit;
++    CoRwlock rwlock;
 +    uint64_t sectors_read;
 +    unsigned long *bitmap;
 +    int bitmap_size;
@@ -86,7 +89,7 @@ index 0000000..c9576d5
 +    void *opaque;
 +} BackupBlockJob;
 +
-+static int backup_get_bitmap(BackupBlockJob *job, int64_t cluster_num)
++static bool backup_get_bitmap(BackupBlockJob *job, int64_t cluster_num)
 +{
 +    assert(job);
 +    assert(job->bitmap);
@@ -104,7 +107,7 @@ index 0000000..c9576d5
 +}
 +
 +static void backup_set_bitmap(BackupBlockJob *job, int64_t cluster_num,
-+                              int dirty)
++                              bool dirty)
 +{
 +    assert(job);
 +    assert(job->bitmap);
@@ -118,19 +121,13 @@ index 0000000..c9576d5
 +    bit = cluster_num % BITS_PER_LONG;
 +    val = job->bitmap[idx];
 +    if (dirty) {
-+        if (!(val & (1UL << bit))) {
-+            val |= 1UL << bit;
-+        }
++        val |= 1UL << bit;
 +    } else {
-+        if (val & (1UL << bit)) {
-+            val &= ~(1UL << bit);
-+        }
++        val &= ~(1UL << bit);
 +    }
 +    job->bitmap[idx] = val;
 +}
 +
-+static int backup_in_progress_count;
-+
 +static int coroutine_fn backup_do_cow(BlockDriverState *bs,
 +                                      int64_t sector_num, int nb_sectors)
 +{
@@ -144,7 +141,7 @@ index 0000000..c9576d5
 +    void *bounce_buffer = NULL;
 +    int ret = 0;
 +
-+    backup_in_progress_count++;
++    qemu_co_rwlock_rdlock(&job->rwlock);
 +
 +    int64_t start, end;
 +
@@ -152,19 +149,21 @@ index 0000000..c9576d5
 +    end = (sector_num + nb_sectors + BACKUP_BLOCKS_PER_CLUSTER - 1) /
 +        BACKUP_BLOCKS_PER_CLUSTER;
 +
-+    DPRINTF("brdv_co_backup_cow enter %s C%zd %zd %d\n",
++    DPRINTF("brdv_co_backup_cow enter %s C%" PRId64 " %" PRId64 " %d\n",
 +            bdrv_get_device_name(bs), start, sector_num, nb_sectors);
 +
 +    for (; start < end; start++) {
++        bool zero = 0;
++
 +        if (backup_get_bitmap(job, start)) {
-+            DPRINTF("brdv_co_backup_cow skip C%zd\n", start);
++            DPRINTF("brdv_co_backup_cow skip C%" PRId64 "\n", start);
 +            continue; /* already copied */
 +        }
 +
 +        /* immediately set bitmap (avoid coroutine race) */
 +        backup_set_bitmap(job, start, 1);
 +
-+        DPRINTF("brdv_co_backup_cow C%zd\n", start);
++        DPRINTF("brdv_co_backup_cow C%" PRId64 "\n", start);
 +
 +        if (!bounce_buffer) {
 +            iov.iov_len = BACKUP_CLUSTER_SIZE;
@@ -172,24 +171,43 @@ index 0000000..c9576d5
 +            qemu_iovec_init_external(&bounce_qiov, &iov, 1);
 +        }
 +
-+        ret = drv->bdrv_co_readv(bs, start * BACKUP_BLOCKS_PER_CLUSTER,
-+                                 BACKUP_BLOCKS_PER_CLUSTER,
-+                                 &bounce_qiov);
-+
-+        job->sectors_read += BACKUP_BLOCKS_PER_CLUSTER;
-+
++#if USE_ALLOCATION_CHECK
++        int n = 0;
++        ret = bdrv_co_is_allocated_above(bs, NULL,
++                                         start * BACKUP_BLOCKS_PER_CLUSTER,
++                                         BACKUP_BLOCKS_PER_CLUSTER, &n);
 +        if (ret < 0) {
-+            DPRINTF("brdv_co_backup_cow bdrv_read C%zd failed\n", start);
++            DPRINTF("brdv_co_backup_cow is_allocated C%" PRId64 " failed\n",
++                    start);
 +            goto out;
 +        }
 +
-+        ret = job->backup_dump_cb(job->opaque, bs, start, bounce_buffer);
++        zero = (ret == 0) && (n == BACKUP_BLOCKS_PER_CLUSTER);
++
++        if (!zero) {
++#endif
++            ret = drv->bdrv_co_readv(bs, start * BACKUP_BLOCKS_PER_CLUSTER,
++                                     BACKUP_BLOCKS_PER_CLUSTER,
++                                     &bounce_qiov);
++            if (ret < 0) {
++                DPRINTF("brdv_co_backup_cow bdrv_read C%" PRId64 " failed\n",
++                        start);
++                goto out;
++            }
++#if USE_ALLOCATION_CHECK
++        }
++#endif
++        job->sectors_read += BACKUP_BLOCKS_PER_CLUSTER;
++
++        ret = job->backup_dump_cb(job->opaque, bs, start,
++                                  zero ? NULL : bounce_buffer);
 +        if (ret < 0) {
-+            DPRINTF("brdv_co_backup_cow dump_cluster_cb C%zd failed\n", start);
++            DPRINTF("brdv_co_backup_cow dump_cluster_cb C%" PRId64 " failed\n",
++                    start);
 +            goto out;
 +        }
 +
-+        DPRINTF("brdv_co_backup_cow done C%zd\n", start);
++        DPRINTF("brdv_co_backup_cow done C%" PRId64 "\n", start);
 +    }
 +
 +out:
@@ -197,7 +215,7 @@ index 0000000..c9576d5
 +        qemu_vfree(bounce_buffer);
 +    }
 +
-+    backup_in_progress_count--;
++    qemu_co_rwlock_unlock(&job->rwlock);
 +
 +    return ret;
 +}
@@ -247,8 +265,8 @@ index 0000000..c9576d5
 +    end = (bs->total_sectors + BACKUP_BLOCKS_PER_CLUSTER - 1) /
 +        BACKUP_BLOCKS_PER_CLUSTER;
 +
-+    DPRINTF("backup_run start %s %zd %zd\n", bdrv_get_device_name(bs),
-+            start, end);
++    DPRINTF("backup_run start %s %" PRId64 " %" PRId64 "\n",
++            bdrv_get_device_name(bs), start, end);
 +
 +    int ret = 0;
 +
@@ -260,7 +278,7 @@ index 0000000..c9576d5
 +
 +        /* we need to yield so that qemu_aio_flush() returns.
 +         * (without, VM does not reboot)
-+        * Note: use 1000 instead of 0 (0 prioritize this task too much)
++         * Note: use 1000 instead of 0 (0 prioritize this task too much)
 +         */
 +        if (job->common.speed) {
 +            uint64_t delay_ns = ratelimit_calculate_delay(
@@ -280,7 +298,7 @@ index 0000000..c9576d5
 +            continue; /* already copied */
 +        }
 +
-+        DPRINTF("backup_run loop C%zd\n", start);
++        DPRINTF("backup_run loop C%" PRId64 "\n", start);
 +
 +        /**
 +         * This triggers a cluster copy
@@ -295,12 +313,9 @@ index 0000000..c9576d5
 +        job->common.offset += BACKUP_CLUSTER_SIZE;
 +    }
 +
-+    while (backup_in_progress_count > 0) {
-+        DPRINTF("backup_run backup_in_progress_count != 0 (%d)",
-+                backup_in_progress_count);
-+        block_job_sleep_ns(&job->common, rt_clock, 10000);
-+
-+    }
++    /* wait until pending backup_do_cow()calls have completed */
++    qemu_co_rwlock_wrlock(&job->rwlock);
++    qemu_co_rwlock_unlock(&job->rwlock);
 +
 +    DPRINTF("backup_run complete %d\n", ret);
 +    block_job_completed(&job->common, ret);
@@ -365,6 +380,8 @@ index 0000000..c9576d5
 +    BackupBlockJob *job = block_job_create(&backup_job_type, bs, speed,
 +                                           backup_job_cleanup_cb, bs, &errp);
 +
++    qemu_co_rwlock_init(&job->rwlock);
++
 +    job->common.cluster_size = BACKUP_CLUSTER_SIZE;
 +
 +    bitmap_size = bs->total_sectors +
@@ -383,10 +400,10 @@ index 0000000..c9576d5
 +}
 diff --git a/backup.h b/backup.h
 new file mode 100644
-index 0000000..d9395bc
+index 0000000..9b1ea1c
 --- /dev/null
 +++ b/backup.h
-@@ -0,0 +1,32 @@
+@@ -0,0 +1,30 @@
 +/*
 + * QEMU backup related definitions
 + *
@@ -403,8 +420,6 @@ index 0000000..d9395bc
 +#ifndef QEMU_BACKUP_H
 +#define QEMU_BACKUP_H
 +
-+#include <uuid/uuid.h>
-+
 +#define BACKUP_CLUSTER_BITS 16
 +#define BACKUP_CLUSTER_SIZE (1<<BACKUP_CLUSTER_BITS)
 +#define BACKUP_BLOCKS_PER_CLUSTER (BACKUP_CLUSTER_SIZE/BDRV_SECTOR_SIZE)
index ea7a2e468e9c30f21cdbb7f966ba02cc12dbcf68..0a23a45bc941322f364966c1f388a2f60cbebed3 100644 (file)
@@ -1,7 +1,7 @@
-From 982a8ac63f778110ad89b4dc415011166c9dcd8e Mon Sep 17 00:00:00 2001
+From cf9cc8878d3246069da3fdf7ec865b7b983487fe Mon Sep 17 00:00:00 2001
 From: Dietmar Maurer <dietmar@proxmox.com>
 Date: Tue, 13 Nov 2012 11:27:56 +0100
-Subject: [PATCH v4 3/6] add backup related monitor commands
+Subject: [PATCH v5 3/6] add backup related monitor commands
 
 We use a generic BackupDriver struct to encapsulate all archive format
 related function.
@@ -12,7 +12,7 @@ could move the whole archive format related code out of qemu.
 
 Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>
 ---
- backup.h         |   12 ++
+ backup.h         |   15 ++
  blockdev.c       |  423 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
  hmp-commands.hx  |   31 ++++
  hmp.c            |   63 ++++++++
@@ -20,31 +20,41 @@ Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>
  monitor.c        |    7 +
  qapi-schema.json |   95 ++++++++++++
  qmp-commands.hx  |   27 ++++
- 8 files changed, 661 insertions(+), 0 deletions(-)
+ 8 files changed, 664 insertions(+), 0 deletions(-)
 
 diff --git a/backup.h b/backup.h
-index d9395bc..c8ba153 100644
+index 9b1ea1c..22598a6 100644
 --- a/backup.h
 +++ b/backup.h
-@@ -29,4 +29,16 @@ int backup_job_create(BlockDriverState *bs, BackupDumpFunc *backup_dump_cb,
+@@ -14,6 +14,9 @@
+ #ifndef QEMU_BACKUP_H
+ #define QEMU_BACKUP_H
++#include <uuid/uuid.h>
++#include "block/block.h"
++
+ #define BACKUP_CLUSTER_BITS 16
+ #define BACKUP_CLUSTER_SIZE (1<<BACKUP_CLUSTER_BITS)
+ #define BACKUP_BLOCKS_PER_CLUSTER (BACKUP_CLUSTER_SIZE/BDRV_SECTOR_SIZE)
+@@ -27,4 +30,16 @@ int backup_job_create(BlockDriverState *bs, BackupDumpFunc *backup_dump_cb,
                        BlockDriverCompletionFunc *backup_complete_cb,
                        void *opaque, int64_t speed);
  
 +typedef struct BackupDriver {
 +    const char *format;
-+    void *(*open_cb)(const char *filename, uuid_t uuid, Error **errp);
-+    int (*close_cb)(void *opaque, Error **errp);
-+    int (*register_config_cb)(void *opaque, const char *name, gpointer data,
++    void *(*open)(const char *filename, uuid_t uuid, Error **errp);
++    int (*close)(void *opaque, Error **errp);
++    int (*register_config)(void *opaque, const char *name, gpointer data,
 +                              size_t data_len);
-+    int (*register_stream_cb)(void *opaque, const char *devname, size_t size);
-+    int (*dump_cb)(void *opaque, uint8_t dev_id, int64_t cluster_num,
++    int (*register_stream)(void *opaque, const char *devname, size_t size);
++    int (*dump)(void *opaque, uint8_t dev_id, int64_t cluster_num,
 +                   unsigned char *buf, size_t *zero_bytes);
-+    int (*complete_cb)(void *opaque, uint8_t dev_id, int ret);
++    int (*complete)(void *opaque, uint8_t dev_id, int ret);
 +} BackupDriver;
 +
  #endif /* QEMU_BACKUP_H */
 diff --git a/blockdev.c b/blockdev.c
-index 63e6f1e..c340fde 100644
+index 63e6f1e..84f598d 100644
 --- a/blockdev.c
 +++ b/blockdev.c
 @@ -20,6 +20,7 @@
@@ -97,12 +107,12 @@ index 63e6f1e..c340fde 100644
 +
 +    assert(backup_state.driver);
 +    assert(backup_state.writer);
-+    assert(backup_state.driver->dump_cb);
++    assert(backup_state.driver->dump);
 +
 +    size_t zero_bytes = 0;
-+    int bytes = backup_state.driver->dump_cb(backup_state.writer,
-+                                             bcb->dev_id, cluster_num,
-+                                             buf, &zero_bytes);
++    int bytes = backup_state.driver->dump(backup_state.writer,
++                                          bcb->dev_id, cluster_num,
++                                          buf, &zero_bytes);
 +
 +    if (bytes > 0) {
 +        bcb->transferred += bytes;
@@ -121,7 +131,7 @@ index 63e6f1e..c340fde 100644
 +    if (backup_state.writer && backup_state.driver) {
 +        backup_state.end_time = time(NULL);
 +        Error *local_err = NULL;
-+        backup_state.driver->close_cb(backup_state.writer, &local_err);
++        backup_state.driver->close(backup_state.writer, &local_err);
 +        error_propagate(&backup_state.error, local_err);
 +        backup_state.writer = NULL;
 +    }
@@ -145,12 +155,12 @@ index 63e6f1e..c340fde 100644
 +
 +    assert(backup_state.driver);
 +    assert(backup_state.writer);
-+    assert(backup_state.driver->complete_cb);
-+    assert(backup_state.driver->close_cb);
++    assert(backup_state.driver->complete);
++    assert(backup_state.driver->close);
 +
 +    bcb->completed = true;
 +
-+    backup_state.driver->complete_cb(backup_state.writer, bcb->dev_id, ret);
++    backup_state.driver->complete(backup_state.writer, bcb->dev_id, ret);
 +
 +    if (!backup_state.cancel) {
 +        backup_run_next_job();
@@ -319,7 +329,7 @@ index 63e6f1e..c340fde 100644
 +
 +    uuid_generate(uuid);
 +
-+    writer = driver->open_cb(backup_file, uuid, &local_err);
++    writer = driver->open(backup_file, uuid, &local_err);
 +    if (!writer) {
 +        if (error_is_set(&local_err)) {
 +            error_propagate(errp, local_err);
@@ -337,7 +347,7 @@ index 63e6f1e..c340fde 100644
 +
 +        int64_t size = bdrv_getlength(bcb->bs);
 +        const char *devname = bdrv_get_device_name(bcb->bs);
-+        bcb->dev_id = driver->register_stream_cb(writer, devname, size);
++        bcb->dev_id = driver->register_stream(writer, devname, size);
 +        if (bcb->dev_id <= 0) {
 +            error_set(errp, ERROR_CLASS_GENERIC_ERROR,
 +                      "register_stream failed");
@@ -358,7 +368,7 @@ index 63e6f1e..c340fde 100644
 +        }
 +
 +        const char *basename = g_path_get_basename(config_file);
-+        if (driver->register_config_cb(writer, basename, cdata, clen) < 0) {
++        if (driver->register_config(writer, basename, cdata, clen) < 0) {
 +            error_setg(errp, "register_config failed");
 +            g_free(cdata);
 +            goto err;
@@ -429,7 +439,7 @@ index 63e6f1e..c340fde 100644
 +        unlink(backup_file);
 +        if (driver) {
 +            Error *err = NULL;
-+            driver->close_cb(writer, &err);
++            driver->close(writer, &err);
 +        }
 +    }
 +
index 905c58761088469754ebde009456f03363192eeb..0ff1c13183f6e443ccba913cb09c803afec9528b 100644 (file)
@@ -1,7 +1,7 @@
-From 5476ae43806488e74cd293bbaa17f130aa53d402 Mon Sep 17 00:00:00 2001
+From ec5c25c57d35ea662f70382a074620ef2abd0627 Mon Sep 17 00:00:00 2001
 From: Dietmar Maurer <dietmar@proxmox.com>
 Date: Tue, 13 Nov 2012 11:11:38 +0100
-Subject: [PATCH v4 4/6] introduce new vma archive format
+Subject: [PATCH v5 4/6] introduce new vma archive format
 
 This is a very simple archive format, see docs/specs/vma_spec.txt
 
@@ -9,14 +9,13 @@ Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>
 ---
  Makefile                |    3 +-
  Makefile.objs           |    2 +-
- backup.h                |    1 +
  blockdev.c              |    6 +-
  docs/specs/vma_spec.txt |   24 ++
  vma-reader.c            |  799 ++++++++++++++++++++++++++++++++++++++++
- vma-writer.c            |  932 +++++++++++++++++++++++++++++++++++++++++++++++
- vma.c                   |  559 ++++++++++++++++++++++++++++
+ vma-writer.c            |  940 +++++++++++++++++++++++++++++++++++++++++++++++
+ vma.c                   |  561 ++++++++++++++++++++++++++++
  vma.h                   |  145 ++++++++
9 files changed, 2467 insertions(+), 4 deletions(-)
8 files changed, 2476 insertions(+), 4 deletions(-)
  create mode 100644 docs/specs/vma_spec.txt
  create mode 100644 vma-reader.c
  create mode 100644 vma-writer.c
@@ -57,20 +56,8 @@ index df64f70..91f133b 100644
  
  block-obj-y += qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o
  block-obj-y += qemu-coroutine-sleep.o
-diff --git a/backup.h b/backup.h
-index c8ba153..406f011 100644
---- a/backup.h
-+++ b/backup.h
-@@ -15,6 +15,7 @@
- #define QEMU_BACKUP_H
- #include <uuid/uuid.h>
-+#include "block/block.h"
- #define BACKUP_CLUSTER_BITS 16
- #define BACKUP_CLUSTER_SIZE (1<<BACKUP_CLUSTER_BITS)
 diff --git a/blockdev.c b/blockdev.c
-index c340fde..1cfc780 100644
+index 84f598d..683f7da 100644
 --- a/blockdev.c
 +++ b/blockdev.c
 @@ -21,6 +21,7 @@
@@ -97,7 +84,7 @@ index c340fde..1cfc780 100644
      }
 diff --git a/docs/specs/vma_spec.txt b/docs/specs/vma_spec.txt
 new file mode 100644
-index 0000000..052c629
+index 0000000..9b715f2
 --- /dev/null
 +++ b/docs/specs/vma_spec.txt
 @@ -0,0 +1,24 @@
@@ -114,9 +101,9 @@ index 0000000..052c629
 +cluster in the header to store the following information:
 +
 +* 1 byte dev_id (to identity the drive)
++* 1 byte not used (reserved)
 +* 2 bytes zero indicator (mark zero regions (16x4096))
 +* 4 bytes cluster number
-+* 1 byte not used (reserved)
 +
 +We only store non-zero blocks (such block is 4096 bytes).
 +
@@ -127,7 +114,7 @@ index 0000000..052c629
 +
 diff --git a/vma-reader.c b/vma-reader.c
 new file mode 100644
-index 0000000..7e81847
+index 0000000..6d5a9ba
 --- /dev/null
 +++ b/vma-reader.c
 @@ -0,0 +1,799 @@
@@ -161,7 +148,7 @@ index 0000000..7e81847
 +#include "vma.h"
 +#include "block/block.h"
 +
-+#define BITS_PER_LONG  (sizeof(unsigned long) * 8)
++#define BITS_PER_LONG  (sizeof(unsigned long) * CHAR_BIT)
 +
 +static unsigned char zero_vma_block[VMA_BLOCK_SIZE];
 +
@@ -932,10 +919,10 @@ index 0000000..7e81847
 +
 diff --git a/vma-writer.c b/vma-writer.c
 new file mode 100644
-index 0000000..761d7ca
+index 0000000..c292851
 --- /dev/null
 +++ b/vma-writer.c
-@@ -0,0 +1,932 @@
+@@ -0,0 +1,940 @@
 +/*
 + * VMA: Virtual Machine Archive
 + *
@@ -1678,22 +1665,30 @@ index 0000000..761d7ca
 +
 +    DPRINTF("VMA WRITE %d %zd\n", dev_id, cluster_num);
 +
-+    int i;
-+    int bit = 1;
 +    uint16_t mask = 0;
-+    for (i = 0; i < 16; i++) {
-+        unsigned char *vmablock = buf + (i*VMA_BLOCK_SIZE);
-+        if (!buffer_is_zero(vmablock, VMA_BLOCK_SIZE)) {
-+            mask |= bit;
-+            memcpy(vmaw->outbuf + vmaw->outbuf_pos, vmablock, VMA_BLOCK_SIZE);
-+            vmaw->outbuf_pos += VMA_BLOCK_SIZE;
-+        } else {
-+            DPRINTF("VMA WRITE %zd ZERO BLOCK %d\n", cluster_num, i);
-+            vmaw->stream_info[dev_id].zero_bytes += VMA_BLOCK_SIZE;
-+            *zero_bytes += VMA_BLOCK_SIZE;
-+        }
 +
-+        bit = bit << 1;
++    if (buf) {
++        int i;
++        int bit = 1;
++        for (i = 0; i < 16; i++) {
++            unsigned char *vmablock = buf + (i*VMA_BLOCK_SIZE);
++            if (!buffer_is_zero(vmablock, VMA_BLOCK_SIZE)) {
++                mask |= bit;
++                memcpy(vmaw->outbuf + vmaw->outbuf_pos, vmablock,
++                       VMA_BLOCK_SIZE);
++                vmaw->outbuf_pos += VMA_BLOCK_SIZE;
++            } else {
++                DPRINTF("VMA WRITE %zd ZERO BLOCK %d\n", cluster_num, i);
++                vmaw->stream_info[dev_id].zero_bytes += VMA_BLOCK_SIZE;
++                *zero_bytes += VMA_BLOCK_SIZE;
++            }
++
++            bit = bit << 1;
++        }
++    } else {
++        DPRINTF("VMA WRITE %zd ZERO CLUSTER\n", cluster_num);
++        vmaw->stream_info[dev_id].zero_bytes += VMA_CLUSTER_SIZE;
++        *zero_bytes += VMA_CLUSTER_SIZE;
 +    }
 +
 +    uint64_t block_info = ((uint64_t)mask) << (32+16);
@@ -1860,20 +1855,20 @@ index 0000000..761d7ca
 +
 +const BackupDriver backup_vma_driver = {
 +    .format = "vma",
-+    .open_cb = vma_open_cb,
-+    .close_cb = vma_close_cb,
-+    .register_config_cb = vma_register_config_cb,
-+    .register_stream_cb = vma_register_stream_cb,
-+    .dump_cb = vma_dump_cb,
-+    .complete_cb = vma_complete_cb,
++    .open = vma_open_cb,
++    .close = vma_close_cb,
++    .register_config = vma_register_config_cb,
++    .register_stream = vma_register_stream_cb,
++    .dump = vma_dump_cb,
++    .complete = vma_complete_cb,
 +};
 +
 diff --git a/vma.c b/vma.c
 new file mode 100644
-index 0000000..b2e276c
+index 0000000..d3fe39c
 --- /dev/null
 +++ b/vma.c
-@@ -0,0 +1,559 @@
+@@ -0,0 +1,561 @@
 +/*
 + * VMA: Virtual Machine Archive
 + *
@@ -2370,8 +2365,9 @@ index 0000000..b2e276c
 +            }
 +            percent = (transferred*100)/total;
 +            if (percent != last_percent) {
-+                printf("progress %d%% %zd/%zd %zd\n", percent,
-+                       transferred, total, zero_bytes);
++                fprintf(stderr, "progress %d%% %zd/%zd %zd\n", percent,
++                        transferred, total, zero_bytes);
++                fflush(stderr);
 +
 +                last_percent = percent;
 +            }
@@ -2390,8 +2386,9 @@ index 0000000..b2e276c
 +        for (i = 0; i < 256; i++) {
 +            VmaStreamInfo *si = &vmastat.stream_info[i];
 +            if (si->size) {
-+                printf("image %s: size=%zd zeros=%zd saved=%zd\n", si->devname,
-+                       si->size, si->zero_bytes, si->size - si->zero_bytes);
++                fprintf(stderr, "image %s: size=%zd zeros=%zd saved=%zd\n",
++                        si->devname, si->size, si->zero_bytes,
++                        si->size - si->zero_bytes);
 +            }
 +        }
 +    }
index dbf50f9f42900067bf19c3c47ccf3584afd84858..83d55fac30cd0413e33b1c55beb3859578baaa77 100644 (file)
@@ -1,17 +1,15 @@
-From 4fb44b8d03b764db04e7751a14055cbb06a7791d Mon Sep 17 00:00:00 2001
+From 0c613da24e8de22960e5a9f0f1636d9e2b0bd18d Mon Sep 17 00:00:00 2001
 From: Dietmar Maurer <dietmar@proxmox.com>
 Date: Wed, 14 Nov 2012 09:57:04 +0100
-Subject: [PATCH v4 5/6] add regression tests for backup
+Subject: [PATCH v5 5/6] add regression tests for backup
 
 Simple regression tests using vma-reader and vma-writer.
 
-Note: the call to g_thread_init() solves problems with g_slice_alloc() - without that call we get arbitrary crashes.
-
 Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>
 ---
  tests/Makefile      |   11 +-
- tests/backup-test.c |  517 +++++++++++++++++++++++++++++++++++++++++++++++++++
- 2 files changed, 526 insertions(+), 2 deletions(-)
+ tests/backup-test.c |  529 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 538 insertions(+), 2 deletions(-)
  create mode 100644 tests/backup-test.c
 
 diff --git a/tests/Makefile b/tests/Makefile
@@ -54,14 +52,14 @@ index 567e36e..136be84 100644
  -include $(wildcard tests/*.d)
 diff --git a/tests/backup-test.c b/tests/backup-test.c
 new file mode 100644
-index 0000000..5ff6f1d
+index 0000000..039ac1d
 --- /dev/null
 +++ b/tests/backup-test.c
-@@ -0,0 +1,517 @@
+@@ -0,0 +1,529 @@
 +/*
 + * QEMU backup test suit
 + *
-+ * Copyright (C) Proxmox Server Solutions
++ * Copyright (C) 2013 Proxmox Server Solutions
 + *
 + * Authors:
 + *  Dietmar Maurer (dietmar@proxmox.com)
@@ -69,9 +67,6 @@ index 0000000..5ff6f1d
 + * This work is licensed under the terms of the GNU GPL, version 2.  See
 + * the COPYING file in the top-level directory.
 + *
-+ * Fixme: running 'backup-test -l' trigger a bug in g_slice_alloc()
-+ * Note: 'G_SLICE=always-malloc ./tests/backup-test -l' works
-+ *
 + */
 +
 +#include <sys/time.h>
@@ -116,7 +111,7 @@ index 0000000..5ff6f1d
 +{
 +    BackupCB *bcb = opaque;
 +
-+    DPRINTF("backup_dump_cb C%zd %d\n", cluster_num, bcb->dev_id);
++    DPRINTF("backup_dump_cb C%" PRId64 " %d\n", cluster_num, bcb->dev_id);
 +
 +    size_t zb = 0;
 +    if (vma_writer_write(bcb->vmaw, bcb->dev_id, cluster_num, buf, &zb) < 0) {
@@ -150,26 +145,27 @@ index 0000000..5ff6f1d
 +{
 +    int ret;
 +
-+    DPRINTF("write_sec_pattern_cd %zd\n", offset);
++    DPRINTF("write_sec_pattern_cd %" PRId64 "\n", offset);
 +
 +    if (offset & 0x1ff) {
-+        g_error("write_sec_pattern_cd offset %zd is not sector aligned\n",
-+                offset);
++        g_error("write_sec_pattern_cd offset %" PRId64
++                " is not sector aligned\n", offset);
 +    }
 +
 +    ret = bdrv_write(bs, offset >> 9, buf_sec_pattern_cd, 1);
 +    if (ret < 0) {
-+        g_error("write_sec_pattern_cd %zd failed", offset);
++        g_error("write_sec_pattern_cd %" PRId64 " failed", offset);
 +    }
 +
 +}
 +
 +static void read_sec(BlockDriverState *bs, int64_t offset, unsigned char *buf)
 +{
-+    DPRINTF("read_sec C%zd start %zd\n", offset>>VMA_CLUSTER_BITS, offset);
++    DPRINTF("read_sec C%" PRId64 " start %" PRId64 "\n",
++            offset>>VMA_CLUSTER_BITS, offset);
 +
 +    if (offset & 0x1ff) {
-+        g_error("read_sec offset %zd is not sector aligned\n", offset);
++        g_error("read_sec offset %" PRId64 " is not sector aligned\n", offset);
 +    }
 +
 +    if (bdrv_read(bs, offset >> 9, buf, 1) < 0) {
@@ -281,6 +277,12 @@ index 0000000..5ff6f1d
 +        data = 0;  /* add zero region for testing */
 +    }
 +
++
++    if (sector_num >= 20*BACKUP_BLOCKS_PER_CLUSTER &&
++        sector_num <= 23*BACKUP_BLOCKS_PER_CLUSTER) {
++        data = 0;  /* another zero region for testing unallocated regions */
++    }
++
 +    for (i = 0; i < (512/sizeof(int64_t)); i++) {
 +        i64buf[i] = data;
 +    }
@@ -335,7 +337,7 @@ index 0000000..5ff6f1d
 +        }
 +        fill_test_sector(buf2, i);
 +        if (bcmp(buf, buf2, sizeof(buf))) {
-+            g_error("data is different at sector %zd", i);
++            g_error("data is different at sector %" PRId64, i);
 +        }
 +    }
 +
@@ -355,11 +357,16 @@ index 0000000..5ff6f1d
 +    int64_t buf[512/sizeof(int64_t)];
 +
 +    for (i = 0; i < sectors; i++) {
++        if (i >= 20*BACKUP_BLOCKS_PER_CLUSTER &&
++            i <= 23*BACKUP_BLOCKS_PER_CLUSTER) {
++            continue; /* create a hole */
++        }
++
 +        fill_test_sector(buf, i);
 +
-+         int res = 0;
++        int res = 0;
 +        while (1) {
-+            res = write(fd, buf, sizeof(buf));
++            res = pwrite(fd, buf, sizeof(buf), i*512);
 +            if (!(res < 0 && errno == EINTR)) {
 +                break;
 +            }
@@ -479,7 +486,7 @@ index 0000000..5ff6f1d
 +
 +    VmaStatus vmastat;
 +    vma_writer_get_status(vmaw, &vmastat);
-+    DPRINTF("statistic %zd %zd\n", vmastat.stream_info[1].size,
++    DPRINTF("statistic %" PRId64 " %" PRId64 "\n", vmastat.stream_info[1].size,
 +            vmastat.stream_info[1].transferred);
 +    assert(vmastat.stream_info[1].size == vmastat.stream_info[1].transferred);
 +
@@ -517,6 +524,9 @@ index 0000000..5ff6f1d
 +{
 +    int c;
 +
++    /* Note: GLib needs to be running in multithreaded mode in order
++     * for the GSlice allocator to be thread-safe
++     */
 +    g_thread_init(NULL);
 +
 +    for (;;) {
index 530412a35b7d9457930e9cedfe989d83e0dc5f0c..dfed9151fc096af112f53b0a44205aaa3d499b45 100644 (file)
@@ -1,7 +1,7 @@
-From de76a5c6306d782733217668f3f55c92aa2be36a Mon Sep 17 00:00:00 2001
+From aa580be154923056a52fdeec429f7e80f04b456e Mon Sep 17 00:00:00 2001
 From: Dietmar Maurer <dietmar@proxmox.com>
 Date: Thu, 29 Nov 2012 10:46:49 +0100
-Subject: [PATCH v4 6/6] add vm state to backups
+Subject: [PATCH v5 6/6] add vm state to backups
 
 
 Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>
@@ -12,7 +12,7 @@ Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>
  3 files changed, 200 insertions(+), 4 deletions(-)
 
 diff --git a/blockdev.c b/blockdev.c
-index 1cfc780..1b81824 100644
+index 683f7da..dd20631 100644
 --- a/blockdev.c
 +++ b/blockdev.c
 @@ -22,6 +22,8 @@
@@ -50,7 +50,7 @@ index 1cfc780..1b81824 100644
 +        memset(backup_state.buf + backup_state.buf_index, 0,
 +               BACKUP_CLUSTER_SIZE - backup_state.buf_index);
 +    }
-+    int bytes = backup_state.driver->dump_cb(
++    int bytes = backup_state.driver->dump(
 +        backup_state.writer, backup_state.vmstate_dev_id,
 +        backup_state.buf_cluster_num,
 +        backup_state.buf, &zero_bytes);
@@ -64,7 +64,7 @@ index 1cfc780..1b81824 100644
 +{
 +    assert(backup_state.driver);
 +    assert(backup_state.writer);
-+    assert(backup_state.driver->dump_cb);
++    assert(backup_state.driver->dump);
 +
 +    /* Note: our backup driver expects to get whole clusters (64KB) */
 +
@@ -79,7 +79,7 @@ index 1cfc780..1b81824 100644
 +        size -= l;
 +        if (backup_state.buf_index == BACKUP_CLUSTER_SIZE) {
 +            size_t zero_bytes = 0;
-+            int bytes = backup_state.driver->dump_cb(
++            int bytes = backup_state.driver->dump(
 +                backup_state.writer, backup_state.vmstate_dev_id,
 +                backup_state.buf_cluster_num++,
 +                backup_state.buf, &zero_bytes);
@@ -162,9 +162,9 @@ index 1cfc780..1b81824 100644
 +                               "backup_start_savevm: qemu_fclose failed");
 +                    goto abort;
 +                }
-+                if (backup_state.driver->complete_cb(backup_state.writer,
++                if (backup_state.driver->complete(backup_state.writer,
 +                    backup_state.vmstate_dev_id, 0) < 0) {
-+                    err = g_strdup("backup_start_savevm: complete_cb failed");
++                    err = g_strdup("backup_start_savevm: complete failed");
 +                    goto abort;
 +                }
 +                backup_run_next_job();
@@ -183,7 +183,7 @@ index 1cfc780..1b81824 100644
 +    backup_state.end_time = time(NULL);
 +
 +    Error *local_err = NULL;
-+    backup_state.driver->close_cb(backup_state.writer, &local_err);
++    backup_state.driver->close(backup_state.writer, &local_err);
 +    backup_state.writer = NULL;
 +
 +    error_propagate(&backup_state.error, local_err);
@@ -229,7 +229,7 @@ index 1cfc780..1b81824 100644
 +         * not know that size in advance).
 +         */
 +        size_t ramsize = ram_bytes_total();
-+        vmstate_dev_id = driver->register_stream_cb(writer, "vmstate", ramsize);
++        vmstate_dev_id = driver->register_stream(writer, "vmstate", ramsize);
 +        if (vmstate_dev_id <= 0) {
 +            error_setg(errp, "register vmstate stream failed");
 +            goto err;