-From ff878b16c010752dd46a474329d523cded78a004 Mon Sep 17 00:00:00 2001
+From 5476ae43806488e74cd293bbaa17f130aa53d402 Mon Sep 17 00:00:00 2001
From: Dietmar Maurer <dietmar@proxmox.com>
Date: Tue, 13 Nov 2012 11:11:38 +0100
-Subject: [PATCH v3 4/6] introduce new vma archive format
+Subject: [PATCH v4 4/6] introduce new vma archive format
This is a very simple archive format, see docs/specs/vma_spec.txt
---
Makefile | 3 +-
Makefile.objs | 2 +-
+ backup.h | 1 +
blockdev.c | 6 +-
docs/specs/vma_spec.txt | 24 ++
- vma-reader.c | 772 ++++++++++++++++++++++++++++++++++++++++
- vma-writer.c | 900 +++++++++++++++++++++++++++++++++++++++++++++++
- vma.c | 550 +++++++++++++++++++++++++++++
+ vma-reader.c | 799 ++++++++++++++++++++++++++++++++++++++++
+ vma-writer.c | 932 +++++++++++++++++++++++++++++++++++++++++++++++
+ vma.c | 559 ++++++++++++++++++++++++++++
vma.h | 145 ++++++++
- 8 files changed, 2398 insertions(+), 4 deletions(-)
+ 9 files changed, 2467 insertions(+), 4 deletions(-)
create mode 100644 docs/specs/vma_spec.txt
create mode 100644 vma-reader.c
create mode 100644 vma-writer.c
create mode 100644 vma.h
diff --git a/Makefile b/Makefile
-index 9ecbcbb..30a9268 100644
+index 0d9099a..16f1c25 100644
--- a/Makefile
+++ b/Makefile
-@@ -100,7 +100,7 @@ defconfig:
-
- -include config-all-devices.mak
+@@ -115,7 +115,7 @@ ifeq ($(CONFIG_SMARTCARD_NSS),y)
+ include $(SRC_PATH)/libcacard/Makefile
+ endif
-all: $(DOCS) $(TOOLS) $(HELPERS-y) recurse-all
+all: $(DOCS) $(TOOLS) vma$(EXESUF) $(HELPERS-y) recurse-all
config-host.h: config-host.h-timestamp
config-host.h-timestamp: config-host.mak
-@@ -194,6 +194,7 @@ tools-obj-$(CONFIG_POSIX) += compatfd.o
- qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y) libqemustub.a
- qemu-nbd$(EXESUF): qemu-nbd.o $(tools-obj-y) $(block-obj-y) libqemustub.a
- qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y) libqemustub.a
-+vma$(EXESUF): vma.o vma-writer.o vma-reader.o $(tools-obj-y) $(block-obj-y) libqemustub.a
+@@ -167,6 +167,7 @@ qemu-img.o: qemu-img-cmds.h
+ qemu-img$(EXESUF): qemu-img.o $(block-obj-y) libqemuutil.a libqemustub.a
+ qemu-nbd$(EXESUF): qemu-nbd.o $(block-obj-y) libqemuutil.a libqemustub.a
+ qemu-io$(EXESUF): qemu-io.o cmd.o $(block-obj-y) libqemuutil.a libqemustub.a
++vma$(EXESUF): vma.o vma-writer.o vma-reader.o $(block-obj-y) libqemuutil.a libqemustub.a
qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o
diff --git a/Makefile.objs b/Makefile.objs
-index cb46be5..b5732e2 100644
+index df64f70..91f133b 100644
--- a/Makefile.objs
+++ b/Makefile.objs
-@@ -48,7 +48,7 @@ coroutine-obj-$(CONFIG_WIN32) += coroutine-win32.o
- block-obj-y = iov.o cache-utils.o qemu-option.o module.o async.o
- block-obj-y += nbd.o block.o blockjob.o aes.o qemu-config.o
- block-obj-y += thread-pool.o qemu-progress.o qemu-sockets.o uri.o notify.o
+@@ -13,7 +13,7 @@ block-obj-$(CONFIG_POSIX) += aio-posix.o
+ block-obj-$(CONFIG_WIN32) += aio-win32.o
+ block-obj-y += block/
+ block-obj-y += qapi-types.o qapi-visit.o
-block-obj-y += backup.o
+block-obj-y += vma-writer.o backup.o
- block-obj-y += $(coroutine-obj-y) $(qobject-obj-y) $(version-obj-y)
- block-obj-$(CONFIG_POSIX) += event_notifier-posix.o aio-posix.o
- block-obj-$(CONFIG_WIN32) += event_notifier-win32.o aio-win32.o
+
+ 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 c635d21..f424933 100644
+index c340fde..1cfc780 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -21,6 +21,7 @@
#include "trace.h"
- #include "arch_init.h"
+ #include "sysemu/arch_init.h"
#include "backup.h"
+#include "vma.h"
static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives);
-@@ -1483,10 +1484,11 @@ char *qmp_backup(const char *backupfile, bool has_format, const char *format,
+@@ -1530,10 +1531,11 @@ char *qmp_backup(const char *backup_file, bool has_format, BackupFormat format,
/* Todo: try to auto-detect format based on file name */
- format = has_format ? format : "vma";
+ format = has_format ? format : BACKUP_FORMAT_VMA;
- /* fixme: find driver for specifued format */
const BackupDriver *driver = NULL;
- if (!driver) {
-+ if (strcmp(format, "vma") == 0) {
++ if (format == BACKUP_FORMAT_VMA) {
+ driver = &backup_vma_driver;
+ } else {
- error_set(errp, ERROR_CLASS_GENERIC_ERROR,
- "no backup driver for format '%s'", format);
+ error_set(errp, ERROR_CLASS_GENERIC_ERROR, "unknown backup format");
return NULL;
+ }
diff --git a/docs/specs/vma_spec.txt b/docs/specs/vma_spec.txt
new file mode 100644
index 0000000..052c629
+
diff --git a/vma-reader.c b/vma-reader.c
new file mode 100644
-index 0000000..154c96b
+index 0000000..7e81847
--- /dev/null
+++ b/vma-reader.c
-@@ -0,0 +1,772 @@
+@@ -0,0 +1,799 @@
+/*
+ * VMA: Virtual Machine Archive
+ *
+#include <uuid/uuid.h>
+
+#include "qemu-common.h"
-+#include "qemu_socket.h"
-+#include "qemu-coroutine.h"
-+#include "qemu-aio.h"
++#include "qemu/timer.h"
+#include "qemu/ratelimit.h"
+#include "vma.h"
-+#include "block.h"
++#include "block/block.h"
+
+#define BITS_PER_LONG (sizeof(unsigned long) * 8)
+
+ GList *cdata_list;
+ guint8 vmstate_stream;
+ uint32_t vmstate_clusters;
++ /* to show restore percentage if run with -v */
++ time_t start_time;
++ int64_t cluster_count;
++ int64_t clusters_read;
++ int clusters_read_per;
+};
+
+static guint
+
+ VmaReader *vmar = g_new0(VmaReader, 1);
+
-+ vmar->fd = open(filename, O_RDONLY);
++ if (strcmp(filename, "-") == 0) {
++ vmar->fd = dup(0);
++ } else {
++ vmar->fd = open(filename, O_RDONLY);
++ }
+
+ if (vmar->fd < 0) {
+ error_setg(errp, "can't open file %s - %s\n", filename,
+ vmar->rstate[dev_id].bitmap_size = bitmap_size;
+ vmar->rstate[dev_id].bitmap = g_new0(unsigned long, bitmap_size);
+
++ vmar->cluster_count += size/VMA_CLUSTER_SIZE;
++
+ return 0;
+}
+
+ return 0;
+}
+static int restore_extent(VmaReader *vmar, unsigned char *buf,
-+ int extent_size, int vmstate_fd, Error **errp)
++ int extent_size, int vmstate_fd,
++ bool verbose, Error **errp)
+{
+ assert(vmar);
+ assert(buf);
+
+ for (i = 0; i < VMA_BLOCKS_PER_EXTENT; i++) {
+ uint64_t block_info = GUINT64_FROM_BE(ehead->blockinfo[i]);
-+ uint32_t cluster_num = block_info & 0xffffffff;
-+ uint8_t dev_id = (block_info >> 32) & 0xff;
++ uint64_t cluster_num = block_info & 0xffffffff;
++ uint8_t dev_id = (block_info >> 32) & 0xff;
+ uint16_t mask = block_info >> (32+16);
+ int64_t max_sector;
+
+ }
+
+ if (vma_reader_get_bitmap(rstate, cluster_num)) {
-+ error_setg(errp, "found duplicated cluster %d for stream %s",
++ error_setg(errp, "found duplicated cluster %zd for stream %s",
+ cluster_num, vmar->devinfo[dev_id].devname);
+ return -1;
+ }
+ vmar->vmstate_clusters++;
+ }
+
++ vmar->clusters_read++;
++
++ if (verbose) {
++ time_t duration = time(NULL) - vmar->start_time;
++ int percent = (vmar->clusters_read*100)/vmar->cluster_count;
++ if (percent != vmar->clusters_read_per) {
++ printf("progress %d%% (read %zd bytes, duration %zd sec)\n",
++ percent, vmar->clusters_read*VMA_CLUSTER_SIZE,
++ duration);
++ fflush(stdout);
++ vmar->clusters_read_per = percent;
++ }
++ }
++
+ /* try to write whole clusters to speedup restore */
+ if (mask == 0xffff) {
+ if ((start + VMA_CLUSTER_SIZE) > extent_size) {
+
+ } else {
+
-+ if (rstate->write_zeroes & (end_sector > sector_num)) {
++ if (rstate->write_zeroes && (end_sector > sector_num)) {
+ /* Todo: use bdrv_co_write_zeroes (but that need to
+ * be run inside coroutine?)
+ */
+ return 0;
+}
+
-+int vma_reader_restore(VmaReader *vmar, int vmstate_fd, Error **errp)
++int vma_reader_restore(VmaReader *vmar, int vmstate_fd, bool verbose,
++ Error **errp)
+{
+ assert(vmar);
+ assert(vmar->head_data);
+ unsigned char md5sum[16];
+ VmaHeader *h = (VmaHeader *)vmar->head_data;
+
++ vmar->start_time = time(NULL);
+
+ while (1) {
+ int bytes = full_read(vmar->fd, buf + buf_pos, sizeof(buf) - buf_pos);
+ return -1;
+ }
+
-+ if (restore_extent(vmar, buf, extent_size, vmstate_fd, errp) < 0) {
++ if (restore_extent(vmar, buf, extent_size, vmstate_fd, verbose,
++ errp) < 0) {
+ return -1;
+ }
+
+
diff --git a/vma-writer.c b/vma-writer.c
new file mode 100644
-index 0000000..02d4447
+index 0000000..761d7ca
--- /dev/null
+++ b/vma-writer.c
-@@ -0,0 +1,900 @@
+@@ -0,0 +1,932 @@
+/*
+ * VMA: Virtual Machine Archive
+ *
+#include <uuid/uuid.h>
+
+#include "qemu-common.h"
-+#include "qemu_socket.h"
-+#include "qemu-coroutine.h"
-+#include "qemu-aio.h"
-+#include "qemu/ratelimit.h"
+#include "vma.h"
-+#include "block.h"
++#include "block/block.h"
++#include "monitor/monitor.h"
+
+#define DEBUG_VMA 0
+
+
+typedef struct VmaAIOCB VmaAIOCB;
+struct VmaAIOCB {
-+ VmaWriter *vmaw;
+ unsigned char buffer[VMA_MAX_EXTENT_SIZE];
++ VmaWriter *vmaw;
+ size_t bytes;
+ Coroutine *co;
+};
+ int outbuf_count; /* in VMA_BLOCKS */
+ uint64_t outbuf_block_info[VMA_BLOCKS_PER_EXTENT];
+
-+ VmaAIOCB aiocbs[WRITE_BUFFERS];
++ VmaAIOCB *aiocbs[WRITE_BUFFERS];
+ CoQueue wqueue;
+
+ GChecksum *md5csum;
+ CoMutex writer_lock;
+ CoMutex flush_lock;
+ Coroutine *co_writer;
-+ RateLimit limit;
-+ uint64_t delay_ns;
+
+ /* drive informations */
+ VmaStreamInfo stream_info[256];
+{
+ VmaWriter *vmaw = opaque;
+
-+ qemu_aio_set_fd_handler(vmaw->fd, NULL, NULL, NULL, NULL);
-+
+ DPRINTF("vma_co_continue_write\n");
+ qemu_coroutine_enter(vmaw->co_writer, NULL);
+}
+
++static int vma_co_write_finished(void *opaque)
++{
++ VmaWriter *vmaw = opaque;
++
++ return (vmaw->co_writer != 0);
++}
++
+static ssize_t coroutine_fn
+vma_co_write(VmaWriter *vmaw, const void *buf, size_t bytes)
+{
+
+ DPRINTF("vma_co_write enter %zd\n", bytes);
+
++ assert(vmaw->co_writer == NULL);
++
++ vmaw->co_writer = qemu_coroutine_self();
++
++ qemu_aio_set_fd_handler(vmaw->fd, NULL, vma_co_continue_write,
++ vma_co_write_finished, vmaw);
++
++ DPRINTF("vma_co_write wait until writable\n");
++ qemu_coroutine_yield();
++ DPRINTF("vma_co_write starting %zd\n", bytes);
++
+ while (done < bytes) {
+ ret = write(vmaw->fd, buf + done, bytes - done);
+ if (ret > 0) {
+ } else if (ret < 0) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ DPRINTF("vma_co_write yield %zd\n", done);
-+
-+ vmaw->co_writer = qemu_coroutine_self();
-+ qemu_aio_set_fd_handler(vmaw->fd, NULL, vma_co_continue_write,
-+ NULL, vmaw);
-+
+ qemu_coroutine_yield();
+ DPRINTF("vma_co_write restart %zd\n", done);
+ } else {
+ }
+ }
+
++ qemu_aio_set_fd_handler(vmaw->fd, NULL, NULL, NULL, NULL);
++
++ vmaw->co_writer = NULL;
++
+ qemu_co_mutex_unlock(&vmaw->writer_lock);
+
+ DPRINTF("vma_co_write leave %zd\n", done);
+ int i;
+ VmaAIOCB *cb = NULL;
+ for (i = 0; i < WRITE_BUFFERS; i++) {
-+ if (vmaw->aiocbs[i].bytes) {
-+ cb = &vmaw->aiocbs[i];
++ if (vmaw->aiocbs[i]->bytes) {
++ cb = vmaw->aiocbs[i];
+ DPRINTF("FOUND USED AIO BUFFER %d %zd\n", i,
-+ vmaw->aiocbs[i].bytes);
++ vmaw->aiocbs[i]->bytes);
+ break;
+ }
+ }
+ while (!cb) {
+ int i;
+ for (i = 0; i < WRITE_BUFFERS; i++) {
-+ if (!vmaw->aiocbs[i].bytes) {
-+ cb = &vmaw->aiocbs[i];
++ if (!vmaw->aiocbs[i]->bytes) {
++ cb = vmaw->aiocbs[i];
+ break;
+ }
+ }
+ return bytes;
+}
+
-+VmaWriter *vma_writer_create(const char *filename, uuid_t uuid, int64_t speed,
-+ Error **errp)
++VmaWriter *vma_writer_create(const char *filename, uuid_t uuid, Error **errp)
+{
+ const char *p;
+
+ goto err;
+ }
+ vmaw->fd = fileno(vmaw->cmd);
-+ socket_set_nonblock(vmaw->fd);
++
++ /* try to use O_NONBLOCK and O_DIRECT */
++ fcntl(vmaw->fd, F_SETFL, fcntl(vmaw->fd, F_GETFL)|O_NONBLOCK);
++ fcntl(vmaw->fd, F_SETFL, fcntl(vmaw->fd, F_GETFL)|O_DIRECT);
+
+ } else {
-+ vmaw->fd = open(filename, O_NONBLOCK|O_WRONLY|O_CREAT|O_EXCL, 0644);
++ struct stat st;
++ int oflags;
++ const char *tmp_id_str;
++
++ if ((stat(filename, &st) == 0) && S_ISFIFO(st.st_mode)) {
++ oflags = O_NONBLOCK|O_DIRECT|O_WRONLY;
++ vmaw->fd = qemu_open(filename, oflags, 0644);
++ } else if (strstart(filename, "/dev/fdset/", &tmp_id_str)) {
++ oflags = O_NONBLOCK|O_DIRECT|O_WRONLY;
++ vmaw->fd = qemu_open(filename, oflags, 0644);
++ } else if (strstart(filename, "/dev/fdname/", &tmp_id_str)) {
++ vmaw->fd = monitor_get_fd(cur_mon, tmp_id_str, errp);
++ if (vmaw->fd < 0) {
++ goto err;
++ }
++ /* try to use O_NONBLOCK and O_DIRECT */
++ fcntl(vmaw->fd, F_SETFL, fcntl(vmaw->fd, F_GETFL)|O_NONBLOCK);
++ fcntl(vmaw->fd, F_SETFL, fcntl(vmaw->fd, F_GETFL)|O_DIRECT);
++ } else {
++ oflags = O_NONBLOCK|O_DIRECT|O_WRONLY|O_CREAT|O_EXCL;
++ vmaw->fd = qemu_open(filename, oflags, 0644);
++ }
++
+ if (vmaw->fd < 0) {
+ error_setg(errp, "can't open file %s - %s\n", filename,
+ strerror(errno));
+ }
+ }
+
++ /* we use O_DIRECT, so we need to align IO buffers */
++ int i;
++ for (i = 0; i < WRITE_BUFFERS; i++) {
++ vmaw->aiocbs[i] = qemu_memalign(512, sizeof(VmaAIOCB));
++ memset(vmaw->aiocbs[i], 0, sizeof(VmaAIOCB));
++ }
++
+ vmaw->outbuf_count = 0;
+ vmaw->outbuf_pos = VMA_EXTENT_HEADER_SIZE;
+
+
+ uuid_copy(vmaw->uuid, uuid);
+
-+ if (speed <= 0) {
-+ speed = 10*1024*1024*1024LLU; /* default 10GB/s */
-+ }
-+
-+ ratelimit_set_speed(&vmaw->limit, speed, 100000000ULL /* 0.1 sec */);
-+
+ return vmaw;
+
+err:
+
+static int vma_writer_get_buffer(VmaWriter *vmaw)
+{
++ int ret = 0;
++
++ qemu_co_mutex_lock(&vmaw->flush_lock);
+
+ /* wait until buffer is available */
+ while (vmaw->outbuf_count >= (VMA_BLOCKS_PER_EXTENT - 1)) {
-+ int res = 0;
-+
-+ qemu_co_mutex_lock(&vmaw->flush_lock);
-+ res = vma_writer_flush(vmaw);
-+ qemu_co_mutex_unlock(&vmaw->flush_lock);
-+
-+ if (res < 0) {
++ ret = vma_writer_flush(vmaw);
++ if (ret < 0) {
+ vma_writer_set_error(vmaw, "vma_writer_get_buffer: flush failed");
-+ return -1;
++ break;
+ }
+ }
+
-+ return 0;
++ qemu_co_mutex_unlock(&vmaw->flush_lock);
++
++ return ret;
+}
+
+
+ return -1;
+ }
+
-+ DPRINTF("VMA WRITE %zd\n", cluster_num);
++ 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)) {
-+ 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;
-+ } else {
++ 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;
-+
-+ vmaw->delay_ns = ratelimit_calculate_delay(&vmaw->limit,
-+ VMA_BLOCK_SIZE);
-+ if (vmaw->delay_ns) {
-+ co_sleep_ns(rt_clock, vmaw->delay_ns);
-+ }
++ } 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;
+ uint64_t block_info = ((uint64_t)mask) << (32+16);
+ block_info |= ((uint64_t)dev_id) << 32;
+ block_info |= (cluster_num & 0xffffffff);
-+ vmaw->outbuf_block_info[vmaw->outbuf_count] = block_info;
++ vmaw->outbuf_block_info[vmaw->outbuf_count] = block_info;
+
+ DPRINTF("VMA WRITE MASK %zd %zx\n", cluster_num, block_info);
+
+ g_checksum_free(vmaw->md5csum);
+ }
+
++ for (i = 0; i < WRITE_BUFFERS; i++) {
++ free(vmaw->aiocbs[i]);
++ }
++
+ g_free(vmaw);
+}
+
+ return vma_writer_add_config(vmaw, name, data, data_len);
+}
+
-+static void *vma_open_cb(const char *filename, uuid_t uuid, int64_t speed,
-+ Error **errp)
++static void *vma_open_cb(const char *filename, uuid_t uuid, Error **errp)
+{
-+ return vma_writer_create(filename, uuid, speed, errp);
++ return vma_writer_create(filename, uuid, errp);
+}
+
+const BackupDriver backup_vma_driver = {
+
diff --git a/vma.c b/vma.c
new file mode 100644
-index 0000000..69af80c
+index 0000000..b2e276c
--- /dev/null
+++ b/vma.c
-@@ -0,0 +1,550 @@
+@@ -0,0 +1,559 @@
+/*
+ * VMA: Virtual Machine Archive
+ *
+#include <glib.h>
+
+#include "qemu-common.h"
-+#include "qemu-option.h"
-+#include "qemu-error.h"
-+#include "osdep.h"
-+#include "sysemu.h"
-+#include "block_int.h"
-+#include <stdio.h>
++#include "qemu/error-report.h"
+#include "vma.h"
++#include "block/block.h"
+
+static void help(void)
+{
+
+ VmaHeader *head = vma_reader_get_header(vmar);
+
-+ printf("CTIME: %s", ctime(&head->ctime));
-+
+ GList *l = vma_reader_get_config_data(vmar);
+ while (l && l->data) {
+ VmaConfigData *cdata = (VmaConfigData *)l->data;
+ }
+ }
+ }
++ /* ctime is the last entry we print */
++ printf("CTIME: %s", ctime(&head->ctime));
++ fflush(stdout);
+}
+
+static int list_content(int argc, char **argv)
+static int extract_content(int argc, char **argv)
+{
+ int c, ret = 0;
++ int verbose = 0;
+ const char *filename;
+ const char *dirname;
-+ int readmap = 0;
++ const char *readmap = NULL;
+
+ for (;;) {
-+ c = getopt(argc, argv, "hr");
++ c = getopt(argc, argv, "hvr:");
+ if (c == -1) {
+ break;
+ }
+ help();
+ break;
+ case 'r':
-+ readmap = 1;
++ readmap = optarg;
++ break;
++ case 'v':
++ verbose = 1;
+ break;
+ default:
+ help();
+ GError *err = NULL;
+ if (!g_file_set_contents(cfgfn, (gchar *)cdata->data, cdata->len,
+ &err)) {
-+ g_error("Unable to write file: %s", err->message);
++ g_error("unable to write file: %s", err->message);
+ }
+ }
+
+ if (readmap) {
+ print_content(vmar);
+
++ FILE *map = fopen(readmap, "r");
++ if (!map) {
++ g_error("unable to open fifo %s - %s", readmap, strerror(errno));
++ }
++
+ while (1) {
+ char inbuf[8192];
-+ char *line = fgets(inbuf, sizeof(inbuf), stdin);
++ char *line = fgets(inbuf, sizeof(inbuf), map);
+ if (!line || line[0] == '\0' || !strcmp(line, "done\n")) {
+ break;
+ }
+ } else if (line[0] == '1' && line[1] == ':') {
+ path = inbuf + 2;
+ write_zero = true;
-+ } else {
++ } else {
+ g_error("read map failed - parse error ('%s')", inbuf);
+ }
+
+ inbuf);
+ }
+
-+ printf("TEST %s %s\n", path, devname);
-+
+ RestoreMap *map = g_new0(RestoreMap, 1);
+ map->devname = g_strdup(devname);
+ map->path = g_strdup(path);
+ dirname, di->devname);
+ printf("DEVINFO %s %zd\n", devfn, di->size);
+
-+ if (bdrv_img_create(devfn, "raw", NULL, NULL, NULL,
-+ di->size, flags)) {
-+ g_error("can't create file %s", devfn);
++ bdrv_img_create(devfn, "raw", NULL, NULL, NULL, di->size,
++ flags, &errp);
++ if (error_is_set(&errp)) {
++ g_error("can't create file %s: %s", devfn,
++ error_get_pretty(errp));
+ }
+
+ /* Note: we created an empty file above, so there is no
+ write_zero = false;
+ }
+
-+ BlockDriverState *bs = NULL;
-+ if (bdrv_file_open(&bs, devfn, flags)) {
++ BlockDriverState *bs = bdrv_new(di->devname);
++ if (bdrv_open(bs, devfn, flags, NULL)) {
+ g_error("can't open file %s", devfn);
+ }
+ if (vma_reader_register_bs(vmar, i, bs, write_zero, &errp) < 0) {
+ }
+ }
+
-+ if (vma_reader_restore(vmar, vmstate_fd, &errp) < 0) {
++ if (vma_reader_restore(vmar, vmstate_fd, verbose, &errp) < 0) {
+ g_error("restore failed - %s", error_get_pretty(errp));
+ }
+
+ uuid_generate(uuid);
+
+ Error *local_err = NULL;
-+ VmaWriter *vmaw = vma_writer_create(archivename, uuid, 0, &local_err);
++ VmaWriter *vmaw = vma_writer_create(archivename, uuid, &local_err);
+
+ if (vmaw == NULL) {
+ g_error("%s", error_get_pretty(local_err));
+ bcb->vmaw = vmaw;
+ bcb->dev_id = dev_id;
+
-+ if (backup_job_start(bs, backup_dump_cb, backup_complete_cb, bcb) < 0) {
++ if (backup_job_create(bs, backup_dump_cb, backup_complete_cb,
++ bcb, 0) < 0) {
+ unlink(archivename);
+ g_error("backup_job_start failed");
++ } else {
++ backup_job_start(bs, false);
+ }
+ }
+
+}
diff --git a/vma.h b/vma.h
new file mode 100644
-index 0000000..10800a1
+index 0000000..76d0dc8
--- /dev/null
+++ b/vma.h
@@ -0,0 +1,145 @@
+
+extern const BackupDriver backup_vma_driver;
+
-+VmaWriter *vma_writer_create(const char *filename, uuid_t uuid, int64_t speed,
-+ Error **errp);
++VmaWriter *vma_writer_create(const char *filename, uuid_t uuid, Error **errp);
+int vma_writer_close(VmaWriter *vmaw, Error **errp);
+void vma_writer_destroy(VmaWriter *vmaw);
+int vma_writer_add_config(VmaWriter *vmaw, const char *name, gpointer data,
+int vma_reader_register_bs(VmaReader *vmar, guint8 dev_id,
+ BlockDriverState *bs, bool write_zeroes,
+ Error **errp);
-+int vma_reader_restore(VmaReader *vmar, int vmstate_fd, Error **errp);
++int vma_reader_restore(VmaReader *vmar, int vmstate_fd, bool verbose,
++ Error **errp);
+
+#endif /* BACKUP_VMA_H */
--