From b3ac481187a3e4b0e6fca72c5100883cfd5079dd Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Mon, 14 Apr 2014 11:12:49 +0200 Subject: [PATCH] allow the creation of vma files without data streams --- .../backup-vma-allow-empty-backups.patch | 252 ++++++++++++++++++ debian/patches/series | 1 + 2 files changed, 253 insertions(+) create mode 100644 debian/patches/backup-vma-allow-empty-backups.patch diff --git a/debian/patches/backup-vma-allow-empty-backups.patch b/debian/patches/backup-vma-allow-empty-backups.patch new file mode 100644 index 0000000..e4c7e65 --- /dev/null +++ b/debian/patches/backup-vma-allow-empty-backups.patch @@ -0,0 +1,252 @@ +This patch allows the creation of vma files without data streams. + +Such files only contain configuration data. This is useful if a +user set backup=no to all VM disks. + +Index: new/vma-reader.c +=================================================================== +--- new.orig/vma-reader.c 2014-04-14 08:40:47.000000000 +0200 ++++ new/vma-reader.c 2014-04-14 10:33:00.000000000 +0200 +@@ -334,11 +334,6 @@ + } + } + +- if (!count) { +- error_setg(errp, "vma does not contain data"); +- return -1; +- } +- + for (i = 0; i < VMA_MAX_CONFIGS; i++) { + uint32_t name_ptr = GUINT32_FROM_BE(h->config_names[i]); + uint32_t data_ptr = GUINT32_FROM_BE(h->config_data[i]); +@@ -830,16 +825,20 @@ + } + + if (verbose) { +- printf("total bytes read %zd, sparse bytes %zd (%.3g%%)\n", +- vmar->clusters_read*VMA_CLUSTER_SIZE, +- vmar->zero_cluster_data, +- (double)(100.0*vmar->zero_cluster_data)/ +- (vmar->clusters_read*VMA_CLUSTER_SIZE)); +- +- int64_t datasize = vmar->clusters_read*VMA_CLUSTER_SIZE-vmar->zero_cluster_data; +- if (datasize) { // this does not make sense for empty files +- printf("space reduction due to 4K zero bocks %.3g%%\n", +- (double)(100.0*vmar->partial_zero_cluster_data) / datasize); ++ if (vmar->clusters_read) { ++ printf("total bytes read %zd, sparse bytes %zd (%.3g%%)\n", ++ vmar->clusters_read*VMA_CLUSTER_SIZE, ++ vmar->zero_cluster_data, ++ (double)(100.0*vmar->zero_cluster_data)/ ++ (vmar->clusters_read*VMA_CLUSTER_SIZE)); ++ ++ int64_t datasize = vmar->clusters_read*VMA_CLUSTER_SIZE-vmar->zero_cluster_data; ++ if (datasize) { // this does not make sense for empty files ++ printf("space reduction due to 4K zero bocks %.3g%%\n", ++ (double)(100.0*vmar->partial_zero_cluster_data) / datasize); ++ } ++ } else { ++ printf("vma archive contains no image data\n"); + } + } + return ret; +Index: new/vma-writer.c +=================================================================== +--- new.orig/vma-writer.c 2014-04-14 08:40:47.000000000 +0200 ++++ new/vma-writer.c 2014-04-14 11:00:45.000000000 +0200 +@@ -257,7 +257,7 @@ + } + + vmaw->co_writer = NULL; +- ++ + return (done == bytes) ? bytes : -1; + } + +@@ -381,10 +381,6 @@ + time_t ctime = time(NULL); + head->ctime = GUINT64_TO_BE(ctime); + +- if (!vmaw->stream_count) { +- return -1; +- } +- + for (i = 0; i < VMA_MAX_CONFIGS; i++) { + head->config_names[i] = GUINT32_TO_BE(vmaw->config_names[i]); + head->config_data[i] = GUINT32_TO_BE(vmaw->config_data[i]); +@@ -501,6 +497,23 @@ + return open_drives; + } + ++ ++/** ++ * You need to call this if the vma archive does not contain ++ * any data stream. ++ */ ++int coroutine_fn ++vma_writer_flush_output(VmaWriter *vmaw) ++{ ++ qemu_co_mutex_lock(&vmaw->flush_lock); ++ int ret = vma_writer_flush(vmaw); ++ qemu_co_mutex_unlock(&vmaw->flush_lock); ++ if (ret < 0) { ++ vma_writer_set_error(vmaw, "vma_writer_flush_header failed"); ++ } ++ return ret; ++} ++ + /** + * all jobs should call this when there is no more data + * Returns: number of remaining stream (0 ==> finished) +@@ -528,12 +541,7 @@ + + if (open_drives <= 0) { + DPRINTF("vma_writer_set_status all drives completed\n"); +- qemu_co_mutex_lock(&vmaw->flush_lock); +- int ret = vma_writer_flush(vmaw); +- qemu_co_mutex_unlock(&vmaw->flush_lock); +- if (ret < 0) { +- vma_writer_set_error(vmaw, "vma_writer_close_stream: flush failed"); +- } ++ vma_writer_flush_output(vmaw); + } + + return open_drives; +Index: new/vma.c +=================================================================== +--- new.orig/vma.c 2014-04-14 08:40:47.000000000 +0200 ++++ new/vma.c 2014-04-14 10:50:24.000000000 +0200 +@@ -33,7 +33,7 @@ + "\n" + "vma list \n" + "vma config [-c config]\n" +- "vma create [-c config] pathname ...\n" ++ "vma create [-c config] pathname ...\n" + "vma extract [-r ] \n" + "vma verify [-v]\n" + ; +@@ -401,6 +401,18 @@ + + #define BACKUP_SECTORS_PER_CLUSTER (VMA_CLUSTER_SIZE / BDRV_SECTOR_SIZE) + ++static void coroutine_fn backup_run_empty(void *opaque) ++{ ++ VmaWriter *vmaw = (VmaWriter *)opaque; ++ ++ vma_writer_flush_output(vmaw); ++ ++ Error *err = NULL; ++ if (vma_writer_close(vmaw, &err) != 0) { ++ g_warning("vma_writer_close failed %s", error_get_pretty(err)); ++ } ++} ++ + static void coroutine_fn backup_run(void *opaque) + { + BackupJob *job = (BackupJob *)opaque; +@@ -474,8 +486,8 @@ + } + + +- /* make sure we have archive name and at least one path */ +- if ((optind + 2) > argc) { ++ /* make sure we an archive name */ ++ if ((optind + 1) > argc) { + help(); + } + +@@ -510,11 +522,11 @@ + l = g_list_next(l); + } + +- int ind = 0; ++ int devcount = 0; + while (optind < argc) { + const char *path = argv[optind++]; + char *devname = NULL; +- path = extract_devname(path, &devname, ind++); ++ path = extract_devname(path, &devname, devcount++); + + BlockDriver *drv = NULL; + BlockDriverState *bs = bdrv_new(devname); +@@ -546,37 +558,42 @@ + int percent = 0; + int last_percent = -1; + +- while (1) { +- main_loop_wait(false); +- vma_writer_get_status(vmaw, &vmastat); +- +- if (verbose) { +- +- uint64_t total = 0; +- uint64_t transferred = 0; +- uint64_t zero_bytes = 0; +- +- int i; +- for (i = 0; i < 256; i++) { +- if (vmastat.stream_info[i].size) { +- total += vmastat.stream_info[i].size; +- transferred += vmastat.stream_info[i].transferred; +- zero_bytes += vmastat.stream_info[i].zero_bytes; ++ if (devcount) { ++ while (1) { ++ main_loop_wait(false); ++ vma_writer_get_status(vmaw, &vmastat); ++ ++ if (verbose) { ++ ++ uint64_t total = 0; ++ uint64_t transferred = 0; ++ uint64_t zero_bytes = 0; ++ ++ int i; ++ for (i = 0; i < 256; i++) { ++ if (vmastat.stream_info[i].size) { ++ total += vmastat.stream_info[i].size; ++ transferred += vmastat.stream_info[i].transferred; ++ zero_bytes += vmastat.stream_info[i].zero_bytes; ++ } + } +- } +- percent = (transferred*100)/total; +- if (percent != last_percent) { +- fprintf(stderr, "progress %d%% %zd/%zd %zd\n", percent, +- transferred, total, zero_bytes); +- fflush(stderr); ++ percent = (transferred*100)/total; ++ if (percent != last_percent) { ++ fprintf(stderr, "progress %d%% %zd/%zd %zd\n", percent, ++ transferred, total, zero_bytes); ++ fflush(stderr); + +- last_percent = percent; ++ last_percent = percent; ++ } + } +- } + +- if (vmastat.closed) { +- break; ++ if (vmastat.closed) { ++ break; ++ } + } ++ } else { ++ Coroutine *co = qemu_coroutine_create(backup_run_empty); ++ qemu_coroutine_enter(co, vmaw); + } + + bdrv_drain_all(); +Index: new/vma.h +=================================================================== +--- new.orig/vma.h 2014-04-14 08:40:47.000000000 +0200 ++++ new/vma.h 2014-04-14 10:50:00.000000000 +0200 +@@ -128,6 +128,7 @@ + size_t *zero_bytes); + + int coroutine_fn vma_writer_close_stream(VmaWriter *vmaw, uint8_t dev_id); ++int coroutine_fn vma_writer_flush_output(VmaWriter *vmaw); + + int vma_writer_get_status(VmaWriter *vmaw, VmaStatus *status); + void vma_writer_set_error(VmaWriter *vmaw, const char *fmt, ...); diff --git a/debian/patches/series b/debian/patches/series index c3080e7..a7609e9 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -24,3 +24,4 @@ backup-vma-correctly-propagate-error.patch backup-vma-remove-async-queue.patch internal-snapshot-async.patch disable-efi-enable-pxe-roms.patch +backup-vma-allow-empty-backups.patch -- 2.39.2