[pve-devel] [PATCH 30/31] PVE-Backup: add backup-dump block driver

Dietmar Maurer dietmar at proxmox.com
Fri Mar 6 12:30:10 CET 2020


- add backup-dump block driver block/backup-dump.c
- move BackupBlockJob declaration from block/backup.c to include/block/block_int.h
- block/backup.c - backup-job-create: also consider source cluster size
- block/io.c - bdrv_do_drained_begin_quiesce: check for coroutine
- job.c: make job_should_pause non-static
---
 block/Makefile.objs       |   1 +
 block/backup-dump.c       | 170 ++++++++++++++++++++++++++++++++++++++
 block/backup.c            |  23 ++----
 block/io.c                |   8 +-
 include/block/block_int.h |  30 +++++++
 job.c                     |   3 +-
 6 files changed, 215 insertions(+), 20 deletions(-)
 create mode 100644 block/backup-dump.c

diff --git a/block/Makefile.objs b/block/Makefile.objs
index a10ceabf5b..5cd9e40d8d 100644
--- a/block/Makefile.objs
+++ b/block/Makefile.objs
@@ -33,6 +33,7 @@ block-obj-$(CONFIG_RBD) += rbd.o
 block-obj-$(CONFIG_GLUSTERFS) += gluster.o
 block-obj-$(CONFIG_VXHS) += vxhs.o
 block-obj-$(CONFIG_LIBSSH) += ssh.o
+block-obj-y += backup-dump.o
 block-obj-y += accounting.o dirty-bitmap.o
 block-obj-y += write-threshold.o
 block-obj-y += backup.o
diff --git a/block/backup-dump.c b/block/backup-dump.c
new file mode 100644
index 0000000000..ff4ecd4557
--- /dev/null
+++ b/block/backup-dump.c
@@ -0,0 +1,170 @@
+/*
+ * BlockDriver to send backup data stream to a callback function
+ *
+ * Copyright (C) 2020 Proxmox Server Solutions GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qom/object_interfaces.h"
+#include "block/block_int.h"
+
+typedef struct {
+    int             dump_cb_block_size;
+    uint64_t        byte_size;
+    BackupDumpFunc *dump_cb;
+    void           *dump_cb_data;
+} BDRVBackupDumpState;
+
+static int qemu_backup_dump_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
+{
+    BDRVBackupDumpState *s = bs->opaque;
+
+    bdi->cluster_size = s->dump_cb_block_size;
+    bdi->unallocated_blocks_are_zero = true;
+    return 0;
+}
+
+static int qemu_backup_dump_check_perm(
+    BlockDriverState *bs,
+    uint64_t perm,
+    uint64_t shared,
+    Error **errp)
+{
+    /* Nothing to do. */
+    return 0;
+}
+
+static void qemu_backup_dump_set_perm(
+    BlockDriverState *bs,
+    uint64_t perm,
+    uint64_t shared)
+{
+    /* Nothing to do. */
+}
+
+static void qemu_backup_dump_abort_perm_update(BlockDriverState *bs)
+{
+    /* Nothing to do. */
+}
+
+static void qemu_backup_dump_refresh_limits(BlockDriverState *bs, Error **errp)
+{
+    bs->bl.request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O */
+}
+
+static void qemu_backup_dump_close(BlockDriverState *bs)
+{
+    /* Nothing to do. */
+}
+
+static int64_t qemu_backup_dump_getlength(BlockDriverState *bs)
+{
+    BDRVBackupDumpState *s = bs->opaque;
+
+    return s->byte_size;
+}
+
+static coroutine_fn int qemu_backup_dump_co_writev(
+    BlockDriverState *bs,
+    int64_t sector_num,
+    int nb_sectors,
+    QEMUIOVector *qiov,
+    int flags)
+{
+    /* flags can be only values we set in supported_write_flags */
+    assert(flags == 0);
+
+    BDRVBackupDumpState *s = bs->opaque;
+    off_t offset = sector_num * BDRV_SECTOR_SIZE;
+
+    uint64_t written = 0;
+
+    for (int i = 0; i < qiov->niov; ++i) {
+        const struct iovec *v = &qiov->iov[i];
+
+        int rc = s->dump_cb(s->dump_cb_data, offset, v->iov_len, v->iov_base);
+        if (rc < 0) {
+            return rc;
+        }
+
+        if (rc != v->iov_len) {
+            return -EIO;
+        }
+
+        written += v->iov_len;
+        offset += v->iov_len;
+    }
+
+    return written;
+}
+
+static void qemu_backup_dump_child_perm(
+    BlockDriverState *bs,
+    BdrvChild *c,
+    const BdrvChildRole *role,
+    BlockReopenQueue *reopen_queue,
+    uint64_t perm, uint64_t shared,
+    uint64_t *nperm, uint64_t *nshared)
+{
+    *nperm = BLK_PERM_ALL;
+    *nshared = BLK_PERM_ALL;
+}
+
+static BlockDriver bdrv_backup_dump_drive = {
+    .format_name                  = "backup-dump-drive",
+    .protocol_name                = "backup-dump",
+    .instance_size                = sizeof(BDRVBackupDumpState),
+
+    .bdrv_close                   = qemu_backup_dump_close,
+    .bdrv_has_zero_init           = bdrv_has_zero_init_1,
+    .bdrv_getlength               = qemu_backup_dump_getlength,
+    .bdrv_get_info                = qemu_backup_dump_get_info,
+
+    .bdrv_co_writev               = qemu_backup_dump_co_writev,
+
+    .bdrv_refresh_limits          = qemu_backup_dump_refresh_limits,
+    .bdrv_check_perm              = qemu_backup_dump_check_perm,
+    .bdrv_set_perm                = qemu_backup_dump_set_perm,
+    .bdrv_abort_perm_update       = qemu_backup_dump_abort_perm_update,
+    .bdrv_child_perm              = qemu_backup_dump_child_perm,
+};
+
+static void bdrv_backup_dump_init(void)
+{
+    bdrv_register(&bdrv_backup_dump_drive);
+}
+
+block_init(bdrv_backup_dump_init);
+
+
+BlockDriverState *bdrv_backuo_dump_create(
+    int dump_cb_block_size,
+    uint64_t byte_size,
+    BackupDumpFunc *dump_cb,
+    void *dump_cb_data,
+    Error **errp)
+{
+    BDRVBackupDumpState *state;
+    BlockDriverState *bs = bdrv_new_open_driver(
+        &bdrv_backup_dump_drive, NULL, BDRV_O_RDWR, errp);
+
+    if (!bs) {
+        // fixme: print error?
+        return NULL;
+    }
+
+    bs->total_sectors = byte_size / 512; //fixme
+    bs->opaque = state = g_new0(BDRVBackupDumpState, 1);
+
+    state->dump_cb_block_size = dump_cb_block_size;
+    state->byte_size = byte_size;
+    state->dump_cb = dump_cb;
+    state->dump_cb_data = dump_cb_data;
+
+    return bs;
+}
diff --git a/block/backup.c b/block/backup.c
index c155081de2..9d23da027f 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -32,24 +32,6 @@
 
 #define BACKUP_CLUSTER_SIZE_DEFAULT (1 << 16)
 
-typedef struct BackupBlockJob {
-    BlockJob common;
-    BlockDriverState *backup_top;
-    BlockDriverState *source_bs;
-
-    BdrvDirtyBitmap *sync_bitmap;
-
-    MirrorSyncMode sync_mode;
-    BitmapSyncMode bitmap_mode;
-    BlockdevOnError on_source_error;
-    BlockdevOnError on_target_error;
-    uint64_t len;
-    uint64_t bytes_read;
-    int64_t cluster_size;
-
-    BlockCopyState *bcs;
-} BackupBlockJob;
-
 static const BlockJobDriver backup_job_driver;
 
 static void backup_progress_bytes_callback(int64_t bytes, void *opaque)
@@ -420,6 +402,11 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
         goto error;
     }
 
+    BlockDriverInfo bdi;
+    if (bdrv_get_info(bs, &bdi) == 0) {
+        cluster_size = MAX(cluster_size, bdi.cluster_size);
+    }
+
     /*
      * If source is in backing chain of target assume that target is going to be
      * used for "image fleecing", i.e. it should represent a kind of snapshot of
diff --git a/block/io.c b/block/io.c
index f75777f5ea..75dea5ae33 100644
--- a/block/io.c
+++ b/block/io.c
@@ -381,7 +381,13 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
 void bdrv_do_drained_begin_quiesce(BlockDriverState *bs,
                                    BdrvChild *parent, bool ignore_bds_parents)
 {
-    assert(!qemu_in_coroutine());
+    // AFAICT this function is just an optimization, but sadly it doesn't play
+    // nice with the PVE backup code (when we're in a coroutine, even in
+    // pvebackup_co_start), so just call the full-blown drain begin instead
+    if (qemu_in_coroutine()) {
+        bdrv_do_drained_begin(bs, false, parent, ignore_bds_parents, false);
+        return;
+    }
 
     /* Stop things in parent-to-child order */
     if (atomic_fetch_inc(&bs->quiesce_counter) == 0) {
diff --git a/include/block/block_int.h b/include/block/block_int.h
index b0d5eb9485..105bffe0f7 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -60,6 +60,36 @@
 
 #define BLOCK_PROBE_BUF_SIZE        512
 
+typedef int BackupDumpFunc(void *opaque, uint64_t offset, uint64_t bytes, const void *buf);
+
+BlockDriverState *bdrv_backuo_dump_create(
+    int dump_cb_block_size,
+    uint64_t byte_size,
+    BackupDumpFunc *dump_cb,
+    void *dump_cb_data,
+    Error **errp);
+
+// Needs to be defined here, since it's used in blockdev.c to detect PVE backup
+// jobs with source_bs
+typedef struct BlockCopyState BlockCopyState;
+typedef struct BackupBlockJob {
+    BlockJob common;
+    BlockDriverState *backup_top;
+    BlockDriverState *source_bs;
+
+    BdrvDirtyBitmap *sync_bitmap;
+
+    MirrorSyncMode sync_mode;
+    BitmapSyncMode bitmap_mode;
+    BlockdevOnError on_source_error;
+    BlockdevOnError on_target_error;
+    uint64_t len;
+    uint64_t bytes_read;
+    int64_t cluster_size;
+
+    BlockCopyState *bcs;
+} BackupBlockJob;
+
 enum BdrvTrackedRequestType {
     BDRV_TRACKED_READ,
     BDRV_TRACKED_WRITE,
diff --git a/job.c b/job.c
index 7554f735e3..b03ef989e2 100644
--- a/job.c
+++ b/job.c
@@ -248,7 +248,8 @@ static bool job_started(Job *job)
     return job->co;
 }
 
-static bool job_should_pause(Job *job)
+bool job_should_pause(Job *job);
+bool job_should_pause(Job *job)
 {
     return job->pause_count > 0;
 }
-- 
2.20.1




More information about the pve-devel mailing list