From 67af0fa481fc1cab8873a4d8393b865f94bda859 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Mon, 7 Aug 2017 09:10:07 +0200 Subject: [PATCH] rebased pve patches --- .../pve/0001-fr-ca-keymap-corrections.patch | 2 +- ...djust-network-script-path-to-etc-kvm.patch | 2 +- ...n-success-on-info-without-snapshots.patch} | 4 +- ...lt.patch => 0004-use-kvm-by-default.patch} | 4 +- ...ch => 0005-virtio-balloon-fix-query.patch} | 4 +- ...el-to-kvm64-32-instead-of-qemu64-32.patch} | 4 +- ... => 0007-qapi-modify-query-machines.patch} | 4 +- ...tch => 0008-qapi-modify-spice-query.patch} | 4 +- ...to-pve-certs-unless-otherwise-speci.patch} | 4 +- ...tch => 0010-internal-snapshot-async.patch} | 132 +- ...011-convert-savevm-async-to-threads.patch} | 10 +- ...tch => 0012-qmp-add-get_link_status.patch} | 8 +- .../pve/0012-vma-add-verify-command.patch | 321 ---- ...e.patch => 0013-smm_available-false.patch} | 4 +- ...dd-config-command-to-dump-the-config.patch | 101 -- .../pve/0014-backup-modify-job-api.patch | 292 ---- ...pace-between-VERSION-and-PKGVERSION.patch} | 4 +- ...0015-backup-add-pve-monitor-commands.patch | 830 ---------- ...n.patch => 0015-vnc-altgr-emulation.patch} | 4 +- .../pve/0016-backup-vma-add-dir-format.patch | 315 ---- ... 0016-vnc-make-x509-imply-tls-again.patch} | 4 +- ...o-not-return-errors-in-dump-callback.patch | 77 - ... => 0017-vnc-PVE-VNC-authentication.patch} | 51 +- ...backup-vma-correctly-propagate-error.patch | 57 - ...x-possible-unitialised-return-value.patch} | 4 +- .../0019-backup-vma-remove-async-queue.patch | 317 ---- ...-rbd_cache_writethrough_until_flush.patch} | 6 +- ...ackup-vma-run-flush-inside-coroutine.patch | 56 - ...t-qmp_snapshot_drive-add-aiocontext.patch} | 12 +- ...021-backup-do-not-use-bdrv_drain_all.patch | 36 - ...p_delete_drive_snapshot-add-aiocont.patch} | 11 +- ...fs-no-default-logfile-if-daemonized.patch} | 4 +- .../0023-backup-vma-allow-empty-backups.patch | 256 --- ... 0023-glusterfs-allow-partial-reads.patch} | 4 +- ...dd-the-zeroinit-block-driver-filter.patch} | 13 +- ...osize-and-read-from-to-stdin-stdout.patch} | 25 +- .../pve/0026-backup-modify-job-api.patch | 100 ++ ...-backup-introduce-vma-archive-format.patch | 1400 ++++++++++++++++ .../patches/pve/0027-vma-add-firewall.patch | 144 -- ....patch => 0028-adding-old-vma-files.patch} | 1456 +++++++++++++---- ...async-migration-and-bdrv_open-update.patch | 101 -- ...-don-t-bail-out-on-zero-length-files.patch | 24 - ...better-driver-guessing-for-bdrv_open.patch | 42 - ...-add-format-option-to-device-mapping.patch | 108 -- ...036-vnc-refactor-to-QIOChannelSocket.patch | 87 - ...0037-vma-use-BlockBackend-on-extract.patch | 75 - .../pve/0038-vma-byte-based-write-calls.patch | 237 --- ...afe-for-vma-extract_content-and-qmp_.patch | 43 - .../pve/0041-savevm-async-updates.patch | 215 --- ...-to-blk_co_preadv-should-be-bytes-no.patch | 27 - ...0048-vma-don-t-use-O_DIRECT-on-pipes.patch | 52 - ...k-zeroinit-request-child-permissions.patch | 25 - debian/patches/series | 74 +- 53 files changed, 2877 insertions(+), 4319 deletions(-) rename debian/patches/pve/{0004-qemu-img-return-success-on-info-without-snapshots.patch => 0003-qemu-img-return-success-on-info-without-snapshots.patch} (81%) rename debian/patches/pve/{0005-use-kvm-by-default.patch => 0004-use-kvm-by-default.patch} (85%) rename debian/patches/pve/{0006-virtio-balloon-fix-query.patch => 0005-virtio-balloon-fix-query.patch} (97%) rename debian/patches/pve/{0007-set-the-CPU-model-to-kvm64-32-instead-of-qemu64-32.patch => 0006-set-the-CPU-model-to-kvm64-32-instead-of-qemu64-32.patch} (83%) rename debian/patches/pve/{0008-qapi-modify-query-machines.patch => 0007-qapi-modify-query-machines.patch} (92%) rename debian/patches/pve/{0009-qapi-modify-spice-query.patch => 0008-qapi-modify-spice-query.patch} (92%) rename debian/patches/pve/{0010-ui-spice-default-to-pve-certs-unless-otherwise-speci.patch => 0009-ui-spice-default-to-pve-certs-unless-otherwise-speci.patch} (93%) rename debian/patches/pve/{0022-internal-snapshot-async.patch => 0010-internal-snapshot-async.patch} (89%) rename debian/patches/pve/{0046-convert-savevm-async-to-threads.patch => 0011-convert-savevm-async-to-threads.patch} (97%) rename debian/patches/pve/{0024-qmp-add-get_link_status.patch => 0012-qmp-add-get_link_status.patch} (92%) delete mode 100644 debian/patches/pve/0012-vma-add-verify-command.patch rename debian/patches/pve/{0025-smm_available-false.patch => 0013-smm_available-false.patch} (85%) delete mode 100644 debian/patches/pve/0013-vma-add-config-command-to-dump-the-config.patch delete mode 100644 debian/patches/pve/0014-backup-modify-job-api.patch rename debian/patches/pve/{0026-use-whitespace-between-VERSION-and-PKGVERSION.patch => 0014-use-whitespace-between-VERSION-and-PKGVERSION.patch} (83%) delete mode 100644 debian/patches/pve/0015-backup-add-pve-monitor-commands.patch rename debian/patches/pve/{0003-vnc-altgr-emulation.patch => 0015-vnc-altgr-emulation.patch} (94%) delete mode 100644 debian/patches/pve/0016-backup-vma-add-dir-format.patch rename debian/patches/pve/{0029-vnc-make-x509-imply-tls-again.patch => 0016-vnc-make-x509-imply-tls-again.patch} (85%) delete mode 100644 debian/patches/pve/0017-backup-do-not-return-errors-in-dump-callback.patch rename debian/patches/pve/{0030-PVE-VNC-authentication.patch => 0017-vnc-PVE-VNC-authentication.patch} (95%) delete mode 100644 debian/patches/pve/0018-backup-vma-correctly-propagate-error.patch rename debian/patches/pve/{0035-fix-possible-unitialised-return-value.patch => 0018-migrate-fix-possible-unitialised-return-value.patch} (82%) delete mode 100644 debian/patches/pve/0019-backup-vma-remove-async-queue.patch rename debian/patches/pve/{0039-rbd-disable-rbd_cache_writethrough_until_flush-with-.patch => 0019-block-rbd-disable-rbd_cache_writethrough_until_flush.patch} (81%) delete mode 100644 debian/patches/pve/0020-backup-vma-run-flush-inside-coroutine.patch rename debian/patches/pve/{0042-qmp_snapshot_drive-add-aiocontext.patch => 0020-block-snapshot-qmp_snapshot_drive-add-aiocontext.patch} (80%) delete mode 100644 debian/patches/pve/0021-backup-do-not-use-bdrv_drain_all.patch rename debian/patches/pve/{0045-qmp_delete_drive_snapshot-add-aiocontext.patch => 0021-block-snapshot-qmp_delete_drive_snapshot-add-aiocont.patch} (81%) rename debian/patches/pve/{0044-glusterfs-no-default-logfile-if-daemonized.patch => 0022-glusterfs-no-default-logfile-if-daemonized.patch} (91%) delete mode 100644 debian/patches/pve/0023-backup-vma-allow-empty-backups.patch rename debian/patches/pve/{0047-glusterfs-allow-partial-reads.patch => 0023-glusterfs-allow-partial-reads.patch} (95%) rename debian/patches/pve/{0033-block-add-the-zeroinit-block-driver-filter.patch => 0024-block-add-the-zeroinit-block-driver-filter.patch} (95%) rename debian/patches/pve/{0050-qemu-img-dd-add-osize-and-read-from-to-stdin-stdout.patch => 0025-qemu-img-dd-add-osize-and-read-from-to-stdin-stdout.patch} (89%) create mode 100644 debian/patches/pve/0026-backup-modify-job-api.patch create mode 100644 debian/patches/pve/0027-backup-introduce-vma-archive-format.patch delete mode 100644 debian/patches/pve/0027-vma-add-firewall.patch rename debian/patches/pve/{0011-introduce-new-vma-archive-format.patch => 0028-adding-old-vma-files.patch} (59%) delete mode 100644 debian/patches/pve/0028-savevm-async-migration-and-bdrv_open-update.patch delete mode 100644 debian/patches/pve/0031-vma-writer-don-t-bail-out-on-zero-length-files.patch delete mode 100644 debian/patches/pve/0032-vma-better-driver-guessing-for-bdrv_open.patch delete mode 100644 debian/patches/pve/0034-vma-add-format-option-to-device-mapping.patch delete mode 100644 debian/patches/pve/0036-vnc-refactor-to-QIOChannelSocket.patch delete mode 100644 debian/patches/pve/0037-vma-use-BlockBackend-on-extract.patch delete mode 100644 debian/patches/pve/0038-vma-byte-based-write-calls.patch delete mode 100644 debian/patches/pve/0040-enable-cache-unsafe-for-vma-extract_content-and-qmp_.patch delete mode 100644 debian/patches/pve/0041-savevm-async-updates.patch delete mode 100644 debian/patches/pve/0043-vma-sizes-passed-to-blk_co_preadv-should-be-bytes-no.patch delete mode 100644 debian/patches/pve/0048-vma-don-t-use-O_DIRECT-on-pipes.patch delete mode 100644 debian/patches/pve/0049-block-zeroinit-request-child-permissions.patch diff --git a/debian/patches/pve/0001-fr-ca-keymap-corrections.patch b/debian/patches/pve/0001-fr-ca-keymap-corrections.patch index 04bb94a..6aa4f2c 100644 --- a/debian/patches/pve/0001-fr-ca-keymap-corrections.patch +++ b/debian/patches/pve/0001-fr-ca-keymap-corrections.patch @@ -1,7 +1,7 @@ From 926ac2ae6be8a7971e4c24d45345981e3a62d560 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Wed, 9 Dec 2015 14:15:49 +0100 -Subject: [PATCH 01/49] fr-ca keymap corrections +Subject: [PATCH 01/28] fr-ca keymap corrections --- pc-bios/keymaps/fr-ca | 9 +++++++++ diff --git a/debian/patches/pve/0002-Adjust-network-script-path-to-etc-kvm.patch b/debian/patches/pve/0002-Adjust-network-script-path-to-etc-kvm.patch index 787291f..a42c916 100644 --- a/debian/patches/pve/0002-Adjust-network-script-path-to-etc-kvm.patch +++ b/debian/patches/pve/0002-Adjust-network-script-path-to-etc-kvm.patch @@ -1,7 +1,7 @@ From 65a038b874c5770f48077cf77742ac10bb083922 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Wed, 9 Dec 2015 14:16:49 +0100 -Subject: [PATCH 02/49] Adjust network script path to /etc/kvm/ +Subject: [PATCH 02/28] Adjust network script path to /etc/kvm/ --- include/net/net.h | 5 +++-- diff --git a/debian/patches/pve/0004-qemu-img-return-success-on-info-without-snapshots.patch b/debian/patches/pve/0003-qemu-img-return-success-on-info-without-snapshots.patch similarity index 81% rename from debian/patches/pve/0004-qemu-img-return-success-on-info-without-snapshots.patch rename to debian/patches/pve/0003-qemu-img-return-success-on-info-without-snapshots.patch index f0d7da3..2ba022c 100644 --- a/debian/patches/pve/0004-qemu-img-return-success-on-info-without-snapshots.patch +++ b/debian/patches/pve/0003-qemu-img-return-success-on-info-without-snapshots.patch @@ -1,7 +1,7 @@ -From 2d53d7c93802c9c28c5958fae5c71825b1707295 Mon Sep 17 00:00:00 2001 +From 034ee9d08002e8e57c4d09e9a9750aad547f65f1 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Wed, 9 Dec 2015 14:18:46 +0100 -Subject: [PATCH 04/49] qemu-img: return success on info without snapshots +Subject: [PATCH 03/28] qemu-img: return success on info without snapshots --- qemu-img.c | 3 ++- diff --git a/debian/patches/pve/0005-use-kvm-by-default.patch b/debian/patches/pve/0004-use-kvm-by-default.patch similarity index 85% rename from debian/patches/pve/0005-use-kvm-by-default.patch rename to debian/patches/pve/0004-use-kvm-by-default.patch index ca6aae9..92d9ce0 100644 --- a/debian/patches/pve/0005-use-kvm-by-default.patch +++ b/debian/patches/pve/0004-use-kvm-by-default.patch @@ -1,7 +1,7 @@ -From 1a677a89338980c830ba378824996cd53f2ec96b Mon Sep 17 00:00:00 2001 +From 0203288ce982ea135ff82cf4ea6a7868ef053470 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Wed, 9 Dec 2015 14:27:05 +0100 -Subject: [PATCH 05/49] use kvm by default +Subject: [PATCH 04/28] use kvm by default --- accel.c | 4 ++-- diff --git a/debian/patches/pve/0006-virtio-balloon-fix-query.patch b/debian/patches/pve/0005-virtio-balloon-fix-query.patch similarity index 97% rename from debian/patches/pve/0006-virtio-balloon-fix-query.patch rename to debian/patches/pve/0005-virtio-balloon-fix-query.patch index 4e5dd20..13def0d 100644 --- a/debian/patches/pve/0006-virtio-balloon-fix-query.patch +++ b/debian/patches/pve/0005-virtio-balloon-fix-query.patch @@ -1,7 +1,7 @@ -From 1cd097140cab2650415b311bd7549036df6e6978 Mon Sep 17 00:00:00 2001 +From d91355991605106e86f246e0e9091ffc1275b52f Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Wed, 9 Dec 2015 14:27:49 +0100 -Subject: [PATCH 06/49] virtio-balloon: fix query +Subject: [PATCH 05/28] virtio-balloon: fix query Actually provide memory information via the query-balloon command. diff --git a/debian/patches/pve/0007-set-the-CPU-model-to-kvm64-32-instead-of-qemu64-32.patch b/debian/patches/pve/0006-set-the-CPU-model-to-kvm64-32-instead-of-qemu64-32.patch similarity index 83% rename from debian/patches/pve/0007-set-the-CPU-model-to-kvm64-32-instead-of-qemu64-32.patch rename to debian/patches/pve/0006-set-the-CPU-model-to-kvm64-32-instead-of-qemu64-32.patch index 8eda4dd..19e0c5a 100644 --- a/debian/patches/pve/0007-set-the-CPU-model-to-kvm64-32-instead-of-qemu64-32.patch +++ b/debian/patches/pve/0006-set-the-CPU-model-to-kvm64-32-instead-of-qemu64-32.patch @@ -1,7 +1,7 @@ -From b5dd9f221abd0afd83f05787ca270c3d80959a2e Mon Sep 17 00:00:00 2001 +From 99d1d87c126c630afed3885a26b5c4c6ca6e050b Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Wed, 9 Dec 2015 14:30:21 +0100 -Subject: [PATCH 07/49] set the CPU model to kvm64/32 instead of qemu64/32 +Subject: [PATCH 06/28] set the CPU model to kvm64/32 instead of qemu64/32 --- hw/i386/pc.c | 4 ++-- diff --git a/debian/patches/pve/0008-qapi-modify-query-machines.patch b/debian/patches/pve/0007-qapi-modify-query-machines.patch similarity index 92% rename from debian/patches/pve/0008-qapi-modify-query-machines.patch rename to debian/patches/pve/0007-qapi-modify-query-machines.patch index d9b463f..fa51e6f 100644 --- a/debian/patches/pve/0008-qapi-modify-query-machines.patch +++ b/debian/patches/pve/0007-qapi-modify-query-machines.patch @@ -1,7 +1,7 @@ -From 95a583f2d001477eca4c74d49be44f00bf9a8440 Mon Sep 17 00:00:00 2001 +From a761848c2ded6eb644c0e0e5d9184f54db59828a Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Wed, 9 Dec 2015 14:31:18 +0100 -Subject: [PATCH 08/49] qapi: modify query machines +Subject: [PATCH 07/28] qapi: modify query machines provide '*is-current' in MachineInfo struct --- diff --git a/debian/patches/pve/0009-qapi-modify-spice-query.patch b/debian/patches/pve/0008-qapi-modify-spice-query.patch similarity index 92% rename from debian/patches/pve/0009-qapi-modify-spice-query.patch rename to debian/patches/pve/0008-qapi-modify-spice-query.patch index 1703ae8..eb394be 100644 --- a/debian/patches/pve/0009-qapi-modify-spice-query.patch +++ b/debian/patches/pve/0008-qapi-modify-spice-query.patch @@ -1,7 +1,7 @@ -From bc5254a21ab6556c000e30fa340d11e0a5bb7dd3 Mon Sep 17 00:00:00 2001 +From 7215cf5a1ef31a3b0470c16d0b2a3585edf5dbc5 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Wed, 9 Dec 2015 14:32:11 +0100 -Subject: [PATCH 09/49] qapi: modify spice query +Subject: [PATCH 08/28] qapi: modify spice query Provide the last ticket in the SpiceInfo struct optionally. --- diff --git a/debian/patches/pve/0010-ui-spice-default-to-pve-certs-unless-otherwise-speci.patch b/debian/patches/pve/0009-ui-spice-default-to-pve-certs-unless-otherwise-speci.patch similarity index 93% rename from debian/patches/pve/0010-ui-spice-default-to-pve-certs-unless-otherwise-speci.patch rename to debian/patches/pve/0009-ui-spice-default-to-pve-certs-unless-otherwise-speci.patch index 6256bf5..6ec9ed7 100644 --- a/debian/patches/pve/0010-ui-spice-default-to-pve-certs-unless-otherwise-speci.patch +++ b/debian/patches/pve/0009-ui-spice-default-to-pve-certs-unless-otherwise-speci.patch @@ -1,7 +1,7 @@ -From 33d16abdcb9d708b9f63c2a5380e4849b9c34fce Mon Sep 17 00:00:00 2001 +From 3ea2b6f80c46456be2ed339dc2338a61cc7b7bfe Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Wed, 9 Dec 2015 14:33:34 +0100 -Subject: [PATCH 10/49] ui/spice: default to pve certs unless otherwise +Subject: [PATCH 09/28] ui/spice: default to pve certs unless otherwise specified --- diff --git a/debian/patches/pve/0022-internal-snapshot-async.patch b/debian/patches/pve/0010-internal-snapshot-async.patch similarity index 89% rename from debian/patches/pve/0022-internal-snapshot-async.patch rename to debian/patches/pve/0010-internal-snapshot-async.patch index 0ff34e9..77a6ec2 100644 --- a/debian/patches/pve/0022-internal-snapshot-async.patch +++ b/debian/patches/pve/0010-internal-snapshot-async.patch @@ -1,7 +1,7 @@ -From 4599049cf93b3e189caded4f9bf1dd50c257c927 Mon Sep 17 00:00:00 2001 +From 1f5a5623052ba8d593e4356f9fda0281e607be76 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Wed, 9 Dec 2015 16:04:32 +0100 -Subject: [PATCH 22/49] internal snapshot async +Subject: [PATCH 10/28] internal snapshot async --- Makefile.objs | 1 + @@ -15,16 +15,16 @@ Subject: [PATCH 22/49] internal snapshot async migration/savevm.c | 12 +- qapi-schema.json | 68 +++++++ qemu-options.hx | 13 ++ - savevm-async.c | 525 ++++++++++++++++++++++++++++++++++++++++++++++++ + savevm-async.c | 523 ++++++++++++++++++++++++++++++++++++++++++++++++ vl.c | 8 + - 13 files changed, 734 insertions(+), 8 deletions(-) + 13 files changed, 732 insertions(+), 8 deletions(-) create mode 100644 savevm-async.c diff --git a/Makefile.objs b/Makefile.objs -index 9b12ee6afa..f5f8dbab3b 100644 +index 6167e7b17d..fbfbbb7f70 100644 --- a/Makefile.objs +++ b/Makefile.objs -@@ -51,6 +51,7 @@ common-obj-$(CONFIG_LINUX) += fsdev/ +@@ -50,6 +50,7 @@ common-obj-$(CONFIG_LINUX) += fsdev/ common-obj-y += migration/ common-obj-y += page_cache.o #aio.o @@ -46,10 +46,10 @@ index 1fbbb8d606..6ea9ed1c62 100644 assert(!bs->job); assert(bdrv_op_blocker_is_empty(bs)); diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx -index 1a1838099f..3b5a0f95e4 100644 +index a53f105c52..5fc57a2210 100644 --- a/hmp-commands-info.hx +++ b/hmp-commands-info.hx -@@ -573,6 +573,19 @@ Show current migration xbzrle cache size. +@@ -560,6 +560,19 @@ Show current migration xbzrle cache size. ETEXI { @@ -70,10 +70,10 @@ index 1a1838099f..3b5a0f95e4 100644 .args_type = "", .params = "", diff --git a/hmp-commands.hx b/hmp-commands.hx -index 72882039ee..a2867b56f2 100644 +index 88192817b2..58940a762b 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx -@@ -1808,3 +1808,35 @@ ETEXI +@@ -1777,3 +1777,35 @@ ETEXI STEXI @end table ETEXI @@ -110,10 +110,10 @@ index 72882039ee..a2867b56f2 100644 + .cmd = hmp_savevm_end, + }, diff --git a/hmp.c b/hmp.c -index 465d7faad0..aaf0de1642 100644 +index 904542d026..f725d061e6 100644 --- a/hmp.c +++ b/hmp.c -@@ -2270,6 +2270,63 @@ void hmp_info_memory_devices(Monitor *mon, const QDict *qdict) +@@ -2207,6 +2207,63 @@ void hmp_info_memory_devices(Monitor *mon, const QDict *qdict) qapi_free_MemoryDeviceInfoList(info_list); } @@ -178,7 +178,7 @@ index 465d7faad0..aaf0de1642 100644 { IOThreadInfoList *info_list = qmp_query_iothreads(NULL); diff --git a/hmp.h b/hmp.h -index 17a65b2313..8c1b4846b3 100644 +index 799fd371fa..0497afbf65 100644 --- a/hmp.h +++ b/hmp.h @@ -26,6 +26,7 @@ void hmp_info_status(Monitor *mon, const QDict *qdict); @@ -189,7 +189,7 @@ index 17a65b2313..8c1b4846b3 100644 void hmp_info_migrate(Monitor *mon, const QDict *qdict); void hmp_info_migrate_capabilities(Monitor *mon, const QDict *qdict); void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict); -@@ -95,6 +96,10 @@ void hmp_netdev_add(Monitor *mon, const QDict *qdict); +@@ -92,6 +93,10 @@ void hmp_netdev_add(Monitor *mon, const QDict *qdict); void hmp_netdev_del(Monitor *mon, const QDict *qdict); void hmp_getfd(Monitor *mon, const QDict *qdict); void hmp_closefd(Monitor *mon, const QDict *qdict); @@ -299,10 +299,10 @@ index 3b19a4a274..feb0dc6834 100644 /* Give an estimate of the amount left to be transferred, diff --git a/qapi-schema.json b/qapi-schema.json -index edb7c32ac9..a25074183c 100644 +index 1b14ff2476..361700d37c 100644 --- a/qapi-schema.json +++ b/qapi-schema.json -@@ -813,6 +813,40 @@ +@@ -723,6 +723,40 @@ '*error-desc': 'str'} } ## @@ -343,7 +343,7 @@ index edb7c32ac9..a25074183c 100644 # @query-migrate: # # Returns information about current migration process. If migration -@@ -4825,9 +4859,43 @@ +@@ -4735,9 +4769,43 @@ # # Since: 1.2.0 ## @@ -413,10 +413,10 @@ index 99af8edf5f..10f0e81f9b 100644 "-daemonize daemonize QEMU after initializing\n", QEMU_ARCH_ALL) diff --git a/savevm-async.c b/savevm-async.c new file mode 100644 -index 0000000000..9704a412d9 +index 0000000000..2f4766cf6c --- /dev/null +++ b/savevm-async.c -@@ -0,0 +1,525 @@ +@@ -0,0 +1,523 @@ +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "qapi/qmp/qerror.h" @@ -439,6 +439,8 @@ index 0000000000..9704a412d9 + +/* #define DEBUG_SAVEVM_STATE */ + ++#define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */ ++ +#ifdef DEBUG_SAVEVM_STATE +#define DPRINTF(fmt, ...) \ + do { printf("savevm-async: " fmt, ## __VA_ARGS__); } while (0) @@ -457,7 +459,7 @@ index 0000000000..9704a412d9 + + +static struct SnapshotState { -+ BlockDriverState *bs; ++ BlockBackend *target; + size_t bs_pos; + int state; + Error *error; @@ -518,17 +520,17 @@ index 0000000000..9704a412d9 + ret = qemu_fclose(snap_state.file); + } + -+ if (snap_state.bs) { ++ if (snap_state.target) { + /* try to truncate, but ignore errors (will fail on block devices). + * note: bdrv_read() need whole blocks, so we round up + */ + size_t size = (snap_state.bs_pos + BDRV_SECTOR_SIZE) & BDRV_SECTOR_MASK; -+ bdrv_truncate(snap_state.bs, size); -+ bdrv_op_unblock_all(snap_state.bs, snap_state.blocker); ++ blk_truncate(snap_state.target, size); ++ blk_op_unblock_all(snap_state.target, snap_state.blocker); + error_free(snap_state.blocker); + snap_state.blocker = NULL; -+ bdrv_unref(snap_state.bs); -+ snap_state.bs = NULL; ++ blk_unref(snap_state.target); ++ snap_state.target = NULL; + } + + return ret; @@ -570,21 +572,22 @@ index 0000000000..9704a412d9 +static int block_state_close(void *opaque) +{ + snap_state.file = NULL; -+ return bdrv_flush(snap_state.bs); ++ return blk_flush(snap_state.target); +} + -+static int block_state_put_buffer(void *opaque, const uint8_t *buf, -+ int64_t pos, int size) ++static ssize_t block_state_writev_buffer(void *opaque, struct iovec *iov, ++ int iovcnt, int64_t pos) +{ + int ret; ++ QEMUIOVector qiov; + -+ assert(pos == snap_state.bs_pos); -+ -+ if ((ret = bdrv_pwrite(snap_state.bs, snap_state.bs_pos, buf, size)) > 0) { -+ snap_state.bs_pos += ret; ++ qemu_iovec_init_external(&qiov, iov, iovcnt); ++ ret = blk_co_pwritev(snap_state.target, pos, qiov.size, &qiov, 0); ++ if (ret < 0) { ++ return ret; + } -+ -+ return ret; ++ snap_state.bs_pos += qiov.size; ++ return qiov.size; +} + +static int store_and_stop(void) { @@ -620,12 +623,13 @@ index 0000000000..9704a412d9 + } + + while (snap_state.state == SAVE_STATE_ACTIVE) { -+ uint64_t pending_size; ++ uint64_t pending_size, pend_post, pend_nonpost; + -+ pending_size = qemu_savevm_state_pending(snap_state.file, 0); ++ qemu_savevm_state_pending(snap_state.file, 0, &pend_nonpost, &pend_post); ++ pending_size = pend_post + pend_nonpost; + + if (pending_size) { -+ ret = qemu_savevm_state_iterate(snap_state.file); ++ ret = qemu_savevm_state_iterate(snap_state.file, false); + if (ret < 0) { + save_snapshot_error("qemu_savevm_state_iterate error %d", ret); + break; @@ -636,7 +640,7 @@ index 0000000000..9704a412d9 + if (store_and_stop()) + break; + DPRINTF("savevm inerate finished\n"); -+ qemu_savevm_state_complete_precopy(snap_state.file); ++ qemu_savevm_state_complete_precopy(snap_state.file, false); + DPRINTF("save complete\n"); + save_snapshot_completed(); + break; @@ -645,7 +649,7 @@ index 0000000000..9704a412d9 + /* stop the VM if we get to the end of available space, + * or if pending_size is just a few MB + */ -+ maxlen = bdrv_getlength(snap_state.bs) - 30*1024*1024; ++ maxlen = blk_getlength(snap_state.target) - 30*1024*1024; + if ((pending_size < 100000) || + ((snap_state.bs_pos + pending_size) >= maxlen)) { + if (store_and_stop()) @@ -662,18 +666,16 @@ index 0000000000..9704a412d9 +} + +static const QEMUFileOps block_file_ops = { -+ .put_buffer = block_state_put_buffer, ++ .writev_buffer = block_state_writev_buffer, + .close = block_state_close, +}; + + +void qmp_savevm_start(bool has_statefile, const char *statefile, Error **errp) +{ -+ BlockDriver *drv = NULL; + Error *local_err = NULL; + -+ int bdrv_oflags = BDRV_O_RDWR | BDRV_O_RESIZE; -+ int ret; ++ int bdrv_oflags = BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_NO_FLUSH; + + if (snap_state.state != SAVE_STATE_DONE) { + error_set(errp, ERROR_CLASS_GENERIC_ERROR, @@ -703,13 +705,11 @@ index 0000000000..9704a412d9 + } + + /* Open the image */ -+ snap_state.bs = bdrv_new(); -+ + QDict *options = NULL; + options = qdict_new(); + qdict_put(options, "driver", qstring_from_str("raw")); -+ ret = bdrv_open(&snap_state.bs, statefile, NULL, options, bdrv_oflags, drv, &local_err); -+ if (ret < 0) { ++ snap_state.target = blk_new_open(statefile, NULL, options, bdrv_oflags, &local_err); ++ if (!snap_state.target) { + error_set(errp, ERROR_CLASS_GENERIC_ERROR, "failed to open '%s'", statefile); + goto restart; + } @@ -723,9 +723,9 @@ index 0000000000..9704a412d9 + + + error_setg(&snap_state.blocker, "block device is in use by savevm"); -+ bdrv_op_block_all(snap_state.bs, snap_state.blocker); ++ blk_op_block_all(snap_state.target, snap_state.blocker); + -+ Coroutine *co = qemu_coroutine_create(process_savevm_co); ++ Coroutine *co = qemu_coroutine_create(process_savevm_co, NULL); + qemu_coroutine_enter(co); + + return; @@ -873,11 +873,11 @@ index 0000000000..9704a412d9 + } +} + -+static int loadstate_get_buffer(void *opaque, uint8_t *buf, int64_t pos, -+ int size) ++static ssize_t loadstate_get_buffer(void *opaque, uint8_t *buf, int64_t pos, ++ size_t size) +{ -+ BlockDriverState *bs = (BlockDriverState *)opaque; -+ int64_t maxlen = bdrv_getlength(bs); ++ BlockBackend *be = opaque; ++ int64_t maxlen = blk_getlength(be); + if (pos > maxlen) { + return -EIO; + } @@ -887,7 +887,7 @@ index 0000000000..9704a412d9 + if (size == 0) { + return 0; + } -+ return bdrv_pread(bs, pos, buf, size); ++ return blk_pread(be, pos, buf, size); +} + +static const QEMUFileOps loadstate_file_ops = { @@ -896,29 +896,27 @@ index 0000000000..9704a412d9 + +int load_state_from_blockdev(const char *filename) +{ -+ BlockDriverState *bs = NULL; -+ BlockDriver *drv = NULL; ++ BlockBackend *be; + Error *local_err = NULL; + Error *blocker = NULL; + + QEMUFile *f; -+ int ret; ++ int ret = -EINVAL; + -+ bs = bdrv_new(); -+ ret = bdrv_open(&bs, filename, NULL, NULL, 0, drv, &local_err); -+ error_setg(&blocker, "block device is in use by load state"); -+ bdrv_op_block_all(bs, blocker); ++ be = blk_new_open(filename, NULL, NULL, 0, &local_err); + -+ if (ret < 0) { ++ if (!be) { + error_report("Could not open VM state file"); + goto the_end; + } + ++ error_setg(&blocker, "block device is in use by load state"); ++ blk_op_block_all(be, blocker); ++ + /* restore the VM state */ -+ f = qemu_fopen_ops(bs, &loadstate_file_ops); ++ f = qemu_fopen_ops(be, &loadstate_file_ops); + if (!f) { + error_report("Could not open VM state file"); -+ ret = -EINVAL; + goto the_end; + } + @@ -935,10 +933,10 @@ index 0000000000..9704a412d9 + ret = 0; + + the_end: -+ if (bs) { -+ bdrv_op_unblock_all(bs, blocker); ++ if (be) { ++ blk_op_unblock_all(be, blocker); + error_free(blocker); -+ bdrv_unref(bs); ++ blk_unref(be); + } + return ret; +} diff --git a/debian/patches/pve/0046-convert-savevm-async-to-threads.patch b/debian/patches/pve/0011-convert-savevm-async-to-threads.patch similarity index 97% rename from debian/patches/pve/0046-convert-savevm-async-to-threads.patch rename to debian/patches/pve/0011-convert-savevm-async-to-threads.patch index ac8389a..258f03c 100644 --- a/debian/patches/pve/0046-convert-savevm-async-to-threads.patch +++ b/debian/patches/pve/0011-convert-savevm-async-to-threads.patch @@ -1,14 +1,14 @@ -From c80c9d6e7365d83bae020de4862cc9825374b88c Mon Sep 17 00:00:00 2001 +From 1a92a719b15ed17e57999e009bc0fb4cf94ef468 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Tue, 8 Nov 2016 11:13:06 +0100 -Subject: [PATCH 46/49] convert savevm-async to threads +Subject: [PATCH 11/28] convert savevm-async to threads --- savevm-async.c | 144 +++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 88 insertions(+), 56 deletions(-) diff --git a/savevm-async.c b/savevm-async.c -index 3adf89fdb2..9f839faab5 100644 +index 2f4766cf6c..624e3a34b4 100644 --- a/savevm-async.c +++ b/savevm-async.c @@ -48,6 +48,8 @@ static struct SnapshotState { @@ -177,12 +177,12 @@ index 3adf89fdb2..9f839faab5 100644 + ret = global_state_store(); + if (ret) { + save_snapshot_error("global_state_store error %d", ret); -+ break; + break; + } + ret = vm_stop_force_state(RUN_STATE_FINISH_MIGRATE); + if (ret < 0) { + save_snapshot_error("vm_stop_force_state error %d", ret); - break; ++ break; + } DPRINTF("savevm inerate finished\n"); qemu_savevm_state_complete_precopy(snap_state.file, false); diff --git a/debian/patches/pve/0024-qmp-add-get_link_status.patch b/debian/patches/pve/0012-qmp-add-get_link_status.patch similarity index 92% rename from debian/patches/pve/0024-qmp-add-get_link_status.patch rename to debian/patches/pve/0012-qmp-add-get_link_status.patch index a35fbc8..bba5a93 100644 --- a/debian/patches/pve/0024-qmp-add-get_link_status.patch +++ b/debian/patches/pve/0012-qmp-add-get_link_status.patch @@ -1,7 +1,7 @@ -From d8699dad1b5941aa0a5a9346f13586366f1fb051 Mon Sep 17 00:00:00 2001 +From 6c70ffe629c678a110d311fab784d65836a7917e Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Wed, 9 Dec 2015 16:34:41 +0100 -Subject: [PATCH 24/49] qmp: add get_link_status +Subject: [PATCH 12/28] qmp: add get_link_status --- net/net.c | 27 +++++++++++++++++++++++++++ @@ -47,7 +47,7 @@ index 0ac3b9e80c..7410c1e5f3 100644 { NetClientState *ncs[MAX_QUEUE_NUM]; diff --git a/qapi-schema.json b/qapi-schema.json -index a25074183c..21f822aada 100644 +index 361700d37c..5e82933ca1 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -56,6 +56,7 @@ @@ -58,7 +58,7 @@ index a25074183c..21f822aada 100644 'human-monitor-command', 'qom-get', 'query-migrate-cache-size', -@@ -2627,6 +2628,21 @@ +@@ -2537,6 +2538,21 @@ { 'command': 'set_link', 'data': {'name': 'str', 'up': 'bool'} } ## diff --git a/debian/patches/pve/0012-vma-add-verify-command.patch b/debian/patches/pve/0012-vma-add-verify-command.patch deleted file mode 100644 index 6c853cb..0000000 --- a/debian/patches/pve/0012-vma-add-verify-command.patch +++ /dev/null @@ -1,321 +0,0 @@ -From d4c9597f3064b68853cefca90dd335cd5e5320d0 Mon Sep 17 00:00:00 2001 -From: Dietmar Maurer -Date: Mon, 11 Mar 2013 07:07:46 +0100 -Subject: [PATCH 12/49] vma: add verify command - -Users wants to verify the archive after backup. - -Examples: - - # vma verify -v test.vma - - # lzop -d -c test.vma.lzo |vma verify - - -Signed-off-by: Dietmar Maurer ---- - vma-reader.c | 121 ++++++++++++++++++++++++++++++++++++++++++++--------------- - vma.c | 55 +++++++++++++++++++++++++++ - vma.h | 1 + - 3 files changed, 147 insertions(+), 30 deletions(-) - -diff --git a/vma-reader.c b/vma-reader.c -index 51dd8fee0e..2aafb26b2a 100644 ---- a/vma-reader.c -+++ b/vma-reader.c -@@ -45,6 +45,8 @@ struct VmaReader { - time_t start_time; - int64_t cluster_count; - int64_t clusters_read; -+ int64_t zero_cluster_data; -+ int64_t partial_zero_cluster_data; - int clusters_read_per; - }; - -@@ -425,6 +427,27 @@ VmaDeviceInfo *vma_reader_get_device_info(VmaReader *vmar, guint8 dev_id) - return NULL; - } - -+static void allocate_rstate(VmaReader *vmar, guint8 dev_id, -+ BlockDriverState *bs, bool write_zeroes) -+{ -+ assert(vmar); -+ assert(dev_id); -+ -+ vmar->rstate[dev_id].bs = bs; -+ vmar->rstate[dev_id].write_zeroes = write_zeroes; -+ -+ int64_t size = vmar->devinfo[dev_id].size; -+ -+ int64_t bitmap_size = (size/BDRV_SECTOR_SIZE) + -+ (VMA_CLUSTER_SIZE/BDRV_SECTOR_SIZE) * BITS_PER_LONG - 1; -+ bitmap_size /= (VMA_CLUSTER_SIZE/BDRV_SECTOR_SIZE) * BITS_PER_LONG; -+ -+ 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; -+} -+ - int vma_reader_register_bs(VmaReader *vmar, guint8 dev_id, BlockDriverState *bs, - bool write_zeroes, Error **errp) - { -@@ -447,17 +470,7 @@ int vma_reader_register_bs(VmaReader *vmar, guint8 dev_id, BlockDriverState *bs, - return -1; - } - -- vmar->rstate[dev_id].bs = bs; -- vmar->rstate[dev_id].write_zeroes = write_zeroes; -- -- int64_t bitmap_size = (size/BDRV_SECTOR_SIZE) + -- (VMA_CLUSTER_SIZE/BDRV_SECTOR_SIZE) * BITS_PER_LONG - 1; -- bitmap_size /= (VMA_CLUSTER_SIZE/BDRV_SECTOR_SIZE) * BITS_PER_LONG; -- -- 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; -+ allocate_rstate(vmar, dev_id, bs, write_zeroes); - - return 0; - } -@@ -524,9 +537,10 @@ static int restore_write_data(VmaReader *vmar, guint8 dev_id, - } - return 0; - } -+ - static int restore_extent(VmaReader *vmar, unsigned char *buf, - int extent_size, int vmstate_fd, -- bool verbose, Error **errp) -+ bool verbose, bool verify, Error **errp) - { - assert(vmar); - assert(buf); -@@ -551,7 +565,7 @@ static int restore_extent(VmaReader *vmar, unsigned char *buf, - - if (dev_id != vmar->vmstate_stream) { - bs = rstate->bs; -- if (!bs) { -+ if (!verify && !bs) { - error_setg(errp, "got wrong dev id %d", dev_id); - return -1; - } -@@ -607,10 +621,13 @@ static int restore_extent(VmaReader *vmar, unsigned char *buf, - return -1; - } - -- int nb_sectors = end_sector - sector_num; -- if (restore_write_data(vmar, dev_id, bs, vmstate_fd, buf + start, -- sector_num, nb_sectors, errp) < 0) { -- return -1; -+ if (!verify) { -+ int nb_sectors = end_sector - sector_num; -+ if (restore_write_data(vmar, dev_id, bs, vmstate_fd, -+ buf + start, sector_num, nb_sectors, -+ errp) < 0) { -+ return -1; -+ } - } - - start += VMA_CLUSTER_SIZE; -@@ -640,26 +657,37 @@ static int restore_extent(VmaReader *vmar, unsigned char *buf, - return -1; - } - -- int nb_sectors = end_sector - sector_num; -- if (restore_write_data(vmar, dev_id, bs, vmstate_fd, -- buf + start, sector_num, -- nb_sectors, errp) < 0) { -- return -1; -+ if (!verify) { -+ int nb_sectors = end_sector - sector_num; -+ if (restore_write_data(vmar, dev_id, bs, vmstate_fd, -+ buf + start, sector_num, -+ nb_sectors, errp) < 0) { -+ return -1; -+ } - } - - start += VMA_BLOCK_SIZE; - - } else { - -- if (rstate->write_zeroes && (end_sector > sector_num)) { -+ -+ if (end_sector > sector_num) { - /* Todo: use bdrv_co_write_zeroes (but that need to - * be run inside coroutine?) - */ - int nb_sectors = end_sector - sector_num; -- if (restore_write_data(vmar, dev_id, bs, vmstate_fd, -- zero_vma_block, sector_num, -- nb_sectors, errp) < 0) { -- return -1; -+ int zero_size = BDRV_SECTOR_SIZE*nb_sectors; -+ vmar->zero_cluster_data += zero_size; -+ if (mask != 0) { -+ vmar->partial_zero_cluster_data += zero_size; -+ } -+ -+ if (rstate->write_zeroes && !verify) { -+ if (restore_write_data(vmar, dev_id, bs, vmstate_fd, -+ zero_vma_block, sector_num, -+ nb_sectors, errp) < 0) { -+ return -1; -+ } - } - } - } -@@ -677,8 +705,9 @@ static int restore_extent(VmaReader *vmar, unsigned char *buf, - return 0; - } - --int vma_reader_restore(VmaReader *vmar, int vmstate_fd, bool verbose, -- Error **errp) -+static int vma_reader_restore_full(VmaReader *vmar, int vmstate_fd, -+ bool verbose, bool verify, -+ Error **errp) - { - assert(vmar); - assert(vmar->head_data); -@@ -745,7 +774,7 @@ int vma_reader_restore(VmaReader *vmar, int vmstate_fd, bool verbose, - } - - if (restore_extent(vmar, buf, extent_size, vmstate_fd, verbose, -- errp) < 0) { -+ verify, errp) < 0) { - return -1; - } - -@@ -792,6 +821,38 @@ int vma_reader_restore(VmaReader *vmar, int vmstate_fd, bool verbose, - } - } - -+ 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 blocks %.3g%%\n", -+ (double)(100.0*vmar->partial_zero_cluster_data) / datasize); -+ } -+ } - return ret; - } - -+int vma_reader_restore(VmaReader *vmar, int vmstate_fd, bool verbose, -+ Error **errp) -+{ -+ return vma_reader_restore_full(vmar, vmstate_fd, verbose, false, errp); -+} -+ -+int vma_reader_verify(VmaReader *vmar, bool verbose, Error **errp) -+{ -+ guint8 dev_id; -+ -+ for (dev_id = 1; dev_id < 255; dev_id++) { -+ if (vma_reader_get_device_info(vmar, dev_id)) { -+ allocate_rstate(vmar, dev_id, NULL, false); -+ } -+ } -+ -+ return vma_reader_restore_full(vmar, -1, verbose, true, errp); -+} -+ -diff --git a/vma.c b/vma.c -index 8732bfa85e..ab7b766014 100644 ---- a/vma.c -+++ b/vma.c -@@ -29,6 +29,7 @@ static void help(void) - "vma list \n" - "vma create [-c config] pathname ...\n" - "vma extract [-r ] \n" -+ "vma verify [-v]\n" - ; - - printf("%s", help_msg); -@@ -333,6 +334,58 @@ static int extract_content(int argc, char **argv) - return ret; - } - -+static int verify_content(int argc, char **argv) -+{ -+ int c, ret = 0; -+ int verbose = 0; -+ const char *filename; -+ -+ for (;;) { -+ c = getopt(argc, argv, "hv"); -+ if (c == -1) { -+ break; -+ } -+ switch (c) { -+ case '?': -+ case 'h': -+ help(); -+ break; -+ case 'v': -+ verbose = 1; -+ break; -+ default: -+ help(); -+ } -+ } -+ -+ /* Get the filename */ -+ if ((optind + 1) != argc) { -+ help(); -+ } -+ filename = argv[optind++]; -+ -+ Error *errp = NULL; -+ VmaReader *vmar = vma_reader_create(filename, &errp); -+ -+ if (!vmar) { -+ g_error("%s", error_get_pretty(errp)); -+ } -+ -+ if (verbose) { -+ print_content(vmar); -+ } -+ -+ if (vma_reader_verify(vmar, verbose, &errp) < 0) { -+ g_error("verify failed - %s", error_get_pretty(errp)); -+ } -+ -+ vma_reader_destroy(vmar); -+ -+ bdrv_close_all(); -+ -+ return ret; -+} -+ - typedef struct BackupJob { - BlockDriverState *bs; - int64_t len; -@@ -579,6 +632,8 @@ int main(int argc, char **argv) - return create_archive(argc, argv); - } else if (!strcmp(cmdname, "extract")) { - return extract_content(argc, argv); -+ } else if (!strcmp(cmdname, "verify")) { -+ return verify_content(argc, argv); - } - - help(); -diff --git a/vma.h b/vma.h -index 6625eb95c6..9bb6ea4f69 100644 ---- a/vma.h -+++ b/vma.h -@@ -142,5 +142,6 @@ int vma_reader_register_bs(VmaReader *vmar, guint8 dev_id, - Error **errp); - int vma_reader_restore(VmaReader *vmar, int vmstate_fd, bool verbose, - Error **errp); -+int vma_reader_verify(VmaReader *vmar, bool verbose, Error **errp); - - #endif /* BACKUP_VMA_H */ --- -2.11.0 - diff --git a/debian/patches/pve/0025-smm_available-false.patch b/debian/patches/pve/0013-smm_available-false.patch similarity index 85% rename from debian/patches/pve/0025-smm_available-false.patch rename to debian/patches/pve/0013-smm_available-false.patch index 62d4ae1..a4a4599 100644 --- a/debian/patches/pve/0025-smm_available-false.patch +++ b/debian/patches/pve/0013-smm_available-false.patch @@ -1,7 +1,7 @@ -From 2d50e3a3e1eecb40c4935ee6c5808a823ae79440 Mon Sep 17 00:00:00 2001 +From 3afb3d14378cc401e37dafd8437cfc45cce2aaea Mon Sep 17 00:00:00 2001 From: Alexandre Derumier Date: Tue, 29 Sep 2015 15:37:44 +0200 -Subject: [PATCH 25/49] smm_available = false +Subject: [PATCH 13/28] smm_available = false Signed-off-by: Alexandre Derumier --- diff --git a/debian/patches/pve/0013-vma-add-config-command-to-dump-the-config.patch b/debian/patches/pve/0013-vma-add-config-command-to-dump-the-config.patch deleted file mode 100644 index 9dbe832..0000000 --- a/debian/patches/pve/0013-vma-add-config-command-to-dump-the-config.patch +++ /dev/null @@ -1,101 +0,0 @@ -From 7462043311f01c05c98a1f60f696ac4b465a7f38 Mon Sep 17 00:00:00 2001 -From: Wolfgang Bumiller -Date: Wed, 9 Dec 2015 14:46:49 +0100 -Subject: [PATCH 13/49] vma: add 'config' command to dump the config - ---- - vma.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 64 insertions(+) - -diff --git a/vma.c b/vma.c -index ab7b766014..89254070c4 100644 ---- a/vma.c -+++ b/vma.c -@@ -27,6 +27,7 @@ static void help(void) - "usage: vma command [command options]\n" - "\n" - "vma list \n" -+ "vma config [-c config]\n" - "vma create [-c config] pathname ...\n" - "vma extract [-r ] \n" - "vma verify [-v]\n" -@@ -605,6 +606,67 @@ static int create_archive(int argc, char **argv) - return 0; - } - -+static int dump_config(int argc, char **argv) -+{ -+ int c, ret = 0; -+ const char *filename; -+ const char *config_name = "qemu-server.conf"; -+ -+ for (;;) { -+ c = getopt(argc, argv, "hc:"); -+ if (c == -1) { -+ break; -+ } -+ switch (c) { -+ case '?': -+ case 'h': -+ help(); -+ break; -+ case 'c': -+ config_name = optarg; -+ break; -+ default: -+ help(); -+ } -+ } -+ -+ /* Get the filename */ -+ if ((optind + 1) != argc) { -+ help(); -+ } -+ filename = argv[optind++]; -+ -+ Error *errp = NULL; -+ VmaReader *vmar = vma_reader_create(filename, &errp); -+ -+ if (!vmar) { -+ g_error("%s", error_get_pretty(errp)); -+ } -+ -+ int found = 0; -+ GList *l = vma_reader_get_config_data(vmar); -+ while (l && l->data) { -+ VmaConfigData *cdata = (VmaConfigData *)l->data; -+ l = g_list_next(l); -+ if (strcmp(cdata->name, config_name) == 0) { -+ found = 1; -+ fwrite(cdata->data, cdata->len, 1, stdout); -+ break; -+ } -+ } -+ -+ vma_reader_destroy(vmar); -+ -+ bdrv_close_all(); -+ -+ if (!found) { -+ fprintf(stderr, "unable to find configuration data '%s'\n", config_name); -+ return -1; -+ } -+ -+ return ret; -+} -+ - int main(int argc, char **argv) - { - const char *cmdname; -@@ -634,6 +696,8 @@ int main(int argc, char **argv) - return extract_content(argc, argv); - } else if (!strcmp(cmdname, "verify")) { - return verify_content(argc, argv); -+ } else if (!strcmp(cmdname, "config")) { -+ return dump_config(argc, argv); - } - - help(); --- -2.11.0 - diff --git a/debian/patches/pve/0014-backup-modify-job-api.patch b/debian/patches/pve/0014-backup-modify-job-api.patch deleted file mode 100644 index 29d9bab..0000000 --- a/debian/patches/pve/0014-backup-modify-job-api.patch +++ /dev/null @@ -1,292 +0,0 @@ -From 18f7a9b94a81e794c66e6e9d1ca7a9dafb1d17cb Mon Sep 17 00:00:00 2001 -From: Wolfgang Bumiller -Date: Wed, 9 Dec 2015 15:04:57 +0100 -Subject: [PATCH 14/49] backup: modify job api - -Introduces a BackupDump function callback and a pause_count -for backup_start. For a dump-backup the target parameter -can now be NULL so access to target needs to be guarded now. ---- - block/backup.c | 118 +++++++++++++++++++++++++++++----------------- - block/replication.c | 3 +- - blockdev.c | 4 +- - include/block/block_int.h | 5 ++ - 4 files changed, 83 insertions(+), 47 deletions(-) - -diff --git a/block/backup.c b/block/backup.c -index a4fb2884f9..fe4ce7f504 100644 ---- a/block/backup.c -+++ b/block/backup.c -@@ -36,6 +36,7 @@ typedef struct BackupBlockJob { - BdrvDirtyBitmap *sync_bitmap; - MirrorSyncMode sync_mode; - RateLimit limit; -+ BackupDumpFunc *dump_cb; - BlockdevOnError on_source_error; - BlockdevOnError on_target_error; - CoRwlock flush_rwlock; -@@ -145,13 +146,24 @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job, - goto out; - } - -+ int64_t start_sec = start * sectors_per_cluster; - if (buffer_is_zero(iov.iov_base, iov.iov_len)) { -- ret = blk_co_pwrite_zeroes(job->target, start * job->cluster_size, -- bounce_qiov.size, BDRV_REQ_MAY_UNMAP); -+ if (job->dump_cb) { -+ ret = job->dump_cb(job->common.opaque, job->target, start_sec, n, NULL); -+ } -+ if (job->target) { -+ ret = blk_co_pwrite_zeroes(job->target, start * job->cluster_size, -+ bounce_qiov.size, BDRV_REQ_MAY_UNMAP); -+ } - } else { -- ret = blk_co_pwritev(job->target, start * job->cluster_size, -- bounce_qiov.size, &bounce_qiov, -- job->compress ? BDRV_REQ_WRITE_COMPRESSED : 0); -+ if (job->dump_cb) { -+ ret = job->dump_cb(job->common.opaque, job->target, start_sec, n, bounce_buffer); -+ } -+ if (job->target) { -+ ret = blk_co_pwritev(job->target, start * job->cluster_size, -+ bounce_qiov.size, &bounce_qiov, -+ job->compress ? BDRV_REQ_WRITE_COMPRESSED : 0); -+ } - } - if (ret < 0) { - trace_backup_do_cow_write_fail(job, start, ret); -@@ -246,6 +258,8 @@ static void backup_abort(BlockJob *job) - static void backup_clean(BlockJob *job) - { - BackupBlockJob *s = container_of(job, BackupBlockJob, common); -+ if (!s->target) -+ return; - assert(s->target); - blk_unref(s->target); - s->target = NULL; -@@ -330,9 +344,11 @@ static BlockErrorAction backup_error_action(BackupBlockJob *job, - if (read) { - return block_job_error_action(&job->common, job->on_source_error, - true, error); -- } else { -+ } else if (job->target) { - return block_job_error_action(&job->common, job->on_target_error, - false, error); -+ } else { -+ return BLOCK_ERROR_ACTION_REPORT; - } - } - -@@ -453,6 +469,7 @@ static void coroutine_fn backup_run(void *opaque) - - job->done_bitmap = bitmap_new(end); - -+ - job->before_write.notify = backup_before_write_notify; - bdrv_add_before_write_notifier(bs, &job->before_write); - -@@ -557,7 +574,9 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, - BlockdevOnError on_source_error, - BlockdevOnError on_target_error, - int creation_flags, -+ BackupDumpFunc *dump_cb, - BlockCompletionFunc *cb, void *opaque, -+ int pause_count, - BlockJobTxn *txn, Error **errp) - { - int64_t len; -@@ -566,7 +585,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, - int ret; - - assert(bs); -- assert(target); -+ assert(target || dump_cb); - - if (bs == target) { - error_setg(errp, "Source and target cannot be the same"); -@@ -579,13 +598,13 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, - return NULL; - } - -- if (!bdrv_is_inserted(target)) { -+ if (target && !bdrv_is_inserted(target)) { - error_setg(errp, "Device is not inserted: %s", - bdrv_get_device_name(target)); - return NULL; - } - -- if (compress && target->drv->bdrv_co_pwritev_compressed == NULL) { -+ if (target && compress && target->drv->bdrv_co_pwritev_compressed == NULL) { - error_setg(errp, "Compression is not supported for this drive %s", - bdrv_get_device_name(target)); - return NULL; -@@ -595,7 +614,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, - return NULL; - } - -- if (bdrv_op_is_blocked(target, BLOCK_OP_TYPE_BACKUP_TARGET, errp)) { -+ if (target && bdrv_op_is_blocked(target, BLOCK_OP_TYPE_BACKUP_TARGET, errp)) { - return NULL; - } - -@@ -635,15 +654,18 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, - goto error; - } - -- /* The target must match the source in size, so no resize here either */ -- job->target = blk_new(BLK_PERM_WRITE, -- BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | -- BLK_PERM_WRITE_UNCHANGED | BLK_PERM_GRAPH_MOD); -- ret = blk_insert_bs(job->target, target, errp); -- if (ret < 0) { -- goto error; -+ if (target) { -+ /* The target must match the source in size, so no resize here either */ -+ job->target = blk_new(BLK_PERM_WRITE, -+ BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | -+ BLK_PERM_WRITE_UNCHANGED | BLK_PERM_GRAPH_MOD); -+ ret = blk_insert_bs(job->target, target, errp); -+ if (ret < 0) { -+ goto error; -+ } - } - -+ job->dump_cb = dump_cb; - job->on_source_error = on_source_error; - job->on_target_error = on_target_error; - job->sync_mode = sync_mode; -@@ -651,36 +673,44 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, - sync_bitmap : NULL; - job->compress = compress; - -- /* If there is no backing file on the target, we cannot rely on COW if our -- * backup cluster size is smaller than the target cluster size. Even for -- * targets with a backing file, try to avoid COW if possible. */ -- ret = bdrv_get_info(target, &bdi); -- if (ret == -ENOTSUP && !target->backing) { -- /* Cluster size is not defined */ -- error_report("WARNING: The target block device doesn't provide " -- "information about the block size and it doesn't have a " -- "backing file. The default block size of %u bytes is " -- "used. If the actual block size of the target exceeds " -- "this default, the backup may be unusable", -- BACKUP_CLUSTER_SIZE_DEFAULT); -- job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT; -- } else if (ret < 0 && !target->backing) { -- error_setg_errno(errp, -ret, -- "Couldn't determine the cluster size of the target image, " -- "which has no backing file"); -- error_append_hint(errp, -- "Aborting, since this may create an unusable destination image\n"); -- goto error; -- } else if (ret < 0 && target->backing) { -- /* Not fatal; just trudge on ahead. */ -- job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT; -+ if (target) { -+ /* If there is no backing file on the target, we cannot rely on COW if our -+ * backup cluster size is smaller than the target cluster size. Even for -+ * targets with a backing file, try to avoid COW if possible. */ -+ ret = bdrv_get_info(target, &bdi); -+ if (ret == -ENOTSUP && !target->backing) { -+ /* Cluster size is not defined */ -+ error_report("WARNING: The target block device doesn't provide " -+ "information about the block size and it doesn't have a " -+ "backing file. The default block size of %u bytes is " -+ "used. If the actual block size of the target exceeds " -+ "this default, the backup may be unusable", -+ BACKUP_CLUSTER_SIZE_DEFAULT); -+ job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT; -+ } else if (ret < 0 && !target->backing) { -+ error_setg_errno(errp, -ret, -+ "Couldn't determine the cluster size of the target image, " -+ "which has no backing file"); -+ error_append_hint(errp, -+ "Aborting, since this may create an unusable destination image\n"); -+ goto error; -+ } else if (ret < 0 && target->backing) { -+ /* Not fatal; just trudge on ahead. */ -+ job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT; -+ } else { -+ job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT; -+ } - } else { -- job->cluster_size = MAX(BACKUP_CLUSTER_SIZE_DEFAULT, bdi.cluster_size); -+ job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT; - } - -- /* Required permissions are already taken with target's blk_new() */ -- block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL, -- &error_abort); -+ if (target) { -+ /* Required permissions are already taken with target's blk_new() */ -+ block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL, -+ &error_abort); -+ } else { -+ job->common.pause_count = pause_count; -+ } - job->common.len = len; - block_job_txn_add_job(txn, &job->common); - -diff --git a/block/replication.c b/block/replication.c -index bf3c395eb4..60c6524417 100644 ---- a/block/replication.c -+++ b/block/replication.c -@@ -531,7 +531,8 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, - 0, MIRROR_SYNC_MODE_NONE, NULL, false, - BLOCKDEV_ON_ERROR_REPORT, - BLOCKDEV_ON_ERROR_REPORT, BLOCK_JOB_INTERNAL, -- backup_job_completed, bs, NULL, &local_err); -+ NULL, -+ backup_job_completed, bs, 0, NULL, &local_err); - if (local_err) { - error_propagate(errp, local_err); - backup_job_cleanup(bs); -diff --git a/blockdev.c b/blockdev.c -index 4927914ce3..5ddd363a33 100644 ---- a/blockdev.c -+++ b/blockdev.c -@@ -3273,7 +3273,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup, BlockJobTxn *txn, - job = backup_job_create(backup->job_id, bs, target_bs, backup->speed, - backup->sync, bmap, backup->compress, - backup->on_source_error, backup->on_target_error, -- BLOCK_JOB_DEFAULT, NULL, NULL, txn, &local_err); -+ BLOCK_JOB_DEFAULT, NULL, NULL, NULL, 0, txn, &local_err); - bdrv_unref(target_bs); - if (local_err != NULL) { - error_propagate(errp, local_err); -@@ -3352,7 +3352,7 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn, - job = backup_job_create(backup->job_id, bs, target_bs, backup->speed, - backup->sync, NULL, backup->compress, - backup->on_source_error, backup->on_target_error, -- BLOCK_JOB_DEFAULT, NULL, NULL, txn, &local_err); -+ BLOCK_JOB_DEFAULT, NULL, NULL, NULL, 0, txn, &local_err); - if (local_err != NULL) { - error_propagate(errp, local_err); - } -diff --git a/include/block/block_int.h b/include/block/block_int.h -index 59400bd848..ec655815ca 100644 ---- a/include/block/block_int.h -+++ b/include/block/block_int.h -@@ -59,6 +59,9 @@ - - #define BLOCK_PROBE_BUF_SIZE 512 - -+typedef int BackupDumpFunc(void *opaque, BlockDriverState *bs, -+ int64_t sector_num, int n_sectors, unsigned char *buf); -+ - enum BdrvTrackedRequestType { - BDRV_TRACKED_READ, - BDRV_TRACKED_WRITE, -@@ -877,7 +880,9 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, - BlockdevOnError on_source_error, - BlockdevOnError on_target_error, - int creation_flags, -+ BackupDumpFunc *dump_cb, - BlockCompletionFunc *cb, void *opaque, -+ int pause_count, - BlockJobTxn *txn, Error **errp); - - void hmp_drive_add_node(Monitor *mon, const char *optstr); --- -2.11.0 - diff --git a/debian/patches/pve/0026-use-whitespace-between-VERSION-and-PKGVERSION.patch b/debian/patches/pve/0014-use-whitespace-between-VERSION-and-PKGVERSION.patch similarity index 83% rename from debian/patches/pve/0026-use-whitespace-between-VERSION-and-PKGVERSION.patch rename to debian/patches/pve/0014-use-whitespace-between-VERSION-and-PKGVERSION.patch index 3d3e100..c0e5d67 100644 --- a/debian/patches/pve/0026-use-whitespace-between-VERSION-and-PKGVERSION.patch +++ b/debian/patches/pve/0014-use-whitespace-between-VERSION-and-PKGVERSION.patch @@ -1,7 +1,7 @@ -From 907dfd6792ab3e5030c859e1bd857f0127515e5c Mon Sep 17 00:00:00 2001 +From 8f6787a80cafc259d2247a294ea657aee0928488 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Wed, 9 Dec 2015 16:50:05 +0100 -Subject: [PATCH 26/49] use whitespace between VERSION and PKGVERSION +Subject: [PATCH 14/28] use whitespace between VERSION and PKGVERSION Our kvm version parser expects a white space or comma after the version string, see PVE::QemuServer::kvm_user_version() diff --git a/debian/patches/pve/0015-backup-add-pve-monitor-commands.patch b/debian/patches/pve/0015-backup-add-pve-monitor-commands.patch deleted file mode 100644 index e1c3cf9..0000000 --- a/debian/patches/pve/0015-backup-add-pve-monitor-commands.patch +++ /dev/null @@ -1,830 +0,0 @@ -From 4919cc7182665534c0ba82203b10a6ead1d41d03 Mon Sep 17 00:00:00 2001 -From: Wolfgang Bumiller -Date: Wed, 9 Dec 2015 15:20:56 +0100 -Subject: [PATCH 15/49] backup: add pve monitor commands - ---- - blockdev.c | 465 ++++++++++++++++++++++++++++++++++++++++++++++ - blockjob.c | 11 +- - hmp-commands-info.hx | 13 ++ - hmp-commands.hx | 29 +++ - hmp.c | 61 ++++++ - hmp.h | 3 + - include/block/block_int.h | 2 +- - qapi-schema.json | 90 +++++++++ - 8 files changed, 668 insertions(+), 6 deletions(-) - -diff --git a/blockdev.c b/blockdev.c -index 5ddd363a33..58cf5d3c80 100644 ---- a/blockdev.c -+++ b/blockdev.c -@@ -35,6 +35,7 @@ - #include "sysemu/blockdev.h" - #include "hw/block/block.h" - #include "block/blockjob.h" -+#include "block/blockjob_int.h" - #include "block/throttle-groups.h" - #include "monitor/monitor.h" - #include "qemu/error-report.h" -@@ -53,6 +54,7 @@ - #include "qemu/cutils.h" - #include "qemu/help_option.h" - #include "qemu/throttle-options.h" -+#include "vma.h" - - static QTAILQ_HEAD(, BlockDriverState) monitor_bdrv_states = - QTAILQ_HEAD_INITIALIZER(monitor_bdrv_states); -@@ -2956,6 +2958,469 @@ out: - aio_context_release(aio_context); - } - -+void block_job_event_cancelled(BlockJob *job); -+void block_job_event_completed(BlockJob *job, const char *msg); -+static void block_job_cb(void *opaque, int ret) -+{ -+ /* Note that this function may be executed from another AioContext besides -+ * the QEMU main loop. If you need to access anything that assumes the -+ * QEMU global mutex, use a BH or introduce a mutex. -+ */ -+ -+ BlockDriverState *bs = opaque; -+ const char *msg = NULL; -+ -+ assert(bs->job); -+ -+ if (ret < 0) { -+ msg = strerror(-ret); -+ } -+ -+ if (block_job_is_cancelled(bs->job)) { -+ block_job_event_cancelled(bs->job); -+ } else { -+ block_job_event_completed(bs->job, msg); -+ } -+} -+ -+/* PVE backup related function */ -+ -+static struct PVEBackupState { -+ Error *error; -+ bool cancel; -+ uuid_t uuid; -+ char uuid_str[37]; -+ int64_t speed; -+ time_t start_time; -+ time_t end_time; -+ char *backup_file; -+ VmaWriter *vmaw; -+ GList *di_list; -+ size_t total; -+ size_t transferred; -+ size_t zero_bytes; -+} backup_state; -+ -+typedef struct PVEBackupDevInfo { -+ BlockDriverState *bs; -+ size_t size; -+ uint8_t dev_id; -+ //bool started; -+ bool completed; -+} PVEBackupDevInfo; -+ -+static void pvebackup_run_next_job(void); -+ -+static int pvebackup_dump_cb(void *opaque, BlockBackend *target, -+ int64_t sector_num, int n_sectors, -+ unsigned char *buf) -+{ -+ PVEBackupDevInfo *di = opaque; -+ -+ if (sector_num & 0x7f) { -+ if (!backup_state.error) { -+ error_setg(&backup_state.error, -+ "got unaligned write inside backup dump " -+ "callback (sector %ld)", sector_num); -+ } -+ return -1; // not aligned to cluster size -+ } -+ -+ int64_t cluster_num = sector_num >> 7; -+ int size = n_sectors * BDRV_SECTOR_SIZE; -+ -+ int ret = -1; -+ -+ if (backup_state.vmaw) { -+ size_t zero_bytes = 0; -+ ret = vma_writer_write(backup_state.vmaw, di->dev_id, cluster_num, -+ buf, &zero_bytes); -+ backup_state.zero_bytes += zero_bytes; -+ } else { -+ ret = size; -+ if (!buf) { -+ backup_state.zero_bytes += size; -+ } -+ } -+ -+ backup_state.transferred += size; -+ -+ return ret; -+} -+ -+static void pvebackup_cleanup(void) -+{ -+ backup_state.end_time = time(NULL); -+ -+ if (backup_state.vmaw) { -+ Error *local_err = NULL; -+ vma_writer_close(backup_state.vmaw, &local_err); -+ error_propagate(&backup_state.error, local_err); -+ backup_state.vmaw = NULL; -+ } -+ -+ if (backup_state.di_list) { -+ GList *l = backup_state.di_list; -+ while (l) { -+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; -+ l = g_list_next(l); -+ g_free(di); -+ } -+ g_list_free(backup_state.di_list); -+ backup_state.di_list = NULL; -+ } -+} -+ -+static void pvebackup_complete_cb(void *opaque, int ret) -+{ -+ PVEBackupDevInfo *di = opaque; -+ -+ assert(backup_state.vmaw); -+ -+ di->completed = true; -+ -+ if (ret < 0 && !backup_state.error) { -+ error_setg(&backup_state.error, "job failed with err %d - %s", -+ ret, strerror(-ret)); -+ } -+ -+ BlockDriverState *bs = di->bs; -+ -+ di->bs = NULL; -+ -+ vma_writer_close_stream(backup_state.vmaw, di->dev_id); -+ -+ block_job_cb(bs, ret); -+ -+ if (!backup_state.cancel) { -+ pvebackup_run_next_job(); -+ } -+} -+ -+static void pvebackup_cancel(void *opaque) -+{ -+ backup_state.cancel = true; -+ -+ if (!backup_state.error) { -+ error_setg(&backup_state.error, "backup cancelled"); -+ } -+ -+ /* drain all i/o (awake jobs waiting for aio) */ -+ bdrv_drain_all(); -+ -+ GList *l = backup_state.di_list; -+ while (l) { -+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; -+ l = g_list_next(l); -+ if (!di->completed && di->bs) { -+ BlockJob *job = di->bs->job; -+ if (job) { -+ if (!di->completed) { -+ block_job_cancel_sync(job); -+ } -+ } -+ } -+ } -+ -+ pvebackup_cleanup(); -+} -+ -+void qmp_backup_cancel(Error **errp) -+{ -+ Coroutine *co = qemu_coroutine_create(pvebackup_cancel, NULL); -+ qemu_coroutine_enter(co); -+ -+ while (backup_state.vmaw) { -+ /* vma writer use main aio context */ -+ aio_poll(qemu_get_aio_context(), true); -+ } -+} -+ -+bool block_job_should_pause(BlockJob *job); -+static void pvebackup_run_next_job(void) -+{ -+ GList *l = backup_state.di_list; -+ while (l) { -+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; -+ l = g_list_next(l); -+ if (!di->completed && di->bs && di->bs->job) { -+ BlockJob *job = di->bs->job; -+ if (block_job_should_pause(job)) { -+ bool cancel = backup_state.error || backup_state.cancel; -+ if (cancel) { -+ block_job_cancel(job); -+ } else { -+ block_job_resume(job); -+ } -+ } -+ return; -+ } -+ } -+ -+ pvebackup_cleanup(); -+} -+ -+UuidInfo *qmp_backup(const char *backup_file, bool has_format, -+ BackupFormat format, -+ bool has_config_file, const char *config_file, -+ bool has_devlist, const char *devlist, -+ bool has_speed, int64_t speed, Error **errp) -+{ -+ BlockBackend *blk; -+ BlockDriverState *bs = NULL; -+ Error *local_err = NULL; -+ uuid_t uuid; -+ VmaWriter *vmaw = NULL; -+ gchar **devs = NULL; -+ GList *di_list = NULL; -+ GList *l; -+ UuidInfo *uuid_info; -+ -+ if (backup_state.di_list) { -+ error_set(errp, ERROR_CLASS_GENERIC_ERROR, -+ "previous backup not finished"); -+ return NULL; -+ } -+ -+ /* Todo: try to auto-detect format based on file name */ -+ format = has_format ? format : BACKUP_FORMAT_VMA; -+ -+ if (format != BACKUP_FORMAT_VMA) { -+ error_set(errp, ERROR_CLASS_GENERIC_ERROR, "unknown backup format"); -+ return NULL; -+ } -+ -+ if (has_devlist) { -+ devs = g_strsplit_set(devlist, ",;:", -1); -+ -+ gchar **d = devs; -+ while (d && *d) { -+ blk = blk_by_name(*d); -+ if (blk) { -+ bs = blk_bs(blk); -+ if (bdrv_is_read_only(bs)) { -+ error_setg(errp, "Node '%s' is read only", *d); -+ goto err; -+ } -+ if (!bdrv_is_inserted(bs)) { -+ error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, *d); -+ goto err; -+ } -+ PVEBackupDevInfo *di = g_new0(PVEBackupDevInfo, 1); -+ di->bs = bs; -+ di_list = g_list_append(di_list, di); -+ } else { -+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, -+ "Device '%s' not found", *d); -+ goto err; -+ } -+ d++; -+ } -+ -+ } else { -+ BdrvNextIterator it; -+ -+ bs = NULL; -+ for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { -+ if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) { -+ continue; -+ } -+ -+ PVEBackupDevInfo *di = g_new0(PVEBackupDevInfo, 1); -+ di->bs = bs; -+ di_list = g_list_append(di_list, di); -+ } -+ } -+ -+ if (!di_list) { -+ error_set(errp, ERROR_CLASS_GENERIC_ERROR, "empty device list"); -+ goto err; -+ } -+ -+ size_t total = 0; -+ -+ l = di_list; -+ while (l) { -+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; -+ l = g_list_next(l); -+ if (bdrv_op_is_blocked(di->bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) { -+ goto err; -+ } -+ -+ ssize_t size = bdrv_getlength(di->bs); -+ if (size < 0) { -+ error_setg_errno(errp, -di->size, "bdrv_getlength failed"); -+ goto err; -+ } -+ di->size = size; -+ total += size; -+ } -+ -+ uuid_generate(uuid); -+ -+ vmaw = vma_writer_create(backup_file, uuid, &local_err); -+ if (!vmaw) { -+ if (local_err) { -+ error_propagate(errp, local_err); -+ } -+ goto err; -+ } -+ -+ /* register all devices for vma writer */ -+ l = di_list; -+ while (l) { -+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; -+ l = g_list_next(l); -+ -+ const char *devname = bdrv_get_device_name(di->bs); -+ di->dev_id = vma_writer_register_stream(vmaw, devname, di->size); -+ if (di->dev_id <= 0) { -+ error_set(errp, ERROR_CLASS_GENERIC_ERROR, -+ "register_stream failed"); -+ goto err; -+ } -+ } -+ -+ /* add configuration file to archive */ -+ if (has_config_file) { -+ char *cdata = NULL; -+ gsize clen = 0; -+ GError *err = NULL; -+ if (!g_file_get_contents(config_file, &cdata, &clen, &err)) { -+ error_setg(errp, "unable to read file '%s'", config_file); -+ goto err; -+ } -+ -+ const char *basename = g_path_get_basename(config_file); -+ if (vma_writer_add_config(vmaw, basename, cdata, clen) != 0) { -+ error_setg(errp, "unable to add config data to vma archive"); -+ g_free(cdata); -+ goto err; -+ } -+ g_free(cdata); -+ } -+ -+ /* initialize global backup_state now */ -+ -+ backup_state.cancel = false; -+ -+ if (backup_state.error) { -+ error_free(backup_state.error); -+ backup_state.error = NULL; -+ } -+ -+ backup_state.speed = (has_speed && speed > 0) ? speed : 0; -+ -+ backup_state.start_time = time(NULL); -+ backup_state.end_time = 0; -+ -+ if (backup_state.backup_file) { -+ g_free(backup_state.backup_file); -+ } -+ backup_state.backup_file = g_strdup(backup_file); -+ -+ backup_state.vmaw = vmaw; -+ -+ uuid_copy(backup_state.uuid, uuid); -+ uuid_unparse_lower(uuid, backup_state.uuid_str); -+ -+ backup_state.di_list = di_list; -+ -+ backup_state.total = total; -+ backup_state.transferred = 0; -+ backup_state.zero_bytes = 0; -+ -+ /* start all jobs (paused state) */ -+ l = di_list; -+ while (l) { -+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; -+ l = g_list_next(l); -+ -+ backup_job_create(NULL, di->bs, NULL, speed, MIRROR_SYNC_MODE_FULL, NULL, -+ BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT, -+ pvebackup_dump_cb, pvebackup_complete_cb, di, -+ 1, NULL, &local_err); -+ if (local_err != NULL) { -+ error_setg(&backup_state.error, "backup_job_create failed"); -+ pvebackup_cancel(NULL); -+ } -+ } -+ -+ if (!backup_state.error) { -+ pvebackup_run_next_job(); // run one job -+ } -+ -+ uuid_info = g_malloc0(sizeof(*uuid_info)); -+ uuid_info->UUID = g_strdup(backup_state.uuid_str); -+ return uuid_info; -+ -+err: -+ -+ l = di_list; -+ while (l) { -+ g_free(l->data); -+ l = g_list_next(l); -+ } -+ g_list_free(di_list); -+ -+ if (devs) { -+ g_strfreev(devs); -+ } -+ -+ if (vmaw) { -+ Error *err = NULL; -+ vma_writer_close(vmaw, &err); -+ unlink(backup_file); -+ } -+ -+ return NULL; -+} -+ -+BackupStatus *qmp_query_backup(Error **errp) -+{ -+ BackupStatus *info = g_malloc0(sizeof(*info)); -+ -+ if (!backup_state.start_time) { -+ /* not started, return {} */ -+ return info; -+ } -+ -+ info->has_status = true; -+ info->has_start_time = true; -+ info->start_time = backup_state.start_time; -+ -+ if (backup_state.backup_file) { -+ info->has_backup_file = true; -+ info->backup_file = g_strdup(backup_state.backup_file); -+ } -+ -+ info->has_uuid = true; -+ info->uuid = g_strdup(backup_state.uuid_str); -+ -+ if (backup_state.end_time) { -+ if (backup_state.error) { -+ info->status = g_strdup("error"); -+ info->has_errmsg = true; -+ info->errmsg = g_strdup(error_get_pretty(backup_state.error)); -+ } else { -+ info->status = g_strdup("done"); -+ } -+ info->has_end_time = true; -+ info->end_time = backup_state.end_time; -+ } else { -+ info->status = g_strdup("active"); -+ } -+ -+ info->has_total = true; -+ info->total = backup_state.total; -+ info->has_zero_bytes = true; -+ info->zero_bytes = backup_state.zero_bytes; -+ info->has_transferred = true; -+ info->transferred = backup_state.transferred; -+ -+ return info; -+} -+ - void qmp_block_stream(bool has_job_id, const char *job_id, const char *device, - bool has_base, const char *base, - bool has_base_node, const char *base_node, -diff --git a/blockjob.c b/blockjob.c -index 6e489327ff..2162b4d3d8 100644 ---- a/blockjob.c -+++ b/blockjob.c -@@ -37,8 +37,8 @@ - #include "qemu/timer.h" - #include "qapi-event.h" - --static void block_job_event_cancelled(BlockJob *job); --static void block_job_event_completed(BlockJob *job, const char *msg); -+void block_job_event_cancelled(BlockJob *job); -+void block_job_event_completed(BlockJob *job, const char *msg); - - /* Transactional group of block jobs */ - struct BlockJobTxn { -@@ -473,7 +473,8 @@ void block_job_user_pause(BlockJob *job) - block_job_pause(job); - } - --static bool block_job_should_pause(BlockJob *job) -+bool block_job_should_pause(BlockJob *job); -+bool block_job_should_pause(BlockJob *job) - { - return job->pause_count > 0; - } -@@ -687,7 +688,7 @@ static void block_job_iostatus_set_err(BlockJob *job, int error) - } - } - --static void block_job_event_cancelled(BlockJob *job) -+void block_job_event_cancelled(BlockJob *job) - { - if (block_job_is_internal(job)) { - return; -@@ -701,7 +702,7 @@ static void block_job_event_cancelled(BlockJob *job) - &error_abort); - } - --static void block_job_event_completed(BlockJob *job, const char *msg) -+void block_job_event_completed(BlockJob *job, const char *msg) - { - if (block_job_is_internal(job)) { - return; -diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx -index a53f105c52..1a1838099f 100644 ---- a/hmp-commands-info.hx -+++ b/hmp-commands-info.hx -@@ -487,6 +487,19 @@ STEXI - Show CPU statistics. - ETEXI - -+ { -+ .name = "backup", -+ .args_type = "", -+ .params = "", -+ .help = "show backup status", -+ .cmd = hmp_info_backup, -+ }, -+ -+STEXI -+@item info backup -+show backup status -+ETEXI -+ - #if defined(CONFIG_SLIRP) - { - .name = "usernet", -diff --git a/hmp-commands.hx b/hmp-commands.hx -index 88192817b2..aea39d0f45 100644 ---- a/hmp-commands.hx -+++ b/hmp-commands.hx -@@ -87,6 +87,35 @@ STEXI - Copy data from a backing file into a block device. - ETEXI - -+ { -+ .name = "backup", -+ .args_type = "backupfile:s,speed:o?,devlist:s?", -+ .params = "backupfile [speed [devlist]]", -+ .help = "create a VM Backup.", -+ .cmd = hmp_backup, -+ }, -+ -+STEXI -+@item backup -+@findex backup -+Create a VM backup. -+ETEXI -+ -+ { -+ .name = "backup_cancel", -+ .args_type = "", -+ .params = "", -+ .help = "cancel the current VM backup", -+ .cmd = hmp_backup_cancel, -+ }, -+ -+STEXI -+@item backup_cancel -+@findex backup_cancel -+Cancel the current VM backup. -+ -+ETEXI -+ - { - .name = "block_job_set_speed", - .args_type = "device:B,speed:o", -diff --git a/hmp.c b/hmp.c -index 904542d026..c685ba507f 100644 ---- a/hmp.c -+++ b/hmp.c -@@ -151,6 +151,44 @@ void hmp_info_mice(Monitor *mon, const QDict *qdict) - qapi_free_MouseInfoList(mice_list); - } - -+void hmp_info_backup(Monitor *mon, const QDict *qdict) -+{ -+ BackupStatus *info; -+ -+ info = qmp_query_backup(NULL); -+ if (info->has_status) { -+ if (info->has_errmsg) { -+ monitor_printf(mon, "Backup status: %s - %s\n", -+ info->status, info->errmsg); -+ } else { -+ monitor_printf(mon, "Backup status: %s\n", info->status); -+ } -+ } -+ -+ if (info->has_backup_file) { -+ monitor_printf(mon, "Start time: %s", ctime(&info->start_time)); -+ if (info->end_time) { -+ monitor_printf(mon, "End time: %s", ctime(&info->end_time)); -+ } -+ -+ int per = (info->has_total && info->total && -+ info->has_transferred && info->transferred) ? -+ (info->transferred * 100)/info->total : 0; -+ int zero_per = (info->has_total && info->total && -+ info->has_zero_bytes && info->zero_bytes) ? -+ (info->zero_bytes * 100)/info->total : 0; -+ monitor_printf(mon, "Backup file: %s\n", info->backup_file); -+ monitor_printf(mon, "Backup uuid: %s\n", info->uuid); -+ monitor_printf(mon, "Total size: %zd\n", info->total); -+ monitor_printf(mon, "Transferred bytes: %zd (%d%%)\n", -+ info->transferred, per); -+ monitor_printf(mon, "Zero bytes: %zd (%d%%)\n", -+ info->zero_bytes, zero_per); -+ } -+ -+ qapi_free_BackupStatus(info); -+} -+ - void hmp_info_migrate(Monitor *mon, const QDict *qdict) - { - MigrationInfo *info; -@@ -1613,6 +1651,29 @@ void hmp_block_stream(Monitor *mon, const QDict *qdict) - hmp_handle_error(mon, &error); - } - -+void hmp_backup_cancel(Monitor *mon, const QDict *qdict) -+{ -+ Error *error = NULL; -+ -+ qmp_backup_cancel(&error); -+ -+ hmp_handle_error(mon, &error); -+} -+ -+void hmp_backup(Monitor *mon, const QDict *qdict) -+{ -+ Error *error = NULL; -+ -+ const char *backup_file = qdict_get_str(qdict, "backupfile"); -+ const char *devlist = qdict_get_try_str(qdict, "devlist"); -+ int64_t speed = qdict_get_try_int(qdict, "speed", 0); -+ -+ qmp_backup(backup_file, true, BACKUP_FORMAT_VMA, false, NULL, !!devlist, -+ devlist, qdict_haskey(qdict, "speed"), speed, &error); -+ -+ hmp_handle_error(mon, &error); -+} -+ - void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict) - { - Error *error = NULL; -diff --git a/hmp.h b/hmp.h -index 799fd371fa..17a65b2313 100644 ---- a/hmp.h -+++ b/hmp.h -@@ -30,6 +30,7 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict); - void hmp_info_migrate_capabilities(Monitor *mon, const QDict *qdict); - void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict); - void hmp_info_migrate_cache_size(Monitor *mon, const QDict *qdict); -+void hmp_info_backup(Monitor *mon, const QDict *qdict); - void hmp_info_cpus(Monitor *mon, const QDict *qdict); - void hmp_info_block(Monitor *mon, const QDict *qdict); - void hmp_info_blockstats(Monitor *mon, const QDict *qdict); -@@ -79,6 +80,8 @@ void hmp_eject(Monitor *mon, const QDict *qdict); - void hmp_change(Monitor *mon, const QDict *qdict); - void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict); - void hmp_block_stream(Monitor *mon, const QDict *qdict); -+void hmp_backup(Monitor *mon, const QDict *qdict); -+void hmp_backup_cancel(Monitor *mon, const QDict *qdict); - void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict); - void hmp_block_job_cancel(Monitor *mon, const QDict *qdict); - void hmp_block_job_pause(Monitor *mon, const QDict *qdict); -diff --git a/include/block/block_int.h b/include/block/block_int.h -index ec655815ca..278da161fb 100644 ---- a/include/block/block_int.h -+++ b/include/block/block_int.h -@@ -59,7 +59,7 @@ - - #define BLOCK_PROBE_BUF_SIZE 512 - --typedef int BackupDumpFunc(void *opaque, BlockDriverState *bs, -+typedef int BackupDumpFunc(void *opaque, BlockBackend *be, - int64_t sector_num, int n_sectors, unsigned char *buf); - - enum BdrvTrackedRequestType { -diff --git a/qapi-schema.json b/qapi-schema.json -index 1b14ff2476..12d4d20705 100644 ---- a/qapi-schema.json -+++ b/qapi-schema.json -@@ -570,6 +570,96 @@ - { 'command': 'query-events', 'returns': ['EventInfo'] } - - ## -+# @BackupStatus: -+# -+# Detailed backup status. -+# -+# @status: string describing the current backup status. -+# This can be 'active', 'done', 'error'. If this field is not -+# returned, no backup process has been initiated -+# -+# @errmsg: error message (only returned if status is 'error') -+# -+# @total: total amount of bytes involved in the backup process -+# -+# @transferred: amount of bytes already backed up. -+# -+# @zero-bytes: amount of 'zero' bytes detected. -+# -+# @start-time: time (epoch) when backup job started. -+# -+# @end-time: time (epoch) when backup job finished. -+# -+# @backup-file: backup file name -+# -+# @uuid: uuid for this backup job -+# -+## -+{ 'struct': 'BackupStatus', -+ 'data': {'*status': 'str', '*errmsg': 'str', '*total': 'int', -+ '*transferred': 'int', '*zero-bytes': 'int', -+ '*start-time': 'int', '*end-time': 'int', -+ '*backup-file': 'str', '*uuid': 'str' } } -+ -+## -+# @BackupFormat: -+# -+# An enumeration of supported backup formats. -+# -+# @vma: Proxmox vma backup format -+## -+{ 'enum': 'BackupFormat', -+ 'data': [ 'vma' ] } -+ -+## -+# @backup: -+# -+# Starts a VM backup. -+# -+# @backup-file: the backup file name -+# -+# @format: format of the backup file -+# -+# @config-file: a configuration file to include into -+# the backup archive. -+# -+# @speed: the maximum speed, in bytes per second -+# -+# @devlist: list of block device names (separated by ',', ';' -+# or ':'). By default the backup includes all writable block devices. -+# -+# Returns: the uuid of the backup job -+# -+## -+{ 'command': 'backup', 'data': { 'backup-file': 'str', -+ '*format': 'BackupFormat', -+ '*config-file': 'str', -+ '*devlist': 'str', '*speed': 'int' }, -+ 'returns': 'UuidInfo' } -+ -+## -+# @query-backup: -+# -+# Returns information about current/last backup task. -+# -+# Returns: @BackupStatus -+# -+## -+{ 'command': 'query-backup', 'returns': 'BackupStatus' } -+ -+## -+# @backup-cancel: -+# -+# Cancel the current executing backup process. -+# -+# Returns: nothing on success -+# -+# Notes: This command succeeds even if there is no backup process running. -+# -+## -+{ 'command': 'backup-cancel' } -+ -+## - # @MigrationStats: - # - # Detailed migration status. --- -2.11.0 - diff --git a/debian/patches/pve/0003-vnc-altgr-emulation.patch b/debian/patches/pve/0015-vnc-altgr-emulation.patch similarity index 94% rename from debian/patches/pve/0003-vnc-altgr-emulation.patch rename to debian/patches/pve/0015-vnc-altgr-emulation.patch index e593bb8..38ad9b6 100644 --- a/debian/patches/pve/0003-vnc-altgr-emulation.patch +++ b/debian/patches/pve/0015-vnc-altgr-emulation.patch @@ -1,7 +1,7 @@ -From 6c2823a8f34f9edd061a8c56af8fa0fb5014c507 Mon Sep 17 00:00:00 2001 +From 8c4c8041d0cb8523af453e1d1a8408215db6964f Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Wed, 9 Dec 2015 14:17:38 +0100 -Subject: [PATCH 03/49] vnc: altgr emulation +Subject: [PATCH 15/28] vnc: altgr emulation --- ui/vnc.c | 26 +++++++++++++++++++++++++- diff --git a/debian/patches/pve/0016-backup-vma-add-dir-format.patch b/debian/patches/pve/0016-backup-vma-add-dir-format.patch deleted file mode 100644 index d036289..0000000 --- a/debian/patches/pve/0016-backup-vma-add-dir-format.patch +++ /dev/null @@ -1,315 +0,0 @@ -From 1fc4d337a3935f0e80a78f8b14bdda839257ded9 Mon Sep 17 00:00:00 2001 -From: Wolfgang Bumiller -Date: Wed, 9 Dec 2015 15:21:54 +0100 -Subject: [PATCH 16/49] backup: vma: add dir format - ---- - blockdev.c | 137 ++++++++++++++++++++++++++++++++++++++++--------------- - hmp-commands.hx | 8 ++-- - hmp.c | 4 +- - qapi-schema.json | 2 +- - vma.c | 2 +- - 5 files changed, 111 insertions(+), 42 deletions(-) - -diff --git a/blockdev.c b/blockdev.c -index 58cf5d3c80..87e1d1a99e 100644 ---- a/blockdev.c -+++ b/blockdev.c -@@ -3007,6 +3007,8 @@ typedef struct PVEBackupDevInfo { - uint8_t dev_id; - //bool started; - bool completed; -+ char targetfile[PATH_MAX]; -+ BlockDriverState *target; - } PVEBackupDevInfo; - - static void pvebackup_run_next_job(void); -@@ -3075,8 +3077,6 @@ static void pvebackup_complete_cb(void *opaque, int ret) - { - PVEBackupDevInfo *di = opaque; - -- assert(backup_state.vmaw); -- - di->completed = true; - - if (ret < 0 && !backup_state.error) { -@@ -3087,8 +3087,11 @@ static void pvebackup_complete_cb(void *opaque, int ret) - BlockDriverState *bs = di->bs; - - di->bs = NULL; -+ di->target = NULL; - -- vma_writer_close_stream(backup_state.vmaw, di->dev_id); -+ if (backup_state.vmaw) { -+ vma_writer_close_stream(backup_state.vmaw, di->dev_id); -+ } - - block_job_cb(bs, ret); - -@@ -3168,6 +3171,7 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format, - { - BlockBackend *blk; - BlockDriverState *bs = NULL; -+ const char *backup_dir = NULL; - Error *local_err = NULL; - uuid_t uuid; - VmaWriter *vmaw = NULL; -@@ -3175,6 +3179,7 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format, - GList *di_list = NULL; - GList *l; - UuidInfo *uuid_info; -+ BlockJob *job; - - if (backup_state.di_list) { - error_set(errp, ERROR_CLASS_GENERIC_ERROR, -@@ -3185,11 +3190,6 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format, - /* Todo: try to auto-detect format based on file name */ - format = has_format ? format : BACKUP_FORMAT_VMA; - -- if (format != BACKUP_FORMAT_VMA) { -- error_set(errp, ERROR_CLASS_GENERIC_ERROR, "unknown backup format"); -- return NULL; -- } -- - if (has_devlist) { - devs = g_strsplit_set(devlist, ",;:", -1); - -@@ -3258,27 +3258,62 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format, - - uuid_generate(uuid); - -- vmaw = vma_writer_create(backup_file, uuid, &local_err); -- if (!vmaw) { -- if (local_err) { -- error_propagate(errp, local_err); -+ if (format == BACKUP_FORMAT_VMA) { -+ vmaw = vma_writer_create(backup_file, uuid, &local_err); -+ if (!vmaw) { -+ if (local_err) { -+ error_propagate(errp, local_err); -+ } -+ goto err; - } -- goto err; -- } - -- /* register all devices for vma writer */ -- l = di_list; -- while (l) { -- PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; -- l = g_list_next(l); -+ /* register all devices for vma writer */ -+ l = di_list; -+ while (l) { -+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; -+ l = g_list_next(l); - -- const char *devname = bdrv_get_device_name(di->bs); -- di->dev_id = vma_writer_register_stream(vmaw, devname, di->size); -- if (di->dev_id <= 0) { -- error_set(errp, ERROR_CLASS_GENERIC_ERROR, -- "register_stream failed"); -+ const char *devname = bdrv_get_device_name(di->bs); -+ di->dev_id = vma_writer_register_stream(vmaw, devname, di->size); -+ if (di->dev_id <= 0) { -+ error_set(errp, ERROR_CLASS_GENERIC_ERROR, -+ "register_stream failed"); -+ goto err; -+ } -+ } -+ } else if (format == BACKUP_FORMAT_DIR) { -+ if (mkdir(backup_file, 0640) != 0) { -+ error_setg_errno(errp, errno, "can't create directory '%s'\n", -+ backup_file); - goto err; - } -+ backup_dir = backup_file; -+ -+ l = di_list; -+ while (l) { -+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; -+ l = g_list_next(l); -+ -+ const char *devname = bdrv_get_device_name(di->bs); -+ snprintf(di->targetfile, PATH_MAX, "%s/%s.raw", backup_dir, devname); -+ -+ int flags = BDRV_O_RDWR; -+ bdrv_img_create(di->targetfile, "raw", NULL, NULL, NULL, -+ di->size, flags, &local_err, false); -+ if (local_err) { -+ error_propagate(errp, local_err); -+ goto err; -+ } -+ -+ di->target = bdrv_open(di->targetfile, NULL, NULL, flags, &local_err); -+ if (!di->target) { -+ error_propagate(errp, local_err); -+ goto err; -+ } -+ } -+ } else { -+ error_set(errp, ERROR_CLASS_GENERIC_ERROR, "unknown backup format"); -+ goto err; - } - - /* add configuration file to archive */ -@@ -3291,12 +3326,27 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format, - goto err; - } - -- const char *basename = g_path_get_basename(config_file); -- if (vma_writer_add_config(vmaw, basename, cdata, clen) != 0) { -- error_setg(errp, "unable to add config data to vma archive"); -- g_free(cdata); -- goto err; -+ char *basename = g_path_get_basename(config_file); -+ -+ if (format == BACKUP_FORMAT_VMA) { -+ if (vma_writer_add_config(vmaw, basename, cdata, clen) != 0) { -+ error_setg(errp, "unable to add config data to vma archive"); -+ g_free(cdata); -+ g_free(basename); -+ goto err; -+ } -+ } else if (format == BACKUP_FORMAT_DIR) { -+ char config_path[PATH_MAX]; -+ snprintf(config_path, PATH_MAX, "%s/%s", backup_dir, basename); -+ if (!g_file_set_contents(config_path, cdata, clen, &err)) { -+ error_setg(errp, "unable to write config file '%s'", config_path); -+ g_free(cdata); -+ g_free(basename); -+ goto err; -+ } - } -+ -+ g_free(basename); - g_free(cdata); - } - -@@ -3335,15 +3385,16 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format, - while (l) { - PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; - l = g_list_next(l); -- -- backup_job_create(NULL, di->bs, NULL, speed, MIRROR_SYNC_MODE_FULL, NULL, -- BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT, -- pvebackup_dump_cb, pvebackup_complete_cb, di, -- 1, NULL, &local_err); -- if (local_err != NULL) { -+ job = backup_job_create(NULL, di->bs, di->target, speed, MIRROR_SYNC_MODE_FULL, NULL, -+ false, BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT, -+ BLOCK_JOB_DEFAULT, -+ pvebackup_dump_cb, pvebackup_complete_cb, di, -+ 1, NULL, &local_err); -+ if (!job || local_err != NULL) { - error_setg(&backup_state.error, "backup_job_create failed"); - pvebackup_cancel(NULL); - } -+ block_job_start(job); - } - - if (!backup_state.error) { -@@ -3352,14 +3403,24 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format, - - uuid_info = g_malloc0(sizeof(*uuid_info)); - uuid_info->UUID = g_strdup(backup_state.uuid_str); -+ - return uuid_info; - - err: - - l = di_list; - while (l) { -- g_free(l->data); -+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; - l = g_list_next(l); -+ -+ if (di->target) { -+ bdrv_unref(di->target); -+ } -+ -+ if (di->targetfile[0]) { -+ unlink(di->targetfile); -+ } -+ g_free(di); - } - g_list_free(di_list); - -@@ -3373,6 +3434,10 @@ err: - unlink(backup_file); - } - -+ if (backup_dir) { -+ rmdir(backup_dir); -+ } -+ - return NULL; - } - -diff --git a/hmp-commands.hx b/hmp-commands.hx -index aea39d0f45..72882039ee 100644 ---- a/hmp-commands.hx -+++ b/hmp-commands.hx -@@ -89,9 +89,11 @@ ETEXI - - { - .name = "backup", -- .args_type = "backupfile:s,speed:o?,devlist:s?", -- .params = "backupfile [speed [devlist]]", -- .help = "create a VM Backup.", -+ .args_type = "directory:-d,backupfile:s,speed:o?,devlist:s?", -+ .params = "[-d] backupfile [speed [devlist]]", -+ .help = "create a VM Backup." -+ "\n\t\t\t Use -d to dump data into a directory instead" -+ "\n\t\t\t of using VMA format.", - .cmd = hmp_backup, - }, - -diff --git a/hmp.c b/hmp.c -index c685ba507f..465d7faad0 100644 ---- a/hmp.c -+++ b/hmp.c -@@ -1664,11 +1664,13 @@ void hmp_backup(Monitor *mon, const QDict *qdict) - { - Error *error = NULL; - -+ int dir = qdict_get_try_bool(qdict, "directory", 0); - const char *backup_file = qdict_get_str(qdict, "backupfile"); - const char *devlist = qdict_get_try_str(qdict, "devlist"); - int64_t speed = qdict_get_try_int(qdict, "speed", 0); - -- qmp_backup(backup_file, true, BACKUP_FORMAT_VMA, false, NULL, !!devlist, -+ qmp_backup(backup_file, true, dir ? BACKUP_FORMAT_DIR : BACKUP_FORMAT_VMA, -+ false, NULL, !!devlist, - devlist, qdict_haskey(qdict, "speed"), speed, &error); - - hmp_handle_error(mon, &error); -diff --git a/qapi-schema.json b/qapi-schema.json -index 12d4d20705..edb7c32ac9 100644 ---- a/qapi-schema.json -+++ b/qapi-schema.json -@@ -609,7 +609,7 @@ - # @vma: Proxmox vma backup format - ## - { 'enum': 'BackupFormat', -- 'data': [ 'vma' ] } -+ 'data': [ 'vma', 'dir' ] } - - ## - # @backup: -diff --git a/vma.c b/vma.c -index 89254070c4..1ffaced897 100644 ---- a/vma.c -+++ b/vma.c -@@ -264,7 +264,7 @@ static int extract_content(int argc, char **argv) - g_free(statefn); - } else if (di) { - char *devfn = NULL; -- int flags = BDRV_O_RDWR|BDRV_O_CACHE_WB; -+ int flags = BDRV_O_RDWR; - bool write_zero = true; - - if (readmap) { --- -2.11.0 - diff --git a/debian/patches/pve/0029-vnc-make-x509-imply-tls-again.patch b/debian/patches/pve/0016-vnc-make-x509-imply-tls-again.patch similarity index 85% rename from debian/patches/pve/0029-vnc-make-x509-imply-tls-again.patch rename to debian/patches/pve/0016-vnc-make-x509-imply-tls-again.patch index fd228d1..52b23f3 100644 --- a/debian/patches/pve/0029-vnc-make-x509-imply-tls-again.patch +++ b/debian/patches/pve/0016-vnc-make-x509-imply-tls-again.patch @@ -1,7 +1,7 @@ -From d4cccacea777bdf4ce379a0d889acbfd05fcdf05 Mon Sep 17 00:00:00 2001 +From e90d84abb42bc2befe9a48a9be2873d5dce68236 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Tue, 12 Jan 2016 09:09:49 +0100 -Subject: [PATCH 29/49] vnc: make x509 imply tls again +Subject: [PATCH 16/28] vnc: make x509 imply tls again --- ui/vnc.c | 5 ++--- diff --git a/debian/patches/pve/0017-backup-do-not-return-errors-in-dump-callback.patch b/debian/patches/pve/0017-backup-do-not-return-errors-in-dump-callback.patch deleted file mode 100644 index bbe1de9..0000000 --- a/debian/patches/pve/0017-backup-do-not-return-errors-in-dump-callback.patch +++ /dev/null @@ -1,77 +0,0 @@ -From c8fdc50eaa27500204364f15de1aac2c0ac07bf8 Mon Sep 17 00:00:00 2001 -From: Wolfgang Bumiller -Date: Wed, 9 Dec 2015 15:22:19 +0100 -Subject: [PATCH 17/49] backup: do not return errors in dump callback - ---- - blockdev.c | 26 ++++++++++++++++++++------ - 1 file changed, 20 insertions(+), 6 deletions(-) - -diff --git a/blockdev.c b/blockdev.c -index 87e1d1a99e..5017c276e6 100644 ---- a/blockdev.c -+++ b/blockdev.c -@@ -3019,6 +3019,11 @@ static int pvebackup_dump_cb(void *opaque, BlockBackend *target, - { - PVEBackupDevInfo *di = opaque; - -+ int size = n_sectors * BDRV_SECTOR_SIZE; -+ if (backup_state.cancel) { -+ return size; // return success -+ } -+ - if (sector_num & 0x7f) { - if (!backup_state.error) { - error_setg(&backup_state.error, -@@ -3029,7 +3034,6 @@ static int pvebackup_dump_cb(void *opaque, BlockBackend *target, - } - - int64_t cluster_num = sector_num >> 7; -- int size = n_sectors * BDRV_SECTOR_SIZE; - - int ret = -1; - -@@ -3037,17 +3041,27 @@ static int pvebackup_dump_cb(void *opaque, BlockBackend *target, - size_t zero_bytes = 0; - ret = vma_writer_write(backup_state.vmaw, di->dev_id, cluster_num, - buf, &zero_bytes); -- backup_state.zero_bytes += zero_bytes; -+ if (ret < 0) { -+ if (!backup_state.error) { -+ error_setg(&backup_state.error, "vma_writer_write error %d", ret); -+ } -+ if (di->bs && di->bs->job) { -+ block_job_cancel(di->bs->job); -+ } -+ } else { -+ backup_state.zero_bytes += zero_bytes; -+ backup_state.transferred += size; -+ } - } else { -- ret = size; - if (!buf) { - backup_state.zero_bytes += size; - } -+ backup_state.transferred += size; - } - -- backup_state.transferred += size; -+ // Note: always return success, because we want that writes succeed anyways. - -- return ret; -+ return size; - } - - static void pvebackup_cleanup(void) -@@ -3119,7 +3133,7 @@ static void pvebackup_cancel(void *opaque) - BlockJob *job = di->bs->job; - if (job) { - if (!di->completed) { -- block_job_cancel_sync(job); -+ block_job_cancel_sync(job); - } - } - } --- -2.11.0 - diff --git a/debian/patches/pve/0030-PVE-VNC-authentication.patch b/debian/patches/pve/0017-vnc-PVE-VNC-authentication.patch similarity index 95% rename from debian/patches/pve/0030-PVE-VNC-authentication.patch rename to debian/patches/pve/0017-vnc-PVE-VNC-authentication.patch index 4bbe6fd..3d39e05 100644 --- a/debian/patches/pve/0030-PVE-VNC-authentication.patch +++ b/debian/patches/pve/0017-vnc-PVE-VNC-authentication.patch @@ -1,7 +1,7 @@ -From 503d2744e7e5cfdca939404488ee2b3f43894425 Mon Sep 17 00:00:00 2001 +From e9712692a0a336bf56025e1bc8056636cbd3931e Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Mon, 11 Jan 2016 10:40:31 +0100 -Subject: [PATCH 30/49] PVE VNC authentication +Subject: [PATCH 17/28] vnc: PVE VNC authentication --- crypto/tlscreds.c | 47 +++++++++++ @@ -11,11 +11,11 @@ Subject: [PATCH 30/49] PVE VNC authentication include/crypto/tlscreds.h | 1 + include/ui/console.h | 1 + qemu-options.hx | 3 + - ui/vnc-auth-vencrypt.c | 196 ++++++++++++++++++++++++++++++++++++++-------- - ui/vnc.c | 140 ++++++++++++++++++++++++++++++++- + ui/vnc-auth-vencrypt.c | 197 ++++++++++++++++++++++++++++++++++++++-------- + ui/vnc.c | 140 +++++++++++++++++++++++++++++++- ui/vnc.h | 4 + vl.c | 9 +++ - 11 files changed, 376 insertions(+), 41 deletions(-) + 11 files changed, 377 insertions(+), 41 deletions(-) diff --git a/crypto/tlscreds.c b/crypto/tlscreds.c index a8965531b6..e9ae13ce47 100644 @@ -194,34 +194,30 @@ index 10f0e81f9b..fbd1a1cecf 100644 "-fda/-fdb file use 'file' as floppy disk 0/1 image\n", QEMU_ARCH_ALL) DEF("fdb", HAS_ARG, QEMU_OPTION_fdb, "", QEMU_ARCH_ALL) diff --git a/ui/vnc-auth-vencrypt.c b/ui/vnc-auth-vencrypt.c -index ffaab57550..de1c1949ba 100644 +index ffaab57550..594ca737a9 100644 --- a/ui/vnc-auth-vencrypt.c +++ b/ui/vnc-auth-vencrypt.c -@@ -28,6 +28,107 @@ +@@ -28,6 +28,108 @@ #include "vnc.h" #include "qapi/error.h" #include "qemu/main-loop.h" -+#include "qemu/sockets.h" ++#include "io/channel-socket.h" + +static int protocol_client_auth_plain(VncState *vs, uint8_t *data, size_t len) +{ -+ const char *err = NULL; ++ Error *err = NULL; + char username[256]; + char passwd[512]; + -+ char clientip[256]; -+ clientip[0] = 0; -+ struct sockaddr_in client; -+ socklen_t addrlen = sizeof(client); -+ if (getpeername(vs->csock, &client, &addrlen) == 0) { -+ inet_ntop(client.sin_family, &client.sin_addr, -+ clientip, sizeof(clientip)); ++ SocketAddress *clientip = qio_channel_socket_get_remote_address(vs->sioc, &err); ++ if (err) { ++ goto err; + } + + if ((len != (vs->username_len + vs->password_len)) || + (vs->username_len >= (sizeof(username)-1)) || + (vs->password_len >= (sizeof(passwd)-1)) ) { -+ err = "Got unexpected data length"; ++ error_setg(&err, "Got unexpected data length"); + goto err; + } + @@ -232,26 +228,31 @@ index ffaab57550..de1c1949ba 100644 + + VNC_DEBUG("AUTH PLAIN username: %s pw: %s\n", username, passwd); + -+ if (pve_auth_verify(clientip, username, passwd) == 0) { ++ if (pve_auth_verify(clientip->u.inet.data->host, username, passwd) == 0) { + vnc_write_u32(vs, 0); /* Accept auth completion */ + start_client_init(vs); ++ qapi_free_SocketAddress(clientip); + return 0; + } + -+ err = "Authentication failed"; ++ error_setg(&err, "Authentication failed"); +err: + if (err) { -+ VNC_DEBUG("AUTH PLAIN ERROR: %s\n", err); ++ const char *err_msg = error_get_pretty(err); ++ VNC_DEBUG("AUTH PLAIN ERROR: %s\n", err_msg); + vnc_write_u32(vs, 1); /* Reject auth */ + if (vs->minor >= 8) { -+ int elen = strlen(err); ++ int elen = strlen(err_msg); + vnc_write_u32(vs, elen); -+ vnc_write(vs, err, elen); ++ vnc_write(vs, err_msg, elen); + } ++ error_free(err); + } + vnc_flush(vs); + vnc_client_error(vs); + ++ qapi_free_SocketAddress(clientip); ++ + return 0; + +} @@ -305,7 +306,7 @@ index ffaab57550..de1c1949ba 100644 static void start_auth_vencrypt_subauth(VncState *vs) { -@@ -39,6 +140,17 @@ static void start_auth_vencrypt_subauth(VncState *vs) +@@ -39,6 +141,17 @@ static void start_auth_vencrypt_subauth(VncState *vs) start_client_init(vs); break; @@ -323,7 +324,7 @@ index ffaab57550..de1c1949ba 100644 case VNC_AUTH_VENCRYPT_TLSVNC: case VNC_AUTH_VENCRYPT_X509VNC: VNC_DEBUG("Start TLS auth VNC\n"); -@@ -88,45 +200,64 @@ static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len +@@ -88,45 +201,64 @@ static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len { int auth = read_u32(data, 0); @@ -418,7 +419,7 @@ index ffaab57550..de1c1949ba 100644 } return 0; } -@@ -140,10 +271,11 @@ static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len +@@ -140,10 +272,11 @@ static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len vnc_flush(vs); vnc_client_error(vs); } else { diff --git a/debian/patches/pve/0018-backup-vma-correctly-propagate-error.patch b/debian/patches/pve/0018-backup-vma-correctly-propagate-error.patch deleted file mode 100644 index 39fa255..0000000 --- a/debian/patches/pve/0018-backup-vma-correctly-propagate-error.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 95ae3ad5710a4128f27e53d4fd926aa8fe596459 Mon Sep 17 00:00:00 2001 -From: Wolfgang Bumiller -Date: Wed, 9 Dec 2015 15:39:36 +0100 -Subject: [PATCH 18/49] backup: vma: correctly propagate error - ---- - blockdev.c | 2 +- - vma-writer.c | 7 +++++++ - vma.h | 1 + - 3 files changed, 9 insertions(+), 1 deletion(-) - -diff --git a/blockdev.c b/blockdev.c -index 5017c276e6..d3aef2cc83 100644 ---- a/blockdev.c -+++ b/blockdev.c -@@ -3043,7 +3043,7 @@ static int pvebackup_dump_cb(void *opaque, BlockBackend *target, - buf, &zero_bytes); - if (ret < 0) { - if (!backup_state.error) { -- error_setg(&backup_state.error, "vma_writer_write error %d", ret); -+ vma_writer_error_propagate(backup_state.vmaw, &backup_state.error); - } - if (di->bs && di->bs->job) { - block_job_cancel(di->bs->job); -diff --git a/vma-writer.c b/vma-writer.c -index b0cf529125..689e988423 100644 ---- a/vma-writer.c -+++ b/vma-writer.c -@@ -792,6 +792,13 @@ vma_writer_write(VmaWriter *vmaw, uint8_t dev_id, int64_t cluster_num, - return transferred; - } - -+void vma_writer_error_propagate(VmaWriter *vmaw, Error **errp) -+{ -+ if (vmaw->status < 0 && *errp == NULL) { -+ error_setg(errp, "%s", vmaw->errmsg); -+ } -+} -+ - int vma_writer_close(VmaWriter *vmaw, Error **errp) - { - g_assert(vmaw != NULL); -diff --git a/vma.h b/vma.h -index 9bb6ea4f69..98377e473e 100644 ---- a/vma.h -+++ b/vma.h -@@ -116,6 +116,7 @@ typedef struct VmaDeviceInfo { - - VmaWriter *vma_writer_create(const char *filename, uuid_t uuid, Error **errp); - int vma_writer_close(VmaWriter *vmaw, Error **errp); -+void vma_writer_error_propagate(VmaWriter *vmaw, Error **errp); - void vma_writer_destroy(VmaWriter *vmaw); - int vma_writer_add_config(VmaWriter *vmaw, const char *name, gpointer data, - size_t len); --- -2.11.0 - diff --git a/debian/patches/pve/0035-fix-possible-unitialised-return-value.patch b/debian/patches/pve/0018-migrate-fix-possible-unitialised-return-value.patch similarity index 82% rename from debian/patches/pve/0035-fix-possible-unitialised-return-value.patch rename to debian/patches/pve/0018-migrate-fix-possible-unitialised-return-value.patch index bf6b979..2d59f6f 100644 --- a/debian/patches/pve/0035-fix-possible-unitialised-return-value.patch +++ b/debian/patches/pve/0018-migrate-fix-possible-unitialised-return-value.patch @@ -1,7 +1,7 @@ -From 2727cb752e676e4ef0b9364036879212210cf641 Mon Sep 17 00:00:00 2001 +From 0b8732d8e19f69471e2f9b8c9a654de62482915a Mon Sep 17 00:00:00 2001 From: Thomas Lamprecht Date: Wed, 6 Apr 2016 16:45:15 +0200 -Subject: [PATCH 35/49] fix possible unitialised return value +Subject: [PATCH 18/28] migrate: fix possible unitialised return value --- migration/savevm.c | 2 +- diff --git a/debian/patches/pve/0019-backup-vma-remove-async-queue.patch b/debian/patches/pve/0019-backup-vma-remove-async-queue.patch deleted file mode 100644 index 729220a..0000000 --- a/debian/patches/pve/0019-backup-vma-remove-async-queue.patch +++ /dev/null @@ -1,317 +0,0 @@ -From 8847efb5dee0b82e397ed7dfb05eec41c28d916d Mon Sep 17 00:00:00 2001 -From: Wolfgang Bumiller -Date: Wed, 9 Dec 2015 15:40:00 +0100 -Subject: [PATCH 19/49] backup: vma: remove async queue - ---- - blockdev.c | 6 ++ - vma-writer.c | 179 +++++++++++------------------------------------------------ - 2 files changed, 38 insertions(+), 147 deletions(-) - -diff --git a/blockdev.c b/blockdev.c -index d3aef2cc83..bad5b2a8b8 100644 ---- a/blockdev.c -+++ b/blockdev.c -@@ -3122,6 +3122,11 @@ static void pvebackup_cancel(void *opaque) - error_setg(&backup_state.error, "backup cancelled"); - } - -+ if (backup_state.vmaw) { -+ /* make sure vma writer does not block anymore */ -+ vma_writer_set_error(backup_state.vmaw, "backup cancelled"); -+ } -+ - /* drain all i/o (awake jobs waiting for aio) */ - bdrv_drain_all(); - -@@ -3134,6 +3139,7 @@ static void pvebackup_cancel(void *opaque) - if (job) { - if (!di->completed) { - block_job_cancel_sync(job); -+ bdrv_drain_all(); /* drain all i/o (awake jobs waiting for aio) */ - } - } - } -diff --git a/vma-writer.c b/vma-writer.c -index 689e988423..ec8da5378d 100644 ---- a/vma-writer.c -+++ b/vma-writer.c -@@ -28,14 +28,8 @@ - do { if (DEBUG_VMA) { printf("vma: " fmt, ## __VA_ARGS__); } } while (0) - - #define WRITE_BUFFERS 5 -- --typedef struct VmaAIOCB VmaAIOCB; --struct VmaAIOCB { -- unsigned char buffer[VMA_MAX_EXTENT_SIZE]; -- VmaWriter *vmaw; -- size_t bytes; -- Coroutine *co; --}; -+#define HEADER_CLUSTERS 8 -+#define HEADERBUF_SIZE (VMA_CLUSTER_SIZE*HEADER_CLUSTERS) - - struct VmaWriter { - int fd; -@@ -47,16 +41,14 @@ struct VmaWriter { - bool closed; - - /* we always write extents */ -- unsigned char outbuf[VMA_MAX_EXTENT_SIZE]; -+ unsigned char *outbuf; - int outbuf_pos; /* in bytes */ - int outbuf_count; /* in VMA_BLOCKS */ - uint64_t outbuf_block_info[VMA_BLOCKS_PER_EXTENT]; - -- VmaAIOCB *aiocbs[WRITE_BUFFERS]; -- CoQueue wqueue; -+ unsigned char *headerbuf; - - GChecksum *md5csum; -- CoMutex writer_lock; - CoMutex flush_lock; - Coroutine *co_writer; - -@@ -217,38 +209,39 @@ static void vma_co_continue_write(void *opaque) - } - - static ssize_t coroutine_fn --vma_co_write(VmaWriter *vmaw, const void *buf, size_t bytes) -+vma_queue_write(VmaWriter *vmaw, const void *buf, size_t bytes) - { -- size_t done = 0; -- ssize_t ret; -+ DPRINTF("vma_queue_write enter %zd\n", bytes); - -- /* atomic writes (we cannot interleave writes) */ -- qemu_co_mutex_lock(&vmaw->writer_lock); -+ assert(vmaw); -+ assert(buf); -+ assert(bytes <= VMA_MAX_EXTENT_SIZE); - -- DPRINTF("vma_co_write enter %zd\n", bytes); -+ size_t done = 0; -+ ssize_t ret; - - assert(vmaw->co_writer == NULL); - - vmaw->co_writer = qemu_coroutine_self(); - -- aio_set_fd_handler(qemu_get_aio_context(), vmaw->fd, false, NULL, vma_co_continue_write, vmaw); -- -- DPRINTF("vma_co_write wait until writable\n"); -- qemu_coroutine_yield(); -- DPRINTF("vma_co_write starting %zd\n", bytes); -- - while (done < bytes) { -+ aio_set_fd_handler(qemu_get_aio_context(), vmaw->fd, false, NULL, vma_co_continue_write, NULL, vmaw); -+ qemu_coroutine_yield(); -+ aio_set_fd_handler(qemu_get_aio_context(), vmaw->fd, false, NULL, NULL, NULL, NULL); -+ if (vmaw->status < 0) { -+ DPRINTF("vma_queue_write detected canceled backup\n"); -+ done = -1; -+ break; -+ } - ret = write(vmaw->fd, buf + done, bytes - done); - if (ret > 0) { - done += ret; -- DPRINTF("vma_co_write written %zd %zd\n", done, ret); -+ DPRINTF("vma_queue_write written %zd %zd\n", done, ret); - } else if (ret < 0) { - if (errno == EAGAIN || errno == EWOULDBLOCK) { -- DPRINTF("vma_co_write yield %zd\n", done); -- qemu_coroutine_yield(); -- DPRINTF("vma_co_write restart %zd\n", done); -- } else { -- vma_writer_set_error(vmaw, "vma_co_write write error - %s", -+ /* try again */ -+ } else { -+ vma_writer_set_error(vmaw, "vma_queue_write: write error - %s", - g_strerror(errno)); - done = -1; /* always return failure for partial writes */ - break; -@@ -258,102 +251,9 @@ vma_co_write(VmaWriter *vmaw, const void *buf, size_t bytes) - } - } - -- aio_set_fd_handler(qemu_get_aio_context(), vmaw->fd, false, NULL, NULL, NULL); -- - vmaw->co_writer = NULL; -- -- qemu_co_mutex_unlock(&vmaw->writer_lock); -- -- DPRINTF("vma_co_write leave %zd\n", done); -- return done; --} -- --static void coroutine_fn vma_co_writer_task(void *opaque) --{ -- VmaAIOCB *cb = opaque; -- -- DPRINTF("vma_co_writer_task start\n"); -- -- int64_t done = vma_co_write(cb->vmaw, cb->buffer, cb->bytes); -- DPRINTF("vma_co_writer_task write done %zd\n", done); -- -- if (done != cb->bytes) { -- DPRINTF("vma_co_writer_task failed write %zd %zd", cb->bytes, done); -- vma_writer_set_error(cb->vmaw, "vma_co_writer_task failed write %zd", -- done); -- } -- -- cb->bytes = 0; -- -- qemu_co_queue_next(&cb->vmaw->wqueue); -- -- DPRINTF("vma_co_writer_task end\n"); --} -- --static void coroutine_fn vma_queue_flush(VmaWriter *vmaw) --{ -- DPRINTF("vma_queue_flush enter\n"); -- -- assert(vmaw); -- -- while (1) { -- int i; -- VmaAIOCB *cb = NULL; -- for (i = 0; i < WRITE_BUFFERS; i++) { -- if (vmaw->aiocbs[i]->bytes) { -- cb = vmaw->aiocbs[i]; -- DPRINTF("FOUND USED AIO BUFFER %d %zd\n", i, -- vmaw->aiocbs[i]->bytes); -- break; -- } -- } -- if (!cb) { -- break; -- } -- qemu_co_queue_wait(&vmaw->wqueue); -- } -- -- DPRINTF("vma_queue_flush leave\n"); --} -- --/** -- * NOTE: pipe buffer size in only 4096 bytes on linux (see 'ulimit -a') -- * So we need to create a coroutione to allow 'parallel' execution. -- */ --static ssize_t coroutine_fn --vma_queue_write(VmaWriter *vmaw, const void *buf, size_t bytes) --{ -- DPRINTF("vma_queue_write enter %zd\n", bytes); -- -- assert(vmaw); -- assert(buf); -- assert(bytes <= VMA_MAX_EXTENT_SIZE); -- -- VmaAIOCB *cb = NULL; -- while (!cb) { -- int i; -- for (i = 0; i < WRITE_BUFFERS; i++) { -- if (!vmaw->aiocbs[i]->bytes) { -- cb = vmaw->aiocbs[i]; -- break; -- } -- } -- if (!cb) { -- qemu_co_queue_wait(&vmaw->wqueue); -- } -- } -- -- memcpy(cb->buffer, buf, bytes); -- cb->bytes = bytes; -- cb->vmaw = vmaw; -- -- DPRINTF("vma_queue_write start %zd\n", bytes); -- cb->co = qemu_coroutine_create(vma_co_writer_task); -- qemu_coroutine_enter(cb->co, cb); -- -- DPRINTF("vma_queue_write leave\n"); -- -- return bytes; -+ -+ return (done == bytes) ? bytes : -1; - } - - VmaWriter *vma_writer_create(const char *filename, uuid_t uuid, Error **errp) -@@ -420,20 +320,16 @@ VmaWriter *vma_writer_create(const char *filename, uuid_t uuid, Error **errp) - } - - /* 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 = qemu_memalign(512, VMA_MAX_EXTENT_SIZE); -+ vmaw->headerbuf = qemu_memalign(512, HEADERBUF_SIZE); - - vmaw->outbuf_count = 0; - vmaw->outbuf_pos = VMA_EXTENT_HEADER_SIZE; - - vmaw->header_blob_table_pos = 1; /* start at pos 1 */ - -- qemu_co_mutex_init(&vmaw->writer_lock); - qemu_co_mutex_init(&vmaw->flush_lock); -- qemu_co_queue_init(&vmaw->wqueue); - - uuid_copy(vmaw->uuid, uuid); - -@@ -460,8 +356,7 @@ err: - static int coroutine_fn vma_write_header(VmaWriter *vmaw) - { - assert(vmaw); -- int header_clusters = 8; -- char buf[65536*header_clusters]; -+ unsigned char *buf = vmaw->headerbuf; - VmaHeader *head = (VmaHeader *)buf; - - int i; -@@ -472,7 +367,7 @@ static int coroutine_fn vma_write_header(VmaWriter *vmaw) - return vmaw->status; - } - -- memset(buf, 0, sizeof(buf)); -+ memset(buf, 0, HEADERBUF_SIZE); - - head->magic = VMA_MAGIC; - head->version = GUINT32_TO_BE(1); /* v1 */ -@@ -507,7 +402,7 @@ static int coroutine_fn vma_write_header(VmaWriter *vmaw) - uint32_t header_size = sizeof(VmaHeader) + vmaw->header_blob_table_size; - head->header_size = GUINT32_TO_BE(header_size); - -- if (header_size > sizeof(buf)) { -+ if (header_size > HEADERBUF_SIZE) { - return -1; /* just to be sure */ - } - -@@ -805,13 +700,7 @@ int vma_writer_close(VmaWriter *vmaw, Error **errp) - - int i; - -- vma_queue_flush(vmaw); -- -- /* this should not happen - just to be sure */ -- while (!qemu_co_queue_empty(&vmaw->wqueue)) { -- DPRINTF("vma_writer_close wait\n"); -- co_aio_sleep_ns(qemu_get_aio_context(), QEMU_CLOCK_REALTIME, 1000000); -- } -+ assert(vmaw->co_writer == NULL); - - if (vmaw->cmd) { - if (pclose(vmaw->cmd) < 0) { -@@ -869,9 +758,5 @@ void vma_writer_destroy(VmaWriter *vmaw) - g_checksum_free(vmaw->md5csum); - } - -- for (i = 0; i < WRITE_BUFFERS; i++) { -- free(vmaw->aiocbs[i]); -- } -- - g_free(vmaw); - } --- -2.11.0 - diff --git a/debian/patches/pve/0039-rbd-disable-rbd_cache_writethrough_until_flush-with-.patch b/debian/patches/pve/0019-block-rbd-disable-rbd_cache_writethrough_until_flush.patch similarity index 81% rename from debian/patches/pve/0039-rbd-disable-rbd_cache_writethrough_until_flush-with-.patch rename to debian/patches/pve/0019-block-rbd-disable-rbd_cache_writethrough_until_flush.patch index e6143a5..cb98d3b 100644 --- a/debian/patches/pve/0039-rbd-disable-rbd_cache_writethrough_until_flush-with-.patch +++ b/debian/patches/pve/0019-block-rbd-disable-rbd_cache_writethrough_until_flush.patch @@ -1,8 +1,8 @@ -From 26fafa2ddc6257bf3aa0ea0e19505e3f0108172d Mon Sep 17 00:00:00 2001 +From b0603dbd9bd127305472e8162e9b3289b866b824 Mon Sep 17 00:00:00 2001 From: Alexandre Derumier Date: Tue, 26 Jul 2016 16:51:00 +0200 -Subject: [PATCH 39/49] rbd: disable rbd_cache_writethrough_until_flush with - cache=unsafe +Subject: [PATCH 19/28] block: rbd: disable rbd_cache_writethrough_until_flush + with cache=unsafe Signed-off-by: Alexandre Derumier --- diff --git a/debian/patches/pve/0020-backup-vma-run-flush-inside-coroutine.patch b/debian/patches/pve/0020-backup-vma-run-flush-inside-coroutine.patch deleted file mode 100644 index 98d1f47..0000000 --- a/debian/patches/pve/0020-backup-vma-run-flush-inside-coroutine.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 7708c32e3a14860c519ab3540a50e24a314bb3fa Mon Sep 17 00:00:00 2001 -From: Wolfgang Bumiller -Date: Wed, 9 Dec 2015 15:40:42 +0100 -Subject: [PATCH 20/49] backup: vma: run flush inside coroutine - ---- - blockdev.c | 10 +++++++++- - vma-writer.c | 4 ++++ - 2 files changed, 13 insertions(+), 1 deletion(-) - -diff --git a/blockdev.c b/blockdev.c -index bad5b2a8b8..77ee7ff93b 100644 ---- a/blockdev.c -+++ b/blockdev.c -@@ -3087,6 +3087,13 @@ static void pvebackup_cleanup(void) - } - } - -+static void coroutine_fn backup_close_vma_stream(void *opaque) -+{ -+ PVEBackupDevInfo *di = opaque; -+ -+ vma_writer_close_stream(backup_state.vmaw, di->dev_id); -+} -+ - static void pvebackup_complete_cb(void *opaque, int ret) - { - PVEBackupDevInfo *di = opaque; -@@ -3104,7 +3111,8 @@ static void pvebackup_complete_cb(void *opaque, int ret) - di->target = NULL; - - if (backup_state.vmaw) { -- vma_writer_close_stream(backup_state.vmaw, di->dev_id); -+ Coroutine *co = qemu_coroutine_create(backup_close_vma_stream, di); -+ qemu_coroutine_enter(co); - } - - block_job_cb(bs, ret); -diff --git a/vma-writer.c b/vma-writer.c -index ec8da5378d..216577a4f7 100644 ---- a/vma-writer.c -+++ b/vma-writer.c -@@ -700,6 +700,10 @@ int vma_writer_close(VmaWriter *vmaw, Error **errp) - - int i; - -+ while (vmaw->co_writer) { -+ aio_poll(qemu_get_aio_context(), true); -+ } -+ - assert(vmaw->co_writer == NULL); - - if (vmaw->cmd) { --- -2.11.0 - diff --git a/debian/patches/pve/0042-qmp_snapshot_drive-add-aiocontext.patch b/debian/patches/pve/0020-block-snapshot-qmp_snapshot_drive-add-aiocontext.patch similarity index 80% rename from debian/patches/pve/0042-qmp_snapshot_drive-add-aiocontext.patch rename to debian/patches/pve/0020-block-snapshot-qmp_snapshot_drive-add-aiocontext.patch index e63fdc2..21f8470 100644 --- a/debian/patches/pve/0042-qmp_snapshot_drive-add-aiocontext.patch +++ b/debian/patches/pve/0020-block-snapshot-qmp_snapshot_drive-add-aiocontext.patch @@ -1,7 +1,7 @@ -From 26b8ed17e06e00b287352b95212d46ff4261e70b Mon Sep 17 00:00:00 2001 +From 976296684d224ab866fc8b7ebe0d2de4b5b39170 Mon Sep 17 00:00:00 2001 From: Alexandre Derumier Date: Tue, 13 Sep 2016 01:57:56 +0200 -Subject: [PATCH 42/49] qmp_snapshot_drive: add aiocontext +Subject: [PATCH 20/28] block: snapshot: qmp_snapshot_drive: add aiocontext Signed-off-by: Alexandre Derumier --- @@ -9,10 +9,10 @@ Signed-off-by: Alexandre Derumier 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/savevm-async.c b/savevm-async.c -index 2f4766cf6c..5913a905d8 100644 +index 624e3a34b4..95995eab31 100644 --- a/savevm-async.c +++ b/savevm-async.c -@@ -345,6 +345,7 @@ void qmp_snapshot_drive(const char *device, const char *name, Error **errp) +@@ -377,6 +377,7 @@ void qmp_snapshot_drive(const char *device, const char *name, Error **errp) BlockBackend *blk; BlockDriverState *bs; QEMUSnapshotInfo sn1, *sn = &sn1; @@ -20,7 +20,7 @@ index 2f4766cf6c..5913a905d8 100644 int ret; #ifdef _WIN32 struct _timeb tb; -@@ -371,20 +372,23 @@ void qmp_snapshot_drive(const char *device, const char *name, Error **errp) +@@ -403,20 +404,23 @@ void qmp_snapshot_drive(const char *device, const char *name, Error **errp) return; } @@ -47,7 +47,7 @@ index 2f4766cf6c..5913a905d8 100644 } sn = &sn1; -@@ -409,8 +413,11 @@ void qmp_snapshot_drive(const char *device, const char *name, Error **errp) +@@ -441,8 +445,11 @@ void qmp_snapshot_drive(const char *device, const char *name, Error **errp) if (ret < 0) { error_set(errp, ERROR_CLASS_GENERIC_ERROR, "Error while creating snapshot on '%s'\n", device); diff --git a/debian/patches/pve/0021-backup-do-not-use-bdrv_drain_all.patch b/debian/patches/pve/0021-backup-do-not-use-bdrv_drain_all.patch deleted file mode 100644 index ebc2d90..0000000 --- a/debian/patches/pve/0021-backup-do-not-use-bdrv_drain_all.patch +++ /dev/null @@ -1,36 +0,0 @@ -From fbb5d5b954df75a366110c2df3bb0685ebfca145 Mon Sep 17 00:00:00 2001 -From: Wolfgang Bumiller -Date: Wed, 9 Dec 2015 15:41:13 +0100 -Subject: [PATCH 21/49] backup: do not use bdrv_drain_all - ---- - blockdev.c | 6 +----- - 1 file changed, 1 insertion(+), 5 deletions(-) - -diff --git a/blockdev.c b/blockdev.c -index 77ee7ff93b..2713585051 100644 ---- a/blockdev.c -+++ b/blockdev.c -@@ -3135,9 +3135,6 @@ static void pvebackup_cancel(void *opaque) - vma_writer_set_error(backup_state.vmaw, "backup cancelled"); - } - -- /* drain all i/o (awake jobs waiting for aio) */ -- bdrv_drain_all(); -- - GList *l = backup_state.di_list; - while (l) { - PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; -@@ -3146,8 +3143,7 @@ static void pvebackup_cancel(void *opaque) - BlockJob *job = di->bs->job; - if (job) { - if (!di->completed) { -- block_job_cancel_sync(job); -- bdrv_drain_all(); /* drain all i/o (awake jobs waiting for aio) */ -+ block_job_cancel_sync(job); - } - } - } --- -2.11.0 - diff --git a/debian/patches/pve/0045-qmp_delete_drive_snapshot-add-aiocontext.patch b/debian/patches/pve/0021-block-snapshot-qmp_delete_drive_snapshot-add-aiocont.patch similarity index 81% rename from debian/patches/pve/0045-qmp_delete_drive_snapshot-add-aiocontext.patch rename to debian/patches/pve/0021-block-snapshot-qmp_delete_drive_snapshot-add-aiocont.patch index a116368..a0167d3 100644 --- a/debian/patches/pve/0045-qmp_delete_drive_snapshot-add-aiocontext.patch +++ b/debian/patches/pve/0021-block-snapshot-qmp_delete_drive_snapshot-add-aiocont.patch @@ -1,7 +1,8 @@ -From fe00763cb7556dfdd8fdf4b6f4cc269c291d6bfa Mon Sep 17 00:00:00 2001 +From 1540187ba7716d502908a1815298d7c3fc8db6a6 Mon Sep 17 00:00:00 2001 From: Alexandre Derumier Date: Mon, 7 Nov 2016 11:47:50 +0100 -Subject: [PATCH 45/49] qmp_delete_drive_snapshot : add aiocontext +Subject: [PATCH 21/28] block: snapshot: qmp_delete_drive_snapshot : add + aiocontext this fix snapshot delete of qcow2 with iothread enabled @@ -11,10 +12,10 @@ Signed-off-by: Alexandre Derumier 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/savevm-async.c b/savevm-async.c -index 5913a905d8..3adf89fdb2 100644 +index 95995eab31..9f839faab5 100644 --- a/savevm-async.c +++ b/savevm-async.c -@@ -427,6 +427,7 @@ void qmp_delete_drive_snapshot(const char *device, const char *name, +@@ -459,6 +459,7 @@ void qmp_delete_drive_snapshot(const char *device, const char *name, BlockDriverState *bs; QEMUSnapshotInfo sn1, *sn = &sn1; Error *local_err = NULL; @@ -22,7 +23,7 @@ index 5913a905d8..3adf89fdb2 100644 int ret; -@@ -443,22 +444,28 @@ void qmp_delete_drive_snapshot(const char *device, const char *name, +@@ -475,22 +476,28 @@ void qmp_delete_drive_snapshot(const char *device, const char *name, return; } diff --git a/debian/patches/pve/0044-glusterfs-no-default-logfile-if-daemonized.patch b/debian/patches/pve/0022-glusterfs-no-default-logfile-if-daemonized.patch similarity index 91% rename from debian/patches/pve/0044-glusterfs-no-default-logfile-if-daemonized.patch rename to debian/patches/pve/0022-glusterfs-no-default-logfile-if-daemonized.patch index 958538f..ab4e0e8 100644 --- a/debian/patches/pve/0044-glusterfs-no-default-logfile-if-daemonized.patch +++ b/debian/patches/pve/0022-glusterfs-no-default-logfile-if-daemonized.patch @@ -1,7 +1,7 @@ -From f6d6cb162d0cdce8b3d83b0af7772fcd63f1dafe Mon Sep 17 00:00:00 2001 +From 26129edb715505ae35207eff2477cffec50af13e Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Mon, 24 Oct 2016 09:32:36 +0200 -Subject: [PATCH 44/49] glusterfs: no default logfile if daemonized +Subject: [PATCH 22/28] glusterfs: no default logfile if daemonized --- block/gluster.c | 15 +++++++++++---- diff --git a/debian/patches/pve/0023-backup-vma-allow-empty-backups.patch b/debian/patches/pve/0023-backup-vma-allow-empty-backups.patch deleted file mode 100644 index 4278794..0000000 --- a/debian/patches/pve/0023-backup-vma-allow-empty-backups.patch +++ /dev/null @@ -1,256 +0,0 @@ -From 84631ae35b99f60a08a4a02f1596f5c9d17ebff0 Mon Sep 17 00:00:00 2001 -From: Wolfgang Bumiller -Date: Wed, 9 Dec 2015 16:31:51 +0100 -Subject: [PATCH 23/49] backup: vma: allow empty backups - ---- - vma-reader.c | 29 ++++++++++++------------- - vma-writer.c | 30 ++++++++++++++++---------- - vma.c | 70 ++++++++++++++++++++++++++++++++++++------------------------ - vma.h | 1 + - 4 files changed, 76 insertions(+), 54 deletions(-) - -diff --git a/vma-reader.c b/vma-reader.c -index 2aafb26b2a..78f1de9499 100644 ---- a/vma-reader.c -+++ b/vma-reader.c -@@ -326,11 +326,6 @@ static int vma_reader_read_head(VmaReader *vmar, Error **errp) - } - } - -- 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]); -@@ -822,16 +817,20 @@ static int vma_reader_restore_full(VmaReader *vmar, int vmstate_fd, - } - - 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 blocks %.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 blocks %.3g%%\n", -+ (double)(100.0*vmar->partial_zero_cluster_data) / datasize); -+ } -+ } else { -+ printf("vma archive contains no image data\n"); - } - } - return ret; -diff --git a/vma-writer.c b/vma-writer.c -index 216577a4f7..0dd668b257 100644 ---- a/vma-writer.c -+++ b/vma-writer.c -@@ -252,7 +252,7 @@ vma_queue_write(VmaWriter *vmaw, const void *buf, size_t bytes) - } - - vmaw->co_writer = NULL; -- -+ - return (done == bytes) ? bytes : -1; - } - -@@ -376,10 +376,6 @@ static int coroutine_fn vma_write_header(VmaWriter *vmaw) - 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]); -@@ -496,6 +492,23 @@ static int vma_count_open_streams(VmaWriter *vmaw) - 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) -@@ -523,12 +536,7 @@ vma_writer_close_stream(VmaWriter *vmaw, uint8_t dev_id) - - 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; -diff --git a/vma.c b/vma.c -index 1ffaced897..c7c05385f6 100644 ---- a/vma.c -+++ b/vma.c -@@ -28,7 +28,7 @@ static void help(void) - "\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" - ; -@@ -396,6 +396,18 @@ typedef struct BackupJob { - - #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; -@@ -469,8 +481,8 @@ static int create_archive(int argc, char **argv) - } - - -- /* 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(); - } - -@@ -505,11 +517,11 @@ static int create_archive(int argc, char **argv) - 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++); - - Error *errp = NULL; - BlockDriverState *bs; -@@ -540,37 +552,39 @@ static int create_archive(int argc, char **argv) - int percent = 0; - int last_percent = -1; - -- while (1) { -- main_loop_wait(false); -- vma_writer_get_status(vmaw, &vmastat); -+ if (devcount) { -+ while (1) { -+ main_loop_wait(false); -+ vma_writer_get_status(vmaw, &vmastat); -+ -+ if (verbose) { - -- if (verbose) { -+ uint64_t total = 0; -+ uint64_t transferred = 0; -+ uint64_t zero_bytes = 0; - -- 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); - -- 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; -+ last_percent = percent; - } - } -- 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; -+ if (vmastat.closed) { -+ break; - } - } -- -- if (vmastat.closed) { -- break; -- } - } else { - Coroutine *co = qemu_coroutine_create(backup_run_empty, vmaw); - qemu_coroutine_enter(co); -diff --git a/vma.h b/vma.h -index 98377e473e..365ceb2bcb 100644 ---- a/vma.h -+++ b/vma.h -@@ -128,6 +128,7 @@ int64_t coroutine_fn vma_writer_write(VmaWriter *vmaw, uint8_t dev_id, - 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, ...); --- -2.11.0 - diff --git a/debian/patches/pve/0047-glusterfs-allow-partial-reads.patch b/debian/patches/pve/0023-glusterfs-allow-partial-reads.patch similarity index 95% rename from debian/patches/pve/0047-glusterfs-allow-partial-reads.patch rename to debian/patches/pve/0023-glusterfs-allow-partial-reads.patch index 3d98e66..e03ad8f 100644 --- a/debian/patches/pve/0047-glusterfs-allow-partial-reads.patch +++ b/debian/patches/pve/0023-glusterfs-allow-partial-reads.patch @@ -1,7 +1,7 @@ -From 42c448d4ae35e5531023dff7ed07eb0135b3a2a2 Mon Sep 17 00:00:00 2001 +From 113e86e08a88805de1fb3aa88327174c8fa1d437 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Wed, 30 Nov 2016 10:27:47 +0100 -Subject: [PATCH 47/49] glusterfs: allow partial reads +Subject: [PATCH 23/28] glusterfs: allow partial reads This should deal with qemu bug #1644754 until upstream decides which way to go. The general direction seems to be diff --git a/debian/patches/pve/0033-block-add-the-zeroinit-block-driver-filter.patch b/debian/patches/pve/0024-block-add-the-zeroinit-block-driver-filter.patch similarity index 95% rename from debian/patches/pve/0033-block-add-the-zeroinit-block-driver-filter.patch rename to debian/patches/pve/0024-block-add-the-zeroinit-block-driver-filter.patch index 3171576..e692359 100644 --- a/debian/patches/pve/0033-block-add-the-zeroinit-block-driver-filter.patch +++ b/debian/patches/pve/0024-block-add-the-zeroinit-block-driver-filter.patch @@ -1,12 +1,12 @@ -From bdaf742bcf995c0c3f73b2e61d34b8a85199f472 Mon Sep 17 00:00:00 2001 +From f5ec823838e35470f0c9ff6bf7968ac02fa08b4d Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Thu, 17 Mar 2016 11:33:37 +0100 -Subject: [PATCH 33/49] block: add the zeroinit block driver filter +Subject: [PATCH 24/28] block: add the zeroinit block driver filter --- block/Makefile.objs | 1 + - block/zeroinit.c | 219 ++++++++++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 220 insertions(+) + block/zeroinit.c | 220 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 221 insertions(+) create mode 100644 block/zeroinit.c diff --git a/block/Makefile.objs b/block/Makefile.objs @@ -23,10 +23,10 @@ index de96f8ee80..8cdac08db5 100644 block-obj-$(CONFIG_WIN32) += file-win32.o win32-aio.o diff --git a/block/zeroinit.c b/block/zeroinit.c new file mode 100644 -index 0000000000..0a8c7f9622 +index 0000000000..a857ec3c62 --- /dev/null +++ b/block/zeroinit.c -@@ -0,0 +1,219 @@ +@@ -0,0 +1,220 @@ +/* + * Filter to fake a zero-initialized block device. + * @@ -220,6 +220,7 @@ index 0000000000..0a8c7f9622 + .bdrv_file_open = zeroinit_open, + .bdrv_close = zeroinit_close, + .bdrv_getlength = zeroinit_getlength, ++ .bdrv_child_perm = bdrv_filter_default_perms, + .bdrv_co_flush_to_disk = zeroinit_co_flush, + + .bdrv_co_pwrite_zeroes = zeroinit_co_pwrite_zeroes, diff --git a/debian/patches/pve/0050-qemu-img-dd-add-osize-and-read-from-to-stdin-stdout.patch b/debian/patches/pve/0025-qemu-img-dd-add-osize-and-read-from-to-stdin-stdout.patch similarity index 89% rename from debian/patches/pve/0050-qemu-img-dd-add-osize-and-read-from-to-stdin-stdout.patch rename to debian/patches/pve/0025-qemu-img-dd-add-osize-and-read-from-to-stdin-stdout.patch index 2c137f7..fa22468 100644 --- a/debian/patches/pve/0050-qemu-img-dd-add-osize-and-read-from-to-stdin-stdout.patch +++ b/debian/patches/pve/0025-qemu-img-dd-add-osize-and-read-from-to-stdin-stdout.patch @@ -1,7 +1,7 @@ -From 70bc584282901ee2a8954559393f305377016249 Mon Sep 17 00:00:00 2001 +From 3bd6a30a92ecb420bac469ec977fbcc0ad918d1c Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Fri, 23 Jun 2017 12:01:43 +0200 -Subject: [PATCH 50/50] qemu-img dd: add osize and read from/to stdin/stdout +Subject: [PATCH 25/28] qemu-img dd: add osize and read from/to stdin/stdout Neither convert nor dd were previously able to write to or read from a pipe. Particularly serializing an image file @@ -30,9 +30,26 @@ override the output file's size. Signed-off-by: Wolfgang Bumiller --- - qemu-img.c | 176 +++++++++++++++++++++++++++++++++++++++---------------------- - 1 file changed, 113 insertions(+), 63 deletions(-) + qemu-img-cmds.hx | 4 +- + qemu-img.c | 176 +++++++++++++++++++++++++++++++++++-------------------- + 2 files changed, 115 insertions(+), 65 deletions(-) +diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx +index 8ac78222af..16bee83987 100644 +--- a/qemu-img-cmds.hx ++++ b/qemu-img-cmds.hx +@@ -46,9 +46,9 @@ STEXI + ETEXI + + DEF("dd", img_dd, +- "dd [--image-opts] [-f fmt] [-O output_fmt] [bs=block_size] [count=blocks] [skip=blocks] if=input of=output") ++ "dd [--image-opts] [-f fmt] [-O output_fmt] [bs=block_size] [count=blocks] [skip=blocks] [osize=output_size] [if=input] [of=output]") + STEXI +-@item dd [--image-opts] [-f @var{fmt}] [-O @var{output_fmt}] [bs=@var{block_size}] [count=@var{blocks}] [skip=@var{blocks}] if=@var{input} of=@var{output} ++@item dd [--image-opts] [-f @var{fmt}] [-O @var{output_fmt}] [bs=@var{block_size}] [count=@var{blocks}] [skip=@var{blocks}] [osize=output_size] [if=@var{input}] [of=@var{output}] + ETEXI + + DEF("info", img_info, diff --git a/qemu-img.c b/qemu-img.c index 4f7f458dd2..b9d1ef7bb8 100644 --- a/qemu-img.c diff --git a/debian/patches/pve/0026-backup-modify-job-api.patch b/debian/patches/pve/0026-backup-modify-job-api.patch new file mode 100644 index 0000000..be0841d --- /dev/null +++ b/debian/patches/pve/0026-backup-modify-job-api.patch @@ -0,0 +1,100 @@ +From 020e2108f7571fac3853c47ba1ea8bafb5eef81e Mon Sep 17 00:00:00 2001 +From: Wolfgang Bumiller +Date: Wed, 9 Dec 2015 15:04:57 +0100 +Subject: [PATCH 26/28] backup: modify job api + +Introduce a pause_count parameter to start a backup in +paused mode. This way backups of multiple drives can be +started up sequentially via the completion callback while +having been started at the same point in time. +--- + block/backup.c | 2 ++ + block/replication.c | 2 +- + blockdev.c | 4 ++-- + blockjob.c | 2 +- + include/block/block_int.h | 1 + + 5 files changed, 7 insertions(+), 4 deletions(-) + +diff --git a/block/backup.c b/block/backup.c +index a4fb2884f9..1ede70c061 100644 +--- a/block/backup.c ++++ b/block/backup.c +@@ -558,6 +558,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, + BlockdevOnError on_target_error, + int creation_flags, + BlockCompletionFunc *cb, void *opaque, ++ int pause_count, + BlockJobTxn *txn, Error **errp) + { + int64_t len; +@@ -682,6 +683,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, + block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL, + &error_abort); + job->common.len = len; ++ job->common.pause_count = pause_count; + block_job_txn_add_job(txn, &job->common); + + return &job->common; +diff --git a/block/replication.c b/block/replication.c +index bf3c395eb4..1c41d9e6bf 100644 +--- a/block/replication.c ++++ b/block/replication.c +@@ -531,7 +531,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, + 0, MIRROR_SYNC_MODE_NONE, NULL, false, + BLOCKDEV_ON_ERROR_REPORT, + BLOCKDEV_ON_ERROR_REPORT, BLOCK_JOB_INTERNAL, +- backup_job_completed, bs, NULL, &local_err); ++ backup_job_completed, bs, 0, NULL, &local_err); + if (local_err) { + error_propagate(errp, local_err); + backup_job_cleanup(bs); +diff --git a/blockdev.c b/blockdev.c +index 4927914ce3..ec5e931029 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -3273,7 +3273,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup, BlockJobTxn *txn, + job = backup_job_create(backup->job_id, bs, target_bs, backup->speed, + backup->sync, bmap, backup->compress, + backup->on_source_error, backup->on_target_error, +- BLOCK_JOB_DEFAULT, NULL, NULL, txn, &local_err); ++ BLOCK_JOB_DEFAULT, NULL, NULL, 0, txn, &local_err); + bdrv_unref(target_bs); + if (local_err != NULL) { + error_propagate(errp, local_err); +@@ -3352,7 +3352,7 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn, + job = backup_job_create(backup->job_id, bs, target_bs, backup->speed, + backup->sync, NULL, backup->compress, + backup->on_source_error, backup->on_target_error, +- BLOCK_JOB_DEFAULT, NULL, NULL, txn, &local_err); ++ BLOCK_JOB_DEFAULT, NULL, NULL, 0, txn, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + } +diff --git a/blockjob.c b/blockjob.c +index 6e489327ff..764d41863e 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -289,7 +289,7 @@ void block_job_start(BlockJob *job) + job->co = qemu_coroutine_create(block_job_co_entry, job); + job->pause_count--; + job->busy = true; +- job->paused = false; ++ job->paused = job->pause_count > 0; + bdrv_coroutine_enter(blk_bs(job->blk), job->co); + } + +diff --git a/include/block/block_int.h b/include/block/block_int.h +index 59400bd848..2b3ecd0575 100644 +--- a/include/block/block_int.h ++++ b/include/block/block_int.h +@@ -878,6 +878,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, + BlockdevOnError on_target_error, + int creation_flags, + BlockCompletionFunc *cb, void *opaque, ++ int pause_count, + BlockJobTxn *txn, Error **errp); + + void hmp_drive_add_node(Monitor *mon, const char *optstr); +-- +2.11.0 + diff --git a/debian/patches/pve/0027-backup-introduce-vma-archive-format.patch b/debian/patches/pve/0027-backup-introduce-vma-archive-format.patch new file mode 100644 index 0000000..041f143 --- /dev/null +++ b/debian/patches/pve/0027-backup-introduce-vma-archive-format.patch @@ -0,0 +1,1400 @@ +From c904f41916fbfa522513267933da3f08ec74215f Mon Sep 17 00:00:00 2001 +From: Wolfgang Bumiller +Date: Wed, 2 Aug 2017 13:51:02 +0200 +Subject: [PATCH 27/28] backup: introduce vma archive format + +--- + MAINTAINERS | 6 + + block/Makefile.objs | 3 + + block/vma.c | 424 +++++++++++++++++++++++++++++++++++++++++++ + blockdev.c | 499 +++++++++++++++++++++++++++++++++++++++++++++++++++ + configure | 30 ++++ + hmp-commands-info.hx | 13 ++ + hmp-commands.hx | 31 ++++ + hmp.c | 63 +++++++ + hmp.h | 3 + + qapi-schema.json | 91 ++++++++++ + qapi/block-core.json | 20 ++- + 11 files changed, 1181 insertions(+), 2 deletions(-) + create mode 100644 block/vma.c + +diff --git a/MAINTAINERS b/MAINTAINERS +index c60235eaf6..d95f278eb4 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -1810,6 +1810,12 @@ L: qemu-block@nongnu.org + S: Supported + F: block/vvfat.c + ++VMA ++M: Wolfgang Bumiller . ++L: pve-devel@proxmox.com ++S: Supported ++F: block/vma.c ++ + Image format fuzzer + M: Stefan Hajnoczi + L: qemu-block@nongnu.org +diff --git a/block/Makefile.objs b/block/Makefile.objs +index 8cdac08db5..6df5567dd3 100644 +--- a/block/Makefile.objs ++++ b/block/Makefile.objs +@@ -21,6 +21,7 @@ block-obj-$(CONFIG_CURL) += curl.o + block-obj-$(CONFIG_RBD) += rbd.o + block-obj-$(CONFIG_GLUSTERFS) += gluster.o + block-obj-$(CONFIG_LIBSSH2) += ssh.o ++block-obj-$(CONFIG_VMA) += vma.o + block-obj-y += accounting.o dirty-bitmap.o + block-obj-y += write-threshold.o + block-obj-y += backup.o +@@ -45,3 +46,5 @@ block-obj-$(if $(CONFIG_BZIP2),m,n) += dmg-bz2.o + dmg-bz2.o-libs := $(BZIP2_LIBS) + qcow.o-libs := -lz + linux-aio.o-libs := -laio ++vma.o-cflags := $(VMA_CFLAGS) ++vma.o-libs := $(VMA_LIBS) +diff --git a/block/vma.c b/block/vma.c +new file mode 100644 +index 0000000000..7151514f94 +--- /dev/null ++++ b/block/vma.c +@@ -0,0 +1,424 @@ ++/* ++ * VMA archive backend for QEMU, container object ++ * ++ * Copyright (C) 2017 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 ++ ++#include "qemu/osdep.h" ++#include "qemu/uuid.h" ++#include "qemu-common.h" ++#include "qapi/error.h" ++#include "qapi/qmp/qerror.h" ++#include "qapi/qmp/qstring.h" ++#include "qom/object.h" ++#include "qom/object_interfaces.h" ++#include "block/block_int.h" ++ ++/* exported interface */ ++void vma_object_add_config_file(Object *obj, const char *name, ++ const char *contents, size_t len, ++ Error **errp); ++ ++#define TYPE_VMA_OBJECT "vma" ++#define VMA_OBJECT(obj) \ ++ OBJECT_CHECK(VMAObjectState, (obj), TYPE_VMA_OBJECT) ++#define VMA_OBJECT_GET_CLASS(obj) \ ++ OBJECT_GET_CLASS(VMAObjectClass, (obj), TYPE_VMA_OBJECT) ++ ++typedef struct VMAObjectClass { ++ ObjectClass parent_class; ++} VMAObjectClass; ++ ++typedef struct VMAObjectState { ++ Object parent; ++ ++ char *filename; ++ ++ QemuUUID uuid; ++ bool blocked; ++ VMAWriter *vma; ++ QemuMutex mutex; ++} VMAObjectState; ++ ++static VMAObjectState *vma_by_id(const char *name) ++{ ++ Object *container; ++ Object *obj; ++ ++ container = object_get_objects_root(); ++ obj = object_resolve_path_component(container, name); ++ ++ return VMA_OBJECT(obj); ++} ++ ++static void vma_object_class_complete(UserCreatable *uc, Error **errp) ++{ ++ int rc; ++ VMAObjectState *vo = VMA_OBJECT(uc); ++ VMAObjectClass *voc = VMA_OBJECT_GET_CLASS(uc); ++ (void)!vo; ++ (void)!voc; ++ ++ if (!vo->filename) { ++ error_setg(errp, "Parameter 'filename' is required"); ++ return; ++ } ++ ++ rc = VMAWriter_fopen(vo->filename, &vo->vma); ++ if (rc < 0) { ++ error_setg_errno(errp, -rc, "failed to create VMA archive"); ++ return; ++ } ++ ++ rc = VMAWriter_set_uuid(vo->vma, vo->uuid.data, sizeof(vo->uuid.data)); ++ if (rc < 0) { ++ error_setg_errno(errp, -rc, "failed to set UUID of VMA archive"); ++ return; ++ } ++ ++ qemu_mutex_init(&vo->mutex); ++} ++ ++static bool vma_object_can_be_deleted(UserCreatable *uc, Error **errp) ++{ ++ //VMAObjectState *vo = VMA_OBJECT(uc); ++ //if (!vo->vma) { ++ // return true; ++ //} ++ //return false; ++ return true; ++} ++ ++static void vma_object_class_init(ObjectClass *oc, void *data) ++{ ++ UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); ++ ++ ucc->can_be_deleted = vma_object_can_be_deleted; ++ ucc->complete = vma_object_class_complete; ++} ++ ++static char *vma_object_get_filename(Object *obj, Error **errp) ++{ ++ VMAObjectState *vo = VMA_OBJECT(obj); ++ ++ return g_strdup(vo->filename); ++} ++ ++static void vma_object_set_filename(Object *obj, const char *str, Error **errp) ++{ ++ VMAObjectState *vo = VMA_OBJECT(obj); ++ ++ if (vo->vma) { ++ error_setg(errp, "filename cannot be changed after creation"); ++ return; ++ } ++ ++ g_free(vo->filename); ++ vo->filename = g_strdup(str); ++} ++ ++static char *vma_object_get_uuid(Object *obj, Error **errp) ++{ ++ VMAObjectState *vo = VMA_OBJECT(obj); ++ ++ return qemu_uuid_unparse_strdup(&vo->uuid); ++} ++ ++static void vma_object_set_uuid(Object *obj, const char *str, Error **errp) ++{ ++ VMAObjectState *vo = VMA_OBJECT(obj); ++ ++ if (vo->vma) { ++ error_setg(errp, "uuid cannot be changed after creation"); ++ return; ++ } ++ ++ qemu_uuid_parse(str, &vo->uuid); ++} ++ ++static bool vma_object_get_blocked(Object *obj, Error **errp) ++{ ++ VMAObjectState *vo = VMA_OBJECT(obj); ++ ++ return vo->blocked; ++} ++ ++static void vma_object_set_blocked(Object *obj, bool blocked, Error **errp) ++{ ++ VMAObjectState *vo = VMA_OBJECT(obj); ++ ++ (void)errp; ++ ++ vo->blocked = blocked; ++} ++ ++void vma_object_add_config_file(Object *obj, const char *name, ++ const char *contents, size_t len, ++ Error **errp) ++{ ++ int rc; ++ VMAObjectState *vo = VMA_OBJECT(obj); ++ ++ if (!vo || !vo->vma) { ++ error_setg(errp, "not a valid vma object to add config files to"); ++ return; ++ } ++ ++ rc = VMAWriter_addConfigFile(vo->vma, name, contents, len); ++ if (rc < 0) { ++ error_setg_errno(errp, -rc, "failed to add config file to VMA"); ++ return; ++ } ++} ++ ++static void vma_object_init(Object *obj) ++{ ++ VMAObjectState *vo = VMA_OBJECT(obj); ++ (void)!vo; ++ ++ object_property_add_str(obj, "filename", ++ vma_object_get_filename, vma_object_set_filename, ++ NULL); ++ object_property_add_str(obj, "uuid", ++ vma_object_get_uuid, vma_object_set_uuid, ++ NULL); ++ object_property_add_bool(obj, "blocked", ++ vma_object_get_blocked, vma_object_set_blocked, ++ NULL); ++} ++ ++static void vma_object_finalize(Object *obj) ++{ ++ VMAObjectState *vo = VMA_OBJECT(obj); ++ VMAObjectClass *voc = VMA_OBJECT_GET_CLASS(obj); ++ (void)!voc; ++ ++ qemu_mutex_destroy(&vo->mutex); ++ ++ VMAWriter_destroy(vo->vma, true); ++ g_free(vo->filename); ++} ++ ++static const TypeInfo vma_object_info = { ++ .name = TYPE_VMA_OBJECT, ++ .parent = TYPE_OBJECT, ++ .class_size = sizeof(VMAObjectClass), ++ .class_init = vma_object_class_init, ++ .instance_size = sizeof(VMAObjectState), ++ .instance_init = vma_object_init, ++ .instance_finalize = vma_object_finalize, ++ .interfaces = (InterfaceInfo[]) { ++ { TYPE_USER_CREATABLE }, ++ { } ++ } ++}; ++ ++static void register_types(void) ++{ ++ type_register_static(&vma_object_info); ++} ++ ++type_init(register_types); ++ ++typedef struct { ++ VMAObjectState *vma_obj; ++ char *name; ++ size_t device_id; ++ uint64_t byte_size; ++} BDRVVMAState; ++ ++static void qemu_vma_parse_filename(const char *filename, QDict *options, ++ Error **errp) ++{ ++ char *sep; ++ ++ sep = strchr(filename, '/'); ++ if (!sep || sep == filename) { ++ error_setg(errp, "VMA filename should be /"); ++ return; ++ } ++ ++ qdict_put(options, "vma", qstring_from_substr(filename, 0, sep-filename-1)); ++ ++ while (*sep && *sep == '/') ++ ++sep; ++ if (!*sep) { ++ error_setg(errp, "missing device name\n"); ++ return; ++ } ++ ++ qdict_put(options, "name", qstring_from_str(sep)); ++} ++ ++static QemuOptsList runtime_opts = { ++ .name = "vma-drive", ++ .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head), ++ .desc = { ++ { ++ .name = "vma", ++ .type = QEMU_OPT_STRING, ++ .help = "VMA Object name", ++ }, ++ { ++ .name = "name", ++ .type = QEMU_OPT_STRING, ++ .help = "VMA device name", ++ }, ++ { ++ .name = BLOCK_OPT_SIZE, ++ .type = QEMU_OPT_SIZE, ++ .help = "Virtual disk size" ++ }, ++ { /* end of list */ } ++ }, ++}; ++static int qemu_vma_open(BlockDriverState *bs, QDict *options, int flags, ++ Error **errp) ++{ ++ Error *local_err = NULL; ++ BDRVVMAState *s = bs->opaque; ++ QemuOpts *opts; ++ const char *vma_id, *device_name; ++ ssize_t dev_id; ++ int64_t bytes = 0; ++ int ret; ++ ++ opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); ++ qemu_opts_absorb_qdict(opts, options, &local_err); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ ret = -EINVAL; ++ goto failed_opts; ++ } ++ ++ bytes = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0), ++ BDRV_SECTOR_SIZE); ++ ++ vma_id = qemu_opt_get(opts, "vma"); ++ device_name = qemu_opt_get(opts, "name"); ++ ++ VMAObjectState *vma = vma_by_id(vma_id); ++ if (!vma) { ++ ret = -EINVAL; ++ error_setg(errp, "no such VMA object: %s", vma_id); ++ goto failed_opts; ++ } ++ ++ dev_id = VMAWriter_findDevice(vma->vma, device_name); ++ if (dev_id >= 0) { ++ error_setg(errp, "drive already exists in VMA object"); ++ ret = -EIO; ++ goto failed_opts; ++ } ++ ++ dev_id = VMAWriter_addDevice(vma->vma, device_name, (uint64_t)bytes); ++ if (dev_id < 0) { ++ error_setg_errno(errp, -dev_id, "failed to add VMA device"); ++ ret = -EIO; ++ goto failed_opts; ++ } ++ ++ object_ref(OBJECT(vma)); ++ s->vma_obj = vma; ++ s->name = g_strdup(device_name); ++ s->device_id = (size_t)dev_id; ++ s->byte_size = bytes; ++ ++ ret = 0; ++ ++failed_opts: ++ qemu_opts_del(opts); ++ return ret; ++} ++ ++static void qemu_vma_close(BlockDriverState *bs) ++{ ++ BDRVVMAState *s = bs->opaque; ++ ++ (void)VMAWriter_finishDevice(s->vma_obj->vma, s->device_id); ++ object_unref(OBJECT(s->vma_obj)); ++ ++ g_free(s->name); ++} ++ ++static int64_t qemu_vma_getlength(BlockDriverState *bs) ++{ ++ BDRVVMAState *s = bs->opaque; ++ ++ return s->byte_size; ++} ++ ++static coroutine_fn int qemu_vma_co_writev(BlockDriverState *bs, ++ int64_t sector_num, ++ int nb_sectors, ++ QEMUIOVector *qiov) ++{ ++ size_t i; ++ ssize_t rc; ++ BDRVVMAState *s = bs->opaque; ++ VMAObjectState *vo = s->vma_obj; ++ off_t offset = sector_num * BDRV_SECTOR_SIZE; ++ ++ qemu_mutex_lock(&vo->mutex); ++ if (vo->blocked) { ++ return -EPERM; ++ } ++ for (i = 0; i != qiov->niov; ++i) { ++ const struct iovec *v = &qiov->iov[i]; ++ size_t blocks = v->iov_len / VMA_BLOCK_SIZE; ++ if (blocks * VMA_BLOCK_SIZE != v->iov_len) { ++ return -EIO; ++ } ++ rc = VMAWriter_writeBlocks(vo->vma, s->device_id, ++ v->iov_base, blocks, offset); ++ if (errno) { ++ return -errno; ++ } ++ if (rc != blocks) { ++ return -EIO; ++ } ++ offset += v->iov_len; ++ } ++ qemu_mutex_unlock(&vo->mutex); ++ return 0; ++} ++ ++static int qemu_vma_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) ++{ ++ bdi->cluster_size = VMA_CLUSTER_SIZE; ++ bdi->unallocated_blocks_are_zero = true; ++ bdi->can_write_zeroes_with_unmap = false; ++ return 0; ++} ++ ++static BlockDriver bdrv_vma_drive = { ++ .format_name = "vma-drive", ++ .instance_size = sizeof(BDRVVMAState), ++ ++#if 0 ++ .bdrv_create = qemu_vma_create, ++ .create_opts = &qemu_vma_create_opts, ++#endif ++ ++ .bdrv_parse_filename = qemu_vma_parse_filename, ++ .bdrv_file_open = qemu_vma_open, ++ ++ .bdrv_close = qemu_vma_close, ++ .bdrv_has_zero_init = bdrv_has_zero_init_1, ++ .bdrv_getlength = qemu_vma_getlength, ++ .bdrv_get_info = qemu_vma_get_info, ++ ++ .bdrv_co_writev = qemu_vma_co_writev, ++}; ++ ++static void bdrv_vma_init(void) ++{ ++ bdrv_register(&bdrv_vma_drive); ++} ++ ++block_init(bdrv_vma_init); +diff --git a/blockdev.c b/blockdev.c +index ec5e931029..981276692a 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -31,10 +31,12 @@ + */ + + #include "qemu/osdep.h" ++#include "qemu/uuid.h" + #include "sysemu/block-backend.h" + #include "sysemu/blockdev.h" + #include "hw/block/block.h" + #include "block/blockjob.h" ++#include "block/blockjob_int.h" + #include "block/throttle-groups.h" + #include "monitor/monitor.h" + #include "qemu/error-report.h" +@@ -2956,6 +2958,503 @@ out: + aio_context_release(aio_context); + } + ++/* PVE backup related function */ ++ ++static struct PVEBackupState { ++ Error *error; ++ bool cancel; ++ QemuUUID uuid; ++ char uuid_str[37]; ++ int64_t speed; ++ time_t start_time; ++ time_t end_time; ++ char *backup_file; ++ Object *vmaobj; ++ GList *di_list; ++ size_t next_job; ++ size_t total; ++ size_t transferred; ++ size_t zero_bytes; ++} backup_state; ++ ++typedef struct PVEBackupDevInfo { ++ BlockDriverState *bs; ++ size_t size; ++ uint8_t dev_id; ++ bool completed; ++ char targetfile[PATH_MAX]; ++ BlockDriverState *target; ++} PVEBackupDevInfo; ++ ++static void pvebackup_run_next_job(void); ++ ++static void pvebackup_cleanup(void) ++{ ++ backup_state.end_time = time(NULL); ++ ++ if (backup_state.vmaobj) { ++ object_unparent(backup_state.vmaobj); ++ backup_state.vmaobj = NULL; ++ } ++ ++ if (backup_state.di_list) { ++ GList *l = backup_state.di_list; ++ while (l) { ++ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; ++ l = g_list_next(l); ++ g_free(di); ++ } ++ g_list_free(backup_state.di_list); ++ backup_state.di_list = NULL; ++ } ++} ++ ++static void pvebackup_complete_cb(void *opaque, int ret) ++{ ++ PVEBackupDevInfo *di = opaque; ++ ++ di->completed = true; ++ ++ if (ret < 0 && !backup_state.error) { ++ error_setg(&backup_state.error, "job failed with err %d - %s", ++ ret, strerror(-ret)); ++ } ++ ++ di->bs = NULL; ++ di->target = NULL; ++ ++ if (backup_state.vmaobj) { ++ object_unparent(backup_state.vmaobj); ++ backup_state.vmaobj = NULL; ++ } ++ ++ if (!backup_state.cancel) { ++ pvebackup_run_next_job(); ++ } ++} ++ ++static void pvebackup_cancel(void *opaque) ++{ ++ backup_state.cancel = true; ++ ++ if (!backup_state.error) { ++ error_setg(&backup_state.error, "backup cancelled"); ++ } ++ ++ if (backup_state.vmaobj) { ++ Error *err; ++ /* make sure vma writer does not block anymore */ ++ if (!object_set_props(backup_state.vmaobj, &err, "blocked", "yes", NULL)) { ++ if (err) { ++ error_report_err(err); ++ } ++ } ++ } ++ ++ GList *l = backup_state.di_list; ++ while (l) { ++ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; ++ l = g_list_next(l); ++ if (!di->completed && di->bs) { ++ BlockJob *job = di->bs->job; ++ if (job) { ++ if (!di->completed) { ++ block_job_cancel_sync(job); ++ } ++ } ++ } ++ } ++ ++ pvebackup_cleanup(); ++} ++ ++void qmp_backup_cancel(Error **errp) ++{ ++ Coroutine *co = qemu_coroutine_create(pvebackup_cancel, NULL); ++ qemu_coroutine_enter(co); ++ ++ while (backup_state.vmaobj) { ++ /* FIXME: Find something better for this */ ++ aio_poll(qemu_get_aio_context(), true); ++ } ++} ++ ++void vma_object_add_config_file(Object *obj, const char *name, ++ const char *contents, size_t len, ++ Error **errp); ++static int config_to_vma(const char *file, BackupFormat format, ++ Object *vmaobj, ++ const char *backup_dir, ++ Error **errp) ++{ ++ char *cdata = NULL; ++ gsize clen = 0; ++ GError *err = NULL; ++ if (!g_file_get_contents(file, &cdata, &clen, &err)) { ++ error_setg(errp, "unable to read file '%s'", file); ++ return 1; ++ } ++ ++ char *basename = g_path_get_basename(file); ++ ++ if (format == BACKUP_FORMAT_VMA) { ++ vma_object_add_config_file(vmaobj, basename, cdata, clen, errp); ++ } else if (format == BACKUP_FORMAT_DIR) { ++ char config_path[PATH_MAX]; ++ snprintf(config_path, PATH_MAX, "%s/%s", backup_dir, basename); ++ if (!g_file_set_contents(config_path, cdata, clen, &err)) { ++ error_setg(errp, "unable to write config file '%s'", config_path); ++ g_free(cdata); ++ g_free(basename); ++ return 1; ++ } ++ } ++ ++ g_free(basename); ++ g_free(cdata); ++ ++ return 0; ++} ++ ++static void pvebackup_run_next_job(void) ++{ ++ bool cancel = backup_state.error || backup_state.cancel; ++fprintf(stderr, "run next job: %zu\n", backup_state.next_job); ++ GList *next = g_list_nth(backup_state.di_list, backup_state.next_job); ++ while (next) { ++ PVEBackupDevInfo *di = (PVEBackupDevInfo *)next->data; ++ backup_state.next_job++; ++ if (!di->completed && di->bs && di->bs->job) { ++ BlockJob *job = di->bs->job; ++ if (cancel) { ++ block_job_cancel(job); ++ } else { ++ block_job_resume(job); ++ } ++ return; ++ } ++ next = g_list_next(next); ++ } ++ pvebackup_cleanup(); ++} ++ ++UuidInfo *qmp_backup(const char *backup_file, bool has_format, ++ BackupFormat format, ++ bool has_config_file, const char *config_file, ++ bool has_firewall_file, const char *firewall_file, ++ bool has_devlist, const char *devlist, ++ bool has_speed, int64_t speed, Error **errp) ++{ ++ BlockBackend *blk; ++ BlockDriverState *bs = NULL; ++ const char *backup_dir = NULL; ++ Error *local_err = NULL; ++ QemuUUID uuid; ++ gchar **devs = NULL; ++ GList *di_list = NULL; ++ GList *l; ++ UuidInfo *uuid_info; ++ BlockJob *job; ++ ++ if (backup_state.di_list || backup_state.vmaobj) { ++ error_set(errp, ERROR_CLASS_GENERIC_ERROR, ++ "previous backup not finished"); ++ return NULL; ++ } ++ ++ /* Todo: try to auto-detect format based on file name */ ++ format = has_format ? format : BACKUP_FORMAT_VMA; ++ ++ if (has_devlist) { ++ devs = g_strsplit_set(devlist, ",;:", -1); ++ ++ gchar **d = devs; ++ while (d && *d) { ++ blk = blk_by_name(*d); ++ if (blk) { ++ bs = blk_bs(blk); ++ if (bdrv_is_read_only(bs)) { ++ error_setg(errp, "Node '%s' is read only", *d); ++ goto err; ++ } ++ if (!bdrv_is_inserted(bs)) { ++ error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, *d); ++ goto err; ++ } ++ PVEBackupDevInfo *di = g_new0(PVEBackupDevInfo, 1); ++ di->bs = bs; ++ di_list = g_list_append(di_list, di); ++ } else { ++ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, ++ "Device '%s' not found", *d); ++ goto err; ++ } ++ d++; ++ } ++ ++ } else { ++ BdrvNextIterator it; ++ ++ bs = NULL; ++ for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { ++ if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) { ++ continue; ++ } ++ ++ PVEBackupDevInfo *di = g_new0(PVEBackupDevInfo, 1); ++ di->bs = bs; ++ di_list = g_list_append(di_list, di); ++ } ++ } ++ ++ if (!di_list) { ++ error_set(errp, ERROR_CLASS_GENERIC_ERROR, "empty device list"); ++ goto err; ++ } ++ ++ size_t total = 0; ++ ++ l = di_list; ++ while (l) { ++ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; ++ l = g_list_next(l); ++ if (bdrv_op_is_blocked(di->bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) { ++ goto err; ++ } ++ ++ ssize_t size = bdrv_getlength(di->bs); ++ if (size < 0) { ++ error_setg_errno(errp, -di->size, "bdrv_getlength failed"); ++ goto err; ++ } ++ di->size = size; ++ total += size; ++ } ++ ++ qemu_uuid_generate(&uuid); ++ ++ if (format == BACKUP_FORMAT_VMA) { ++ char uuidstr[UUID_FMT_LEN+1]; ++ qemu_uuid_unparse(&uuid, uuidstr); ++ uuidstr[UUID_FMT_LEN] = 0; ++ backup_state.vmaobj = ++ object_new_with_props("vma", object_get_objects_root(), ++ "vma-backup-obj", &local_err, ++ "filename", backup_file, ++ "uuid", uuidstr, ++ NULL); ++ if (!backup_state.vmaobj) { ++ if (local_err) { ++ error_propagate(errp, local_err); ++ } ++ goto err; ++ } ++ ++ l = di_list; ++ while (l) { ++ QDict *options = qdict_new(); ++ ++ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; ++ l = g_list_next(l); ++ ++ const char *devname = bdrv_get_device_name(di->bs); ++ snprintf(di->targetfile, PATH_MAX, "vma-backup-obj/%s.raw", devname); ++ ++ qdict_put(options, "driver", qstring_from_str("vma-drive")); ++ qdict_put(options, "size", qint_from_int(di->size)); ++ di->target = bdrv_open(di->targetfile, NULL, options, BDRV_O_RDWR, &local_err); ++ if (!di->target) { ++ error_propagate(errp, local_err); ++ goto err; ++ } ++ } ++ } else if (format == BACKUP_FORMAT_DIR) { ++ if (mkdir(backup_file, 0640) != 0) { ++ error_setg_errno(errp, errno, "can't create directory '%s'\n", ++ backup_file); ++ goto err; ++ } ++ backup_dir = backup_file; ++ ++ l = di_list; ++ while (l) { ++ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; ++ l = g_list_next(l); ++ ++ const char *devname = bdrv_get_device_name(di->bs); ++ snprintf(di->targetfile, PATH_MAX, "%s/%s.raw", backup_dir, devname); ++ ++ int flags = BDRV_O_RDWR; ++ bdrv_img_create(di->targetfile, "raw", NULL, NULL, NULL, ++ di->size, flags, &local_err, false); ++ if (local_err) { ++ error_propagate(errp, local_err); ++ goto err; ++ } ++ ++ di->target = bdrv_open(di->targetfile, NULL, NULL, flags, &local_err); ++ if (!di->target) { ++ error_propagate(errp, local_err); ++ goto err; ++ } ++ } ++ } else { ++ error_set(errp, ERROR_CLASS_GENERIC_ERROR, "unknown backup format"); ++ goto err; ++ } ++ ++ /* add configuration file to archive */ ++ if (has_config_file) { ++ if(config_to_vma(config_file, format, backup_state.vmaobj, backup_dir, errp) != 0) { ++ goto err; ++ } ++ } ++ ++ /* add firewall file to archive */ ++ if (has_firewall_file) { ++ if(config_to_vma(firewall_file, format, backup_state.vmaobj, backup_dir, errp) != 0) { ++ goto err; ++ } ++ } ++ /* initialize global backup_state now */ ++ ++ backup_state.cancel = false; ++ ++ if (backup_state.error) { ++ error_free(backup_state.error); ++ backup_state.error = NULL; ++ } ++ ++ backup_state.speed = (has_speed && speed > 0) ? speed : 0; ++ ++ backup_state.start_time = time(NULL); ++ backup_state.end_time = 0; ++ ++ if (backup_state.backup_file) { ++ g_free(backup_state.backup_file); ++ } ++ backup_state.backup_file = g_strdup(backup_file); ++ ++ memcpy(&backup_state.uuid, &uuid, sizeof(uuid)); ++ qemu_uuid_unparse(&uuid, backup_state.uuid_str); ++ ++ backup_state.di_list = di_list; ++ backup_state.next_job = 0; ++ ++ backup_state.total = total; ++ backup_state.transferred = 0; ++ backup_state.zero_bytes = 0; ++ ++ /* start all jobs (paused state) */ ++ l = di_list; ++ while (l) { ++ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; ++ l = g_list_next(l); ++ ++ job = backup_job_create(NULL, di->bs, di->target, speed, MIRROR_SYNC_MODE_FULL, NULL, ++ false, BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT, ++ BLOCK_JOB_DEFAULT, ++ pvebackup_complete_cb, di, 2, NULL, &local_err); ++ if (di->target) { ++ bdrv_unref(di->target); ++ di->target = NULL; ++ } ++ if (!job || local_err != NULL) { ++ error_setg(&backup_state.error, "backup_job_create failed"); ++ pvebackup_cancel(NULL); ++ } else { ++ block_job_start(job); ++ } ++ } ++ ++ if (!backup_state.error) { ++ pvebackup_run_next_job(); // run one job ++ } ++ ++ uuid_info = g_malloc0(sizeof(*uuid_info)); ++ uuid_info->UUID = g_strdup(backup_state.uuid_str); ++ ++ return uuid_info; ++ ++err: ++ ++ l = di_list; ++ while (l) { ++ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; ++ l = g_list_next(l); ++ ++ if (di->target) { ++ bdrv_unref(di->target); ++ } ++ ++ if (di->targetfile[0]) { ++ unlink(di->targetfile); ++ } ++ g_free(di); ++ } ++ g_list_free(di_list); ++ ++ if (devs) { ++ g_strfreev(devs); ++ } ++ ++ if (backup_state.vmaobj) { ++ object_unparent(backup_state.vmaobj); ++ backup_state.vmaobj = NULL; ++ } ++ ++ if (backup_dir) { ++ rmdir(backup_dir); ++ } ++ ++ return NULL; ++} ++ ++BackupStatus *qmp_query_backup(Error **errp) ++{ ++ BackupStatus *info = g_malloc0(sizeof(*info)); ++ ++ if (!backup_state.start_time) { ++ /* not started, return {} */ ++ return info; ++ } ++ ++ info->has_status = true; ++ info->has_start_time = true; ++ info->start_time = backup_state.start_time; ++ ++ if (backup_state.backup_file) { ++ info->has_backup_file = true; ++ info->backup_file = g_strdup(backup_state.backup_file); ++ } ++ ++ info->has_uuid = true; ++ info->uuid = g_strdup(backup_state.uuid_str); ++ ++ if (backup_state.end_time) { ++ if (backup_state.error) { ++ info->status = g_strdup("error"); ++ info->has_errmsg = true; ++ info->errmsg = g_strdup(error_get_pretty(backup_state.error)); ++ } else { ++ info->status = g_strdup("done"); ++ } ++ info->has_end_time = true; ++ info->end_time = backup_state.end_time; ++ } else { ++ info->status = g_strdup("active"); ++ } ++ ++ info->has_total = true; ++ info->total = backup_state.total; ++ info->has_zero_bytes = true; ++ info->zero_bytes = backup_state.zero_bytes; ++ info->has_transferred = true; ++ info->transferred = backup_state.transferred; ++ ++ return info; ++} ++ + void qmp_block_stream(bool has_job_id, const char *job_id, const char *device, + bool has_base, const char *base, + bool has_base_node, const char *base_node, +diff --git a/configure b/configure +index be4d326ae0..841f7a8fae 100755 +--- a/configure ++++ b/configure +@@ -320,6 +320,7 @@ numa="" + tcmalloc="no" + jemalloc="no" + replication="yes" ++vma="" + + supported_cpu="no" + supported_os="no" +@@ -1183,6 +1184,10 @@ for opt do + ;; + --enable-replication) replication="yes" + ;; ++ --disable-vma) vma="no" ++ ;; ++ --enable-vma) vma="yes" ++ ;; + *) + echo "ERROR: unknown option $opt" + echo "Try '$0 --help' for more information" +@@ -1427,6 +1432,7 @@ disabled with --disable-FEATURE, default is enabled if available: + xfsctl xfsctl support + qom-cast-debug cast debugging support + tools build qemu-io, qemu-nbd and qemu-image tools ++ vma VMA archive backend + + NOTE: The object files are built at the place where configure is launched + EOF +@@ -3705,6 +3711,23 @@ EOF + fi + + ########################################## ++# vma probe ++if test "$vma" != "no" ; then ++ if $pkg_config --exact-version=0.1.0 vma; then ++ vma="yes" ++ vma_cflags=$($pkg_config --cflags vma) ++ vma_libs=$($pkg_config --libs vma) ++ else ++ if test "$vma" = "yes" ; then ++ feature_not_found "VMA Archive backend support" \ ++ "Install libvma devel" ++ fi ++ vma="no" ++ fi ++fi ++ ++ ++########################################## + # signalfd probe + signalfd="no" + cat > $TMPC << EOF +@@ -5146,6 +5169,7 @@ echo "tcmalloc support $tcmalloc" + echo "jemalloc support $jemalloc" + echo "avx2 optimization $avx2_opt" + echo "replication support $replication" ++echo "VMA support $vma" + + if test "$sdl_too_old" = "yes"; then + echo "-> Your SDL version is too old - please upgrade to have SDL support" +@@ -5703,6 +5727,12 @@ if test "$libssh2" = "yes" ; then + echo "LIBSSH2_LIBS=$libssh2_libs" >> $config_host_mak + fi + ++if test "$vma" = "yes" ; then ++ echo "CONFIG_VMA=y" >> $config_host_mak ++ echo "VMA_CFLAGS=$vma_cflags" >> $config_host_mak ++ echo "VMA_LIBS=$vma_libs" >> $config_host_mak ++fi ++ + # USB host support + if test "$libusb" = "yes"; then + echo "HOST_USB=libusb legacy" >> $config_host_mak +diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx +index 5fc57a2210..3b5a0f95e4 100644 +--- a/hmp-commands-info.hx ++++ b/hmp-commands-info.hx +@@ -487,6 +487,19 @@ STEXI + Show CPU statistics. + ETEXI + ++ { ++ .name = "backup", ++ .args_type = "", ++ .params = "", ++ .help = "show backup status", ++ .cmd = hmp_info_backup, ++ }, ++ ++STEXI ++@item info backup ++show backup status ++ETEXI ++ + #if defined(CONFIG_SLIRP) + { + .name = "usernet", +diff --git a/hmp-commands.hx b/hmp-commands.hx +index 58940a762b..a2867b56f2 100644 +--- a/hmp-commands.hx ++++ b/hmp-commands.hx +@@ -87,6 +87,37 @@ STEXI + Copy data from a backing file into a block device. + ETEXI + ++ { ++ .name = "backup", ++ .args_type = "directory:-d,backupfile:s,speed:o?,devlist:s?", ++ .params = "[-d] backupfile [speed [devlist]]", ++ .help = "create a VM Backup." ++ "\n\t\t\t Use -d to dump data into a directory instead" ++ "\n\t\t\t of using VMA format.", ++ .cmd = hmp_backup, ++ }, ++ ++STEXI ++@item backup ++@findex backup ++Create a VM backup. ++ETEXI ++ ++ { ++ .name = "backup_cancel", ++ .args_type = "", ++ .params = "", ++ .help = "cancel the current VM backup", ++ .cmd = hmp_backup_cancel, ++ }, ++ ++STEXI ++@item backup_cancel ++@findex backup_cancel ++Cancel the current VM backup. ++ ++ETEXI ++ + { + .name = "block_job_set_speed", + .args_type = "device:B,speed:o", +diff --git a/hmp.c b/hmp.c +index f725d061e6..12f1f46125 100644 +--- a/hmp.c ++++ b/hmp.c +@@ -151,6 +151,44 @@ void hmp_info_mice(Monitor *mon, const QDict *qdict) + qapi_free_MouseInfoList(mice_list); + } + ++void hmp_info_backup(Monitor *mon, const QDict *qdict) ++{ ++ BackupStatus *info; ++ ++ info = qmp_query_backup(NULL); ++ if (info->has_status) { ++ if (info->has_errmsg) { ++ monitor_printf(mon, "Backup status: %s - %s\n", ++ info->status, info->errmsg); ++ } else { ++ monitor_printf(mon, "Backup status: %s\n", info->status); ++ } ++ } ++ ++ if (info->has_backup_file) { ++ monitor_printf(mon, "Start time: %s", ctime(&info->start_time)); ++ if (info->end_time) { ++ monitor_printf(mon, "End time: %s", ctime(&info->end_time)); ++ } ++ ++ int per = (info->has_total && info->total && ++ info->has_transferred && info->transferred) ? ++ (info->transferred * 100)/info->total : 0; ++ int zero_per = (info->has_total && info->total && ++ info->has_zero_bytes && info->zero_bytes) ? ++ (info->zero_bytes * 100)/info->total : 0; ++ monitor_printf(mon, "Backup file: %s\n", info->backup_file); ++ monitor_printf(mon, "Backup uuid: %s\n", info->uuid); ++ monitor_printf(mon, "Total size: %zd\n", info->total); ++ monitor_printf(mon, "Transferred bytes: %zd (%d%%)\n", ++ info->transferred, per); ++ monitor_printf(mon, "Zero bytes: %zd (%d%%)\n", ++ info->zero_bytes, zero_per); ++ } ++ ++ qapi_free_BackupStatus(info); ++} ++ + void hmp_info_migrate(Monitor *mon, const QDict *qdict) + { + MigrationInfo *info; +@@ -1613,6 +1651,31 @@ void hmp_block_stream(Monitor *mon, const QDict *qdict) + hmp_handle_error(mon, &error); + } + ++void hmp_backup_cancel(Monitor *mon, const QDict *qdict) ++{ ++ Error *error = NULL; ++ ++ qmp_backup_cancel(&error); ++ ++ hmp_handle_error(mon, &error); ++} ++ ++void hmp_backup(Monitor *mon, const QDict *qdict) ++{ ++ Error *error = NULL; ++ ++ int dir = qdict_get_try_bool(qdict, "directory", 0); ++ const char *backup_file = qdict_get_str(qdict, "backupfile"); ++ const char *devlist = qdict_get_try_str(qdict, "devlist"); ++ int64_t speed = qdict_get_try_int(qdict, "speed", 0); ++ ++ qmp_backup(backup_file, true, dir ? BACKUP_FORMAT_DIR : BACKUP_FORMAT_VMA, ++ false, NULL, false, NULL, !!devlist, ++ devlist, qdict_haskey(qdict, "speed"), speed, &error); ++ ++ hmp_handle_error(mon, &error); ++} ++ + void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict) + { + Error *error = NULL; +diff --git a/hmp.h b/hmp.h +index 0497afbf65..8c1b4846b3 100644 +--- a/hmp.h ++++ b/hmp.h +@@ -31,6 +31,7 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict); + void hmp_info_migrate_capabilities(Monitor *mon, const QDict *qdict); + void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict); + void hmp_info_migrate_cache_size(Monitor *mon, const QDict *qdict); ++void hmp_info_backup(Monitor *mon, const QDict *qdict); + void hmp_info_cpus(Monitor *mon, const QDict *qdict); + void hmp_info_block(Monitor *mon, const QDict *qdict); + void hmp_info_blockstats(Monitor *mon, const QDict *qdict); +@@ -80,6 +81,8 @@ void hmp_eject(Monitor *mon, const QDict *qdict); + void hmp_change(Monitor *mon, const QDict *qdict); + void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict); + void hmp_block_stream(Monitor *mon, const QDict *qdict); ++void hmp_backup(Monitor *mon, const QDict *qdict); ++void hmp_backup_cancel(Monitor *mon, const QDict *qdict); + void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict); + void hmp_block_job_cancel(Monitor *mon, const QDict *qdict); + void hmp_block_job_pause(Monitor *mon, const QDict *qdict); +diff --git a/qapi-schema.json b/qapi-schema.json +index 5e82933ca1..b20020a054 100644 +--- a/qapi-schema.json ++++ b/qapi-schema.json +@@ -571,6 +571,97 @@ + { 'command': 'query-events', 'returns': ['EventInfo'] } + + ## ++# @BackupStatus: ++# ++# Detailed backup status. ++# ++# @status: string describing the current backup status. ++# This can be 'active', 'done', 'error'. If this field is not ++# returned, no backup process has been initiated ++# ++# @errmsg: error message (only returned if status is 'error') ++# ++# @total: total amount of bytes involved in the backup process ++# ++# @transferred: amount of bytes already backed up. ++# ++# @zero-bytes: amount of 'zero' bytes detected. ++# ++# @start-time: time (epoch) when backup job started. ++# ++# @end-time: time (epoch) when backup job finished. ++# ++# @backup-file: backup file name ++# ++# @uuid: uuid for this backup job ++# ++## ++{ 'struct': 'BackupStatus', ++ 'data': {'*status': 'str', '*errmsg': 'str', '*total': 'int', ++ '*transferred': 'int', '*zero-bytes': 'int', ++ '*start-time': 'int', '*end-time': 'int', ++ '*backup-file': 'str', '*uuid': 'str' } } ++ ++## ++# @BackupFormat: ++# ++# An enumeration of supported backup formats. ++# ++# @vma: Proxmox vma backup format ++## ++{ 'enum': 'BackupFormat', ++ 'data': [ 'vma', 'dir' ] } ++ ++## ++# @backup: ++# ++# Starts a VM backup. ++# ++# @backup-file: the backup file name ++# ++# @format: format of the backup file ++# ++# @config-file: a configuration file to include into ++# the backup archive. ++# ++# @speed: the maximum speed, in bytes per second ++# ++# @devlist: list of block device names (separated by ',', ';' ++# or ':'). By default the backup includes all writable block devices. ++# ++# Returns: the uuid of the backup job ++# ++## ++{ 'command': 'backup', 'data': { 'backup-file': 'str', ++ '*format': 'BackupFormat', ++ '*config-file': 'str', ++ '*firewall-file': 'str', ++ '*devlist': 'str', '*speed': 'int' }, ++ 'returns': 'UuidInfo' } ++ ++## ++# @query-backup: ++# ++# Returns information about current/last backup task. ++# ++# Returns: @BackupStatus ++# ++## ++{ 'command': 'query-backup', 'returns': 'BackupStatus' } ++ ++## ++# @backup-cancel: ++# ++# Cancel the current executing backup process. ++# ++# Returns: nothing on success ++# ++# Notes: This command succeeds even if there is no backup process running. ++# ++## ++{ 'command': 'backup-cancel' } ++ ++## + # @MigrationStats: + # + # Detailed migration status. +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 033457ce86..891afe5eaa 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -2116,7 +2116,7 @@ + 'host_device', 'http', 'https', 'iscsi', 'luks', 'nbd', 'nfs', + 'null-aio', 'null-co', 'parallels', 'qcow', 'qcow2', 'qed', + 'quorum', 'raw', 'rbd', 'replication', 'sheepdog', 'ssh', +- 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat' ] } ++ 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vma-drive' ] } + + ## + # @BlockdevOptionsFile: +@@ -2866,6 +2866,21 @@ + 'data': { '*offset': 'int', '*size': 'int' } } + + ## ++# @BlockdevOptionsVMADrive: ++# ++# Driver specific block device options for VMA Drives ++# ++# @filename: vma-drive path ++# ++# @size: drive size in bytes ++# ++# Since: 2.9 ++## ++{ 'struct': 'BlockdevOptionsVMADrive', ++ 'data': { 'filename': 'str', ++ 'size': 'int' } } ++ ++## + # @BlockdevOptions: + # + # Options for creating a block device. Many options are available for all +@@ -2927,7 +2942,8 @@ + 'vhdx': 'BlockdevOptionsGenericFormat', + 'vmdk': 'BlockdevOptionsGenericCOWFormat', + 'vpc': 'BlockdevOptionsGenericFormat', +- 'vvfat': 'BlockdevOptionsVVFAT' ++ 'vvfat': 'BlockdevOptionsVVFAT', ++ 'vma-drive': 'BlockdevOptionsVMADrive' + } } + + ## +-- +2.11.0 + diff --git a/debian/patches/pve/0027-vma-add-firewall.patch b/debian/patches/pve/0027-vma-add-firewall.patch deleted file mode 100644 index d83386d..0000000 --- a/debian/patches/pve/0027-vma-add-firewall.patch +++ /dev/null @@ -1,144 +0,0 @@ -From 23aa2199f34c16254bd342abbd3ae2b16e4aa64e Mon Sep 17 00:00:00 2001 -From: Wolfgang Bumiller -Date: Wed, 9 Dec 2015 16:51:23 +0100 -Subject: [PATCH 27/49] vma: add firewall - ---- - blockdev.c | 78 ++++++++++++++++++++++++++++++++++---------------------- - hmp.c | 2 +- - qapi-schema.json | 1 + - 3 files changed, 50 insertions(+), 31 deletions(-) - -diff --git a/blockdev.c b/blockdev.c -index 2713585051..43818dade1 100644 ---- a/blockdev.c -+++ b/blockdev.c -@@ -3163,6 +3163,44 @@ void qmp_backup_cancel(Error **errp) - } - } - -+static int config_to_vma(const char *file, BackupFormat format, -+ const char *backup_dir, VmaWriter *vmaw, -+ Error **errp) -+{ -+ char *cdata = NULL; -+ gsize clen = 0; -+ GError *err = NULL; -+ if (!g_file_get_contents(file, &cdata, &clen, &err)) { -+ error_setg(errp, "unable to read file '%s'", file); -+ return 1; -+ } -+ -+ char *basename = g_path_get_basename(file); -+ -+ if (format == BACKUP_FORMAT_VMA) { -+ if (vma_writer_add_config(vmaw, basename, cdata, clen) != 0) { -+ error_setg(errp, "unable to add %s config data to vma archive", file); -+ g_free(cdata); -+ g_free(basename); -+ return 1; -+ } -+ } else if (format == BACKUP_FORMAT_DIR) { -+ char config_path[PATH_MAX]; -+ snprintf(config_path, PATH_MAX, "%s/%s", backup_dir, basename); -+ if (!g_file_set_contents(config_path, cdata, clen, &err)) { -+ error_setg(errp, "unable to write config file '%s'", config_path); -+ g_free(cdata); -+ g_free(basename); -+ return 1; -+ } -+ } -+ -+ g_free(basename); -+ g_free(cdata); -+ -+ return 0; -+} -+ - bool block_job_should_pause(BlockJob *job); - static void pvebackup_run_next_job(void) - { -@@ -3190,6 +3228,7 @@ static void pvebackup_run_next_job(void) - UuidInfo *qmp_backup(const char *backup_file, bool has_format, - BackupFormat format, - bool has_config_file, const char *config_file, -+ bool has_firewall_file, const char *firewall_file, - bool has_devlist, const char *devlist, - bool has_speed, int64_t speed, Error **errp) - { -@@ -3342,38 +3381,17 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format, - - /* add configuration file to archive */ - if (has_config_file) { -- char *cdata = NULL; -- gsize clen = 0; -- GError *err = NULL; -- if (!g_file_get_contents(config_file, &cdata, &clen, &err)) { -- error_setg(errp, "unable to read file '%s'", config_file); -- goto err; -- } -- -- char *basename = g_path_get_basename(config_file); -- -- if (format == BACKUP_FORMAT_VMA) { -- if (vma_writer_add_config(vmaw, basename, cdata, clen) != 0) { -- error_setg(errp, "unable to add config data to vma archive"); -- g_free(cdata); -- g_free(basename); -- goto err; -- } -- } else if (format == BACKUP_FORMAT_DIR) { -- char config_path[PATH_MAX]; -- snprintf(config_path, PATH_MAX, "%s/%s", backup_dir, basename); -- if (!g_file_set_contents(config_path, cdata, clen, &err)) { -- error_setg(errp, "unable to write config file '%s'", config_path); -- g_free(cdata); -- g_free(basename); -- goto err; -- } -- } -- -- g_free(basename); -- g_free(cdata); -+ if(config_to_vma(config_file, format, backup_dir, vmaw, errp) != 0) { -+ goto err; -+ } - } - -+ /* add firewall file to archive */ -+ if (has_firewall_file) { -+ if(config_to_vma(firewall_file, format, backup_dir, vmaw, errp) != 0) { -+ goto err; -+ } -+ } - /* initialize global backup_state now */ - - backup_state.cancel = false; -diff --git a/hmp.c b/hmp.c -index aaf0de1642..12f1f46125 100644 ---- a/hmp.c -+++ b/hmp.c -@@ -1670,7 +1670,7 @@ void hmp_backup(Monitor *mon, const QDict *qdict) - int64_t speed = qdict_get_try_int(qdict, "speed", 0); - - qmp_backup(backup_file, true, dir ? BACKUP_FORMAT_DIR : BACKUP_FORMAT_VMA, -- false, NULL, !!devlist, -+ false, NULL, false, NULL, !!devlist, - devlist, qdict_haskey(qdict, "speed"), speed, &error); - - hmp_handle_error(mon, &error); -diff --git a/qapi-schema.json b/qapi-schema.json -index 21f822aada..b20020a054 100644 ---- a/qapi-schema.json -+++ b/qapi-schema.json -@@ -635,6 +635,7 @@ - { 'command': 'backup', 'data': { 'backup-file': 'str', - '*format': 'BackupFormat', - '*config-file': 'str', -+ '*firewall-file': 'str', - '*devlist': 'str', '*speed': 'int' }, - 'returns': 'UuidInfo' } - --- -2.11.0 - diff --git a/debian/patches/pve/0011-introduce-new-vma-archive-format.patch b/debian/patches/pve/0028-adding-old-vma-files.patch similarity index 59% rename from debian/patches/pve/0011-introduce-new-vma-archive-format.patch rename to debian/patches/pve/0028-adding-old-vma-files.patch index 2ec06b7..be25d37 100644 --- a/debian/patches/pve/0011-introduce-new-vma-archive-format.patch +++ b/debian/patches/pve/0028-adding-old-vma-files.patch @@ -1,19 +1,21 @@ -From df49dfac906aaf99e0c006ce61f8457f031f2f5c Mon Sep 17 00:00:00 2001 -From: Dietmar Maurer -Date: Tue, 13 Nov 2012 11:11:38 +0100 -Subject: [PATCH 11/49] introduce new vma archive format +From cf7632dba8a8b7191f5e0c2ba826c6827fecb412 Mon Sep 17 00:00:00 2001 +From: Wolfgang Bumiller +Date: Mon, 7 Aug 2017 08:51:16 +0200 +Subject: [PATCH 28/28] adding old vma files -This is a very simple archive format, see docs/specs/vma_spec.txt - -Signed-off-by: Dietmar Maurer --- - Makefile | 3 +- - Makefile.objs | 1 + - vma-reader.c | 797 +++++++++++++++++++++++++++++++++++++++++++++++++++++ - vma-writer.c | 870 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - vma.c | 586 +++++++++++++++++++++++++++++++++++++++ - vma.h | 146 ++++++++++ - 6 files changed, 2402 insertions(+), 1 deletion(-) + Makefile | 3 +- + Makefile.objs | 1 + + block/backup.c | 128 ++++--- + block/replication.c | 1 + + blockdev.c | 245 ++++++++----- + blockjob.c | 11 +- + include/block/block_int.h | 4 + + vma-reader.c | 857 ++++++++++++++++++++++++++++++++++++++++++++++ + vma-writer.c | 771 +++++++++++++++++++++++++++++++++++++++++ + vma.c | 757 ++++++++++++++++++++++++++++++++++++++++ + vma.h | 149 ++++++++ + 11 files changed, 2794 insertions(+), 133 deletions(-) create mode 100644 vma-reader.c create mode 100644 vma-writer.c create mode 100644 vma.c @@ -41,7 +43,7 @@ index 6c359b2f86..edbc8b50f0 100644 qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o $(COMMON_LDADDS) diff --git a/Makefile.objs b/Makefile.objs -index 6167e7b17d..9b12ee6afa 100644 +index fbfbbb7f70..f5f8dbab3b 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -14,6 +14,7 @@ block-obj-y += block.o blockjob.o @@ -52,12 +54,775 @@ index 6167e7b17d..9b12ee6afa 100644 block-obj-m = block/ +diff --git a/block/backup.c b/block/backup.c +index 1ede70c061..51b5ba6eda 100644 +--- a/block/backup.c ++++ b/block/backup.c +@@ -36,6 +36,7 @@ typedef struct BackupBlockJob { + BdrvDirtyBitmap *sync_bitmap; + MirrorSyncMode sync_mode; + RateLimit limit; ++ BackupDumpFunc *dump_cb; + BlockdevOnError on_source_error; + BlockdevOnError on_target_error; + CoRwlock flush_rwlock; +@@ -145,13 +146,24 @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job, + goto out; + } + ++ int64_t start_sec = start * sectors_per_cluster; + if (buffer_is_zero(iov.iov_base, iov.iov_len)) { +- ret = blk_co_pwrite_zeroes(job->target, start * job->cluster_size, +- bounce_qiov.size, BDRV_REQ_MAY_UNMAP); ++ if (job->dump_cb) { ++ ret = job->dump_cb(job->common.opaque, job->target, start_sec, n, NULL); ++ } ++ if (job->target) { ++ ret = blk_co_pwrite_zeroes(job->target, start * job->cluster_size, ++ bounce_qiov.size, BDRV_REQ_MAY_UNMAP); ++ } + } else { +- ret = blk_co_pwritev(job->target, start * job->cluster_size, +- bounce_qiov.size, &bounce_qiov, +- job->compress ? BDRV_REQ_WRITE_COMPRESSED : 0); ++ if (job->dump_cb) { ++ ret = job->dump_cb(job->common.opaque, job->target, start_sec, n, bounce_buffer); ++ } ++ if (job->target) { ++ ret = blk_co_pwritev(job->target, start * job->cluster_size, ++ bounce_qiov.size, &bounce_qiov, ++ job->compress ? BDRV_REQ_WRITE_COMPRESSED : 0); ++ } + } + if (ret < 0) { + trace_backup_do_cow_write_fail(job, start, ret); +@@ -246,6 +258,8 @@ static void backup_abort(BlockJob *job) + static void backup_clean(BlockJob *job) + { + BackupBlockJob *s = container_of(job, BackupBlockJob, common); ++ if (!s->target) ++ return; + assert(s->target); + blk_unref(s->target); + s->target = NULL; +@@ -330,9 +344,11 @@ static BlockErrorAction backup_error_action(BackupBlockJob *job, + if (read) { + return block_job_error_action(&job->common, job->on_source_error, + true, error); +- } else { ++ } else if (job->target) { + return block_job_error_action(&job->common, job->on_target_error, + false, error); ++ } else { ++ return BLOCK_ERROR_ACTION_REPORT; + } + } + +@@ -453,6 +469,7 @@ static void coroutine_fn backup_run(void *opaque) + + job->done_bitmap = bitmap_new(end); + ++ + job->before_write.notify = backup_before_write_notify; + bdrv_add_before_write_notifier(bs, &job->before_write); + +@@ -557,6 +574,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, + BlockdevOnError on_source_error, + BlockdevOnError on_target_error, + int creation_flags, ++ BackupDumpFunc *dump_cb, + BlockCompletionFunc *cb, void *opaque, + int pause_count, + BlockJobTxn *txn, Error **errp) +@@ -567,7 +585,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, + int ret; + + assert(bs); +- assert(target); ++ assert(target || dump_cb); + + if (bs == target) { + error_setg(errp, "Source and target cannot be the same"); +@@ -580,13 +598,13 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, + return NULL; + } + +- if (!bdrv_is_inserted(target)) { ++ if (target && !bdrv_is_inserted(target)) { + error_setg(errp, "Device is not inserted: %s", + bdrv_get_device_name(target)); + return NULL; + } + +- if (compress && target->drv->bdrv_co_pwritev_compressed == NULL) { ++ if (target && compress && target->drv->bdrv_co_pwritev_compressed == NULL) { + error_setg(errp, "Compression is not supported for this drive %s", + bdrv_get_device_name(target)); + return NULL; +@@ -596,7 +614,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, + return NULL; + } + +- if (bdrv_op_is_blocked(target, BLOCK_OP_TYPE_BACKUP_TARGET, errp)) { ++ if (target && bdrv_op_is_blocked(target, BLOCK_OP_TYPE_BACKUP_TARGET, errp)) { + return NULL; + } + +@@ -636,15 +654,18 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, + goto error; + } + +- /* The target must match the source in size, so no resize here either */ +- job->target = blk_new(BLK_PERM_WRITE, +- BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | +- BLK_PERM_WRITE_UNCHANGED | BLK_PERM_GRAPH_MOD); +- ret = blk_insert_bs(job->target, target, errp); +- if (ret < 0) { +- goto error; ++ if (target) { ++ /* The target must match the source in size, so no resize here either */ ++ job->target = blk_new(BLK_PERM_WRITE, ++ BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | ++ BLK_PERM_WRITE_UNCHANGED | BLK_PERM_GRAPH_MOD); ++ ret = blk_insert_bs(job->target, target, errp); ++ if (ret < 0) { ++ goto error; ++ } + } + ++ job->dump_cb = dump_cb; + job->on_source_error = on_source_error; + job->on_target_error = on_target_error; + job->sync_mode = sync_mode; +@@ -652,38 +673,55 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, + sync_bitmap : NULL; + job->compress = compress; + +- /* If there is no backing file on the target, we cannot rely on COW if our +- * backup cluster size is smaller than the target cluster size. Even for +- * targets with a backing file, try to avoid COW if possible. */ +- ret = bdrv_get_info(target, &bdi); +- if (ret == -ENOTSUP && !target->backing) { +- /* Cluster size is not defined */ +- error_report("WARNING: The target block device doesn't provide " +- "information about the block size and it doesn't have a " +- "backing file. The default block size of %u bytes is " +- "used. If the actual block size of the target exceeds " +- "this default, the backup may be unusable", +- BACKUP_CLUSTER_SIZE_DEFAULT); +- job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT; +- } else if (ret < 0 && !target->backing) { +- error_setg_errno(errp, -ret, +- "Couldn't determine the cluster size of the target image, " +- "which has no backing file"); +- error_append_hint(errp, +- "Aborting, since this may create an unusable destination image\n"); +- goto error; +- } else if (ret < 0 && target->backing) { +- /* Not fatal; just trudge on ahead. */ +- job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT; ++ if (target) { ++ /* If there is no backing file on the target, we cannot rely on COW if our ++ * backup cluster size is smaller than the target cluster size. Even for ++ * targets with a backing file, try to avoid COW if possible. */ ++ ret = bdrv_get_info(target, &bdi); ++ if (ret == -ENOTSUP && !target->backing) { ++ /* Cluster size is not defined */ ++ error_report("WARNING: The target block device doesn't provide " ++ "information about the block size and it doesn't have a " ++ "backing file. The default block size of %u bytes is " ++ "used. If the actual block size of the target exceeds " ++ "this default, the backup may be unusable", ++ BACKUP_CLUSTER_SIZE_DEFAULT); ++ job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT; ++ } else if (ret < 0 && !target->backing) { ++ error_setg_errno(errp, -ret, ++ "Couldn't determine the cluster size of the target image, " ++ "which has no backing file"); ++ error_append_hint(errp, ++ "Aborting, since this may create an unusable destination image\n"); ++ goto error; ++ } else if (ret < 0 && target->backing) { ++ /* Not fatal; just trudge on ahead. */ ++ job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT; ++ } else { ++ job->cluster_size = MAX(BACKUP_CLUSTER_SIZE_DEFAULT, bdi.cluster_size); ++ } + } else { +- job->cluster_size = MAX(BACKUP_CLUSTER_SIZE_DEFAULT, bdi.cluster_size); ++ ret = bdrv_get_info(bs, &bdi); ++ if (ret < 0) { ++ job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT; ++ } else { ++ /* round down to nearest BACKUP_CLUSTER_SIZE_DEFAULT */ ++ job->cluster_size = (bdi.cluster_size / BACKUP_CLUSTER_SIZE_DEFAULT) * BACKUP_CLUSTER_SIZE_DEFAULT; ++ if (job->cluster_size == 0) { ++ /* but we can't go below it */ ++ job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT; ++ } ++ } + } + +- /* Required permissions are already taken with target's blk_new() */ +- block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL, +- &error_abort); ++ if (target) { ++ /* Required permissions are already taken with target's blk_new() */ ++ block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL, ++ &error_abort); ++ } else { ++ job->common.pause_count = pause_count; ++ } + job->common.len = len; +- job->common.pause_count = pause_count; + block_job_txn_add_job(txn, &job->common); + + return &job->common; +diff --git a/block/replication.c b/block/replication.c +index 1c41d9e6bf..60c6524417 100644 +--- a/block/replication.c ++++ b/block/replication.c +@@ -531,6 +531,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, + 0, MIRROR_SYNC_MODE_NONE, NULL, false, + BLOCKDEV_ON_ERROR_REPORT, + BLOCKDEV_ON_ERROR_REPORT, BLOCK_JOB_INTERNAL, ++ NULL, + backup_job_completed, bs, 0, NULL, &local_err); + if (local_err) { + error_propagate(errp, local_err); +diff --git a/blockdev.c b/blockdev.c +index 981276692a..1eeffb0571 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -31,7 +31,6 @@ + */ + + #include "qemu/osdep.h" +-#include "qemu/uuid.h" + #include "sysemu/block-backend.h" + #include "sysemu/blockdev.h" + #include "hw/block/block.h" +@@ -55,6 +54,7 @@ + #include "qemu/cutils.h" + #include "qemu/help_option.h" + #include "qemu/throttle-options.h" ++#include "vma.h" + + static QTAILQ_HEAD(, BlockDriverState) monitor_bdrv_states = + QTAILQ_HEAD_INITIALIZER(monitor_bdrv_states); +@@ -2958,20 +2958,44 @@ out: + aio_context_release(aio_context); + } + ++void block_job_event_cancelled(BlockJob *job); ++void block_job_event_completed(BlockJob *job, const char *msg); ++static void block_job_cb(void *opaque, int ret) ++{ ++ /* Note that this function may be executed from another AioContext besides ++ * the QEMU main loop. If you need to access anything that assumes the ++ * QEMU global mutex, use a BH or introduce a mutex. ++ */ ++ ++ BlockDriverState *bs = opaque; ++ const char *msg = NULL; ++ ++ assert(bs->job); ++ ++ if (ret < 0) { ++ msg = strerror(-ret); ++ } ++ ++ if (block_job_is_cancelled(bs->job)) { ++ block_job_event_cancelled(bs->job); ++ } else { ++ block_job_event_completed(bs->job, msg); ++ } ++} ++ + /* PVE backup related function */ + + static struct PVEBackupState { + Error *error; + bool cancel; +- QemuUUID uuid; ++ uuid_t uuid; + char uuid_str[37]; + int64_t speed; + time_t start_time; + time_t end_time; + char *backup_file; +- Object *vmaobj; ++ VmaWriter *vmaw; + GList *di_list; +- size_t next_job; + size_t total; + size_t transferred; + size_t zero_bytes; +@@ -2981,6 +3005,7 @@ typedef struct PVEBackupDevInfo { + BlockDriverState *bs; + size_t size; + uint8_t dev_id; ++ //bool started; + bool completed; + char targetfile[PATH_MAX]; + BlockDriverState *target; +@@ -2988,13 +3013,74 @@ typedef struct PVEBackupDevInfo { + + static void pvebackup_run_next_job(void); + ++static int pvebackup_dump_cb(void *opaque, BlockBackend *target, ++ int64_t sector_num, int n_sectors, ++ unsigned char *buf) ++{ ++ PVEBackupDevInfo *di = opaque; ++ ++ int size = n_sectors * BDRV_SECTOR_SIZE; ++ if (backup_state.cancel) { ++ return size; // return success ++ } ++ ++ if (sector_num & 0x7f) { ++ if (!backup_state.error) { ++ error_setg(&backup_state.error, ++ "got unaligned write inside backup dump " ++ "callback (sector %ld)", sector_num); ++ } ++ return -1; // not aligned to cluster size ++ } ++ ++ int64_t cluster_num = sector_num >> 7; ++ ++ int ret = -1; ++ ++ if (backup_state.vmaw) { ++ size_t zero_bytes = 0; ++ n_sectors = n_sectors * BDRV_SECTOR_SIZE / VMA_BLOCK_SIZE; ++ while (n_sectors >= VMA_CLUSTER_BITS) { ++ ret = vma_writer_write(backup_state.vmaw, di->dev_id, cluster_num, ++ buf, &zero_bytes); ++ n_sectors -= VMA_CLUSTER_BITS; ++ ++cluster_num; ++ if (buf) { ++ buf += VMA_CLUSTER_SIZE; ++ } ++ if (ret < 0) { ++ if (!backup_state.error) { ++ vma_writer_error_propagate(backup_state.vmaw, &backup_state.error); ++ } ++ if (di->bs && di->bs->job) { ++ block_job_cancel(di->bs->job); ++ } ++ } else { ++ backup_state.zero_bytes += zero_bytes; ++ backup_state.transferred += VMA_CLUSTER_SIZE; ++ } ++ } ++ } else { ++ if (!buf) { ++ backup_state.zero_bytes += size; ++ } ++ backup_state.transferred += size; ++ } ++ ++ // Note: always return success, because we want that writes succeed anyways. ++ ++ return size; ++} ++ + static void pvebackup_cleanup(void) + { + backup_state.end_time = time(NULL); + +- if (backup_state.vmaobj) { +- object_unparent(backup_state.vmaobj); +- backup_state.vmaobj = NULL; ++ if (backup_state.vmaw) { ++ Error *local_err = NULL; ++ vma_writer_close(backup_state.vmaw, &local_err); ++ error_propagate(&backup_state.error, local_err); ++ backup_state.vmaw = NULL; + } + + if (backup_state.di_list) { +@@ -3009,6 +3095,13 @@ static void pvebackup_cleanup(void) + } + } + ++static void coroutine_fn backup_close_vma_stream(void *opaque) ++{ ++ PVEBackupDevInfo *di = opaque; ++ ++ vma_writer_close_stream(backup_state.vmaw, di->dev_id); ++} ++ + static void pvebackup_complete_cb(void *opaque, int ret) + { + PVEBackupDevInfo *di = opaque; +@@ -3020,14 +3113,18 @@ static void pvebackup_complete_cb(void *opaque, int ret) + ret, strerror(-ret)); + } + ++ BlockDriverState *bs = di->bs; ++ + di->bs = NULL; + di->target = NULL; + +- if (backup_state.vmaobj) { +- object_unparent(backup_state.vmaobj); +- backup_state.vmaobj = NULL; ++ if (backup_state.vmaw) { ++ Coroutine *co = qemu_coroutine_create(backup_close_vma_stream, di); ++ qemu_coroutine_enter(co); + } + ++ block_job_cb(bs, ret); ++ + if (!backup_state.cancel) { + pvebackup_run_next_job(); + } +@@ -3041,14 +3138,9 @@ static void pvebackup_cancel(void *opaque) + error_setg(&backup_state.error, "backup cancelled"); + } + +- if (backup_state.vmaobj) { +- Error *err; ++ if (backup_state.vmaw) { + /* make sure vma writer does not block anymore */ +- if (!object_set_props(backup_state.vmaobj, &err, "blocked", "yes", NULL)) { +- if (err) { +- error_report_err(err); +- } +- } ++ vma_writer_set_error(backup_state.vmaw, "backup cancelled"); + } + + GList *l = backup_state.di_list; +@@ -3073,19 +3165,15 @@ void qmp_backup_cancel(Error **errp) + Coroutine *co = qemu_coroutine_create(pvebackup_cancel, NULL); + qemu_coroutine_enter(co); + +- while (backup_state.vmaobj) { +- /* FIXME: Find something better for this */ ++ while (backup_state.vmaw) { ++ /* vma writer use main aio context */ + aio_poll(qemu_get_aio_context(), true); + } + } + +-void vma_object_add_config_file(Object *obj, const char *name, +- const char *contents, size_t len, +- Error **errp); + static int config_to_vma(const char *file, BackupFormat format, +- Object *vmaobj, +- const char *backup_dir, +- Error **errp) ++ const char *backup_dir, VmaWriter *vmaw, ++ Error **errp) + { + char *cdata = NULL; + gsize clen = 0; +@@ -3098,12 +3186,17 @@ static int config_to_vma(const char *file, BackupFormat format, + char *basename = g_path_get_basename(file); + + if (format == BACKUP_FORMAT_VMA) { +- vma_object_add_config_file(vmaobj, basename, cdata, clen, errp); ++ if (vma_writer_add_config(vmaw, basename, cdata, clen) != 0) { ++ error_setg(errp, "unable to add %s config data to vma archive", file); ++ g_free(cdata); ++ g_free(basename); ++ return 1; ++ } + } else if (format == BACKUP_FORMAT_DIR) { + char config_path[PATH_MAX]; + snprintf(config_path, PATH_MAX, "%s/%s", backup_dir, basename); + if (!g_file_set_contents(config_path, cdata, clen, &err)) { +- error_setg(errp, "unable to write config file '%s'", config_path); ++ error_setg(errp, "unable to write config file '%s'", config_path); + g_free(cdata); + g_free(basename); + return 1; +@@ -3113,35 +3206,37 @@ static int config_to_vma(const char *file, BackupFormat format, + g_free(basename); + g_free(cdata); + +- return 0; ++ return 0; + } + ++bool block_job_should_pause(BlockJob *job); + static void pvebackup_run_next_job(void) + { +- bool cancel = backup_state.error || backup_state.cancel; +-fprintf(stderr, "run next job: %zu\n", backup_state.next_job); +- GList *next = g_list_nth(backup_state.di_list, backup_state.next_job); +- while (next) { +- PVEBackupDevInfo *di = (PVEBackupDevInfo *)next->data; +- backup_state.next_job++; ++ GList *l = backup_state.di_list; ++ while (l) { ++ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; ++ l = g_list_next(l); + if (!di->completed && di->bs && di->bs->job) { + BlockJob *job = di->bs->job; +- if (cancel) { +- block_job_cancel(job); +- } else { +- block_job_resume(job); ++ if (block_job_should_pause(job)) { ++ bool cancel = backup_state.error || backup_state.cancel; ++ if (cancel) { ++ block_job_cancel(job); ++ } else { ++ block_job_resume(job); ++ } + } + return; + } +- next = g_list_next(next); + } ++ + pvebackup_cleanup(); + } + + UuidInfo *qmp_backup(const char *backup_file, bool has_format, + BackupFormat format, + bool has_config_file, const char *config_file, +- bool has_firewall_file, const char *firewall_file, ++ bool has_firewall_file, const char *firewall_file, + bool has_devlist, const char *devlist, + bool has_speed, int64_t speed, Error **errp) + { +@@ -3149,14 +3244,15 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format, + BlockDriverState *bs = NULL; + const char *backup_dir = NULL; + Error *local_err = NULL; +- QemuUUID uuid; ++ uuid_t uuid; ++ VmaWriter *vmaw = NULL; + gchar **devs = NULL; + GList *di_list = NULL; + GList *l; + UuidInfo *uuid_info; + BlockJob *job; + +- if (backup_state.di_list || backup_state.vmaobj) { ++ if (backup_state.di_list) { + error_set(errp, ERROR_CLASS_GENERIC_ERROR, + "previous backup not finished"); + return NULL; +@@ -3231,40 +3327,28 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format, + total += size; + } + +- qemu_uuid_generate(&uuid); ++ uuid_generate(uuid); + + if (format == BACKUP_FORMAT_VMA) { +- char uuidstr[UUID_FMT_LEN+1]; +- qemu_uuid_unparse(&uuid, uuidstr); +- uuidstr[UUID_FMT_LEN] = 0; +- backup_state.vmaobj = +- object_new_with_props("vma", object_get_objects_root(), +- "vma-backup-obj", &local_err, +- "filename", backup_file, +- "uuid", uuidstr, +- NULL); +- if (!backup_state.vmaobj) { ++ vmaw = vma_writer_create(backup_file, uuid, &local_err); ++ if (!vmaw) { + if (local_err) { + error_propagate(errp, local_err); + } + goto err; + } + ++ /* register all devices for vma writer */ + l = di_list; + while (l) { +- QDict *options = qdict_new(); +- + PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; + l = g_list_next(l); + + const char *devname = bdrv_get_device_name(di->bs); +- snprintf(di->targetfile, PATH_MAX, "vma-backup-obj/%s.raw", devname); +- +- qdict_put(options, "driver", qstring_from_str("vma-drive")); +- qdict_put(options, "size", qint_from_int(di->size)); +- di->target = bdrv_open(di->targetfile, NULL, options, BDRV_O_RDWR, &local_err); +- if (!di->target) { +- error_propagate(errp, local_err); ++ di->dev_id = vma_writer_register_stream(vmaw, devname, di->size); ++ if (di->dev_id <= 0) { ++ error_set(errp, ERROR_CLASS_GENERIC_ERROR, ++ "register_stream failed"); + goto err; + } + } +@@ -3305,15 +3389,15 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format, + + /* add configuration file to archive */ + if (has_config_file) { +- if(config_to_vma(config_file, format, backup_state.vmaobj, backup_dir, errp) != 0) { +- goto err; ++ if(config_to_vma(config_file, format, backup_dir, vmaw, errp) != 0) { ++ goto err; + } + } + + /* add firewall file to archive */ + if (has_firewall_file) { +- if(config_to_vma(firewall_file, format, backup_state.vmaobj, backup_dir, errp) != 0) { +- goto err; ++ if(config_to_vma(firewall_file, format, backup_dir, vmaw, errp) != 0) { ++ goto err; + } + } + /* initialize global backup_state now */ +@@ -3335,11 +3419,12 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format, + } + backup_state.backup_file = g_strdup(backup_file); + +- memcpy(&backup_state.uuid, &uuid, sizeof(uuid)); +- qemu_uuid_unparse(&uuid, backup_state.uuid_str); ++ backup_state.vmaw = vmaw; ++ ++ uuid_copy(backup_state.uuid, uuid); ++ uuid_unparse_lower(uuid, backup_state.uuid_str); + + backup_state.di_list = di_list; +- backup_state.next_job = 0; + + backup_state.total = total; + backup_state.transferred = 0; +@@ -3350,21 +3435,16 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format, + while (l) { + PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data; + l = g_list_next(l); +- + job = backup_job_create(NULL, di->bs, di->target, speed, MIRROR_SYNC_MODE_FULL, NULL, + false, BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT, + BLOCK_JOB_DEFAULT, +- pvebackup_complete_cb, di, 2, NULL, &local_err); +- if (di->target) { +- bdrv_unref(di->target); +- di->target = NULL; +- } ++ pvebackup_dump_cb, pvebackup_complete_cb, di, ++ 2, NULL, &local_err); + if (!job || local_err != NULL) { + error_setg(&backup_state.error, "backup_job_create failed"); + pvebackup_cancel(NULL); +- } else { +- block_job_start(job); + } ++ block_job_start(job); + } + + if (!backup_state.error) { +@@ -3398,9 +3478,10 @@ err: + g_strfreev(devs); + } + +- if (backup_state.vmaobj) { +- object_unparent(backup_state.vmaobj); +- backup_state.vmaobj = NULL; ++ if (vmaw) { ++ Error *err = NULL; ++ vma_writer_close(vmaw, &err); ++ unlink(backup_file); + } + + if (backup_dir) { +@@ -3772,7 +3853,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup, BlockJobTxn *txn, + job = backup_job_create(backup->job_id, bs, target_bs, backup->speed, + backup->sync, bmap, backup->compress, + backup->on_source_error, backup->on_target_error, +- BLOCK_JOB_DEFAULT, NULL, NULL, 0, txn, &local_err); ++ BLOCK_JOB_DEFAULT, NULL, NULL, NULL, 0, txn, &local_err); + bdrv_unref(target_bs); + if (local_err != NULL) { + error_propagate(errp, local_err); +@@ -3851,7 +3932,7 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn, + job = backup_job_create(backup->job_id, bs, target_bs, backup->speed, + backup->sync, NULL, backup->compress, + backup->on_source_error, backup->on_target_error, +- BLOCK_JOB_DEFAULT, NULL, NULL, 0, txn, &local_err); ++ BLOCK_JOB_DEFAULT, NULL, NULL, NULL, 0, txn, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + } +diff --git a/blockjob.c b/blockjob.c +index 764d41863e..cb3741f6dd 100644 +--- a/blockjob.c ++++ b/blockjob.c +@@ -37,8 +37,8 @@ + #include "qemu/timer.h" + #include "qapi-event.h" + +-static void block_job_event_cancelled(BlockJob *job); +-static void block_job_event_completed(BlockJob *job, const char *msg); ++void block_job_event_cancelled(BlockJob *job); ++void block_job_event_completed(BlockJob *job, const char *msg); + + /* Transactional group of block jobs */ + struct BlockJobTxn { +@@ -473,7 +473,8 @@ void block_job_user_pause(BlockJob *job) + block_job_pause(job); + } + +-static bool block_job_should_pause(BlockJob *job) ++bool block_job_should_pause(BlockJob *job); ++bool block_job_should_pause(BlockJob *job) + { + return job->pause_count > 0; + } +@@ -687,7 +688,7 @@ static void block_job_iostatus_set_err(BlockJob *job, int error) + } + } + +-static void block_job_event_cancelled(BlockJob *job) ++void block_job_event_cancelled(BlockJob *job) + { + if (block_job_is_internal(job)) { + return; +@@ -701,7 +702,7 @@ static void block_job_event_cancelled(BlockJob *job) + &error_abort); + } + +-static void block_job_event_completed(BlockJob *job, const char *msg) ++void block_job_event_completed(BlockJob *job, const char *msg) + { + if (block_job_is_internal(job)) { + return; +diff --git a/include/block/block_int.h b/include/block/block_int.h +index 2b3ecd0575..278da161fb 100644 +--- a/include/block/block_int.h ++++ b/include/block/block_int.h +@@ -59,6 +59,9 @@ + + #define BLOCK_PROBE_BUF_SIZE 512 + ++typedef int BackupDumpFunc(void *opaque, BlockBackend *be, ++ int64_t sector_num, int n_sectors, unsigned char *buf); ++ + enum BdrvTrackedRequestType { + BDRV_TRACKED_READ, + BDRV_TRACKED_WRITE, +@@ -877,6 +880,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, + BlockdevOnError on_source_error, + BlockdevOnError on_target_error, + int creation_flags, ++ BackupDumpFunc *dump_cb, + BlockCompletionFunc *cb, void *opaque, + int pause_count, + BlockJobTxn *txn, Error **errp); diff --git a/vma-reader.c b/vma-reader.c new file mode 100644 -index 0000000000..51dd8fee0e +index 0000000000..2000889bd3 --- /dev/null +++ b/vma-reader.c -@@ -0,0 +1,797 @@ +@@ -0,0 +1,857 @@ +/* + * VMA: Virtual Machine Archive + * @@ -85,7 +850,7 @@ index 0000000000..51dd8fee0e +static unsigned char zero_vma_block[VMA_BLOCK_SIZE]; + +typedef struct VmaRestoreState { -+ BlockDriverState *bs; ++ BlockBackend *target; + bool write_zeroes; + unsigned long *bitmap; + int bitmap_size; @@ -105,6 +870,8 @@ index 0000000000..51dd8fee0e + time_t start_time; + int64_t cluster_count; + int64_t clusters_read; ++ int64_t zero_cluster_data; ++ int64_t partial_zero_cluster_data; + int clusters_read_per; +}; + @@ -384,11 +1151,6 @@ index 0000000000..51dd8fee0e + } + } + -+ 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]); @@ -485,15 +1247,36 @@ index 0000000000..51dd8fee0e + return NULL; +} + -+int vma_reader_register_bs(VmaReader *vmar, guint8 dev_id, BlockDriverState *bs, ++static void allocate_rstate(VmaReader *vmar, guint8 dev_id, ++ BlockBackend *target, bool write_zeroes) ++{ ++ assert(vmar); ++ assert(dev_id); ++ ++ vmar->rstate[dev_id].target = target; ++ vmar->rstate[dev_id].write_zeroes = write_zeroes; ++ ++ int64_t size = vmar->devinfo[dev_id].size; ++ ++ int64_t bitmap_size = (size/BDRV_SECTOR_SIZE) + ++ (VMA_CLUSTER_SIZE/BDRV_SECTOR_SIZE) * BITS_PER_LONG - 1; ++ bitmap_size /= (VMA_CLUSTER_SIZE/BDRV_SECTOR_SIZE) * BITS_PER_LONG; ++ ++ 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; ++} ++ ++int vma_reader_register_bs(VmaReader *vmar, guint8 dev_id, BlockBackend *target, + bool write_zeroes, Error **errp) +{ + assert(vmar); -+ assert(bs != NULL); ++ assert(target != NULL); + assert(dev_id); -+ assert(vmar->rstate[dev_id].bs == NULL); ++ assert(vmar->rstate[dev_id].target == NULL); + -+ int64_t size = bdrv_getlength(bs); ++ int64_t size = blk_getlength(target); + int64_t size_diff = size - vmar->devinfo[dev_id].size; + + /* storage types can have different size restrictions, so it @@ -507,17 +1290,7 @@ index 0000000000..51dd8fee0e + return -1; + } + -+ vmar->rstate[dev_id].bs = bs; -+ vmar->rstate[dev_id].write_zeroes = write_zeroes; -+ -+ int64_t bitmap_size = (size/BDRV_SECTOR_SIZE) + -+ (VMA_CLUSTER_SIZE/BDRV_SECTOR_SIZE) * BITS_PER_LONG - 1; -+ bitmap_size /= (VMA_CLUSTER_SIZE/BDRV_SECTOR_SIZE) * BITS_PER_LONG; -+ -+ 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; ++ allocate_rstate(vmar, dev_id, target, write_zeroes); + + return 0; +} @@ -559,7 +1332,7 @@ index 0000000000..51dd8fee0e +} + +static int restore_write_data(VmaReader *vmar, guint8 dev_id, -+ BlockDriverState *bs, int vmstate_fd, ++ BlockBackend *target, int vmstate_fd, + unsigned char *buf, int64_t sector_num, + int nb_sectors, Error **errp) +{ @@ -575,18 +1348,19 @@ index 0000000000..51dd8fee0e + } + } + } else { -+ int res = bdrv_write(bs, sector_num, buf, nb_sectors); ++ int res = blk_pwrite(target, sector_num * BDRV_SECTOR_SIZE, buf, nb_sectors * BDRV_SECTOR_SIZE, 0); + if (res < 0) { -+ error_setg(errp, "bdrv_write to %s failed (%d)", -+ bdrv_get_device_name(bs), res); ++ error_setg(errp, "blk_pwrite to %s failed (%d)", ++ bdrv_get_device_name(blk_bs(target)), res); + return -1; + } + } + return 0; +} ++ +static int restore_extent(VmaReader *vmar, unsigned char *buf, + int extent_size, int vmstate_fd, -+ bool verbose, Error **errp) ++ bool verbose, bool verify, Error **errp) +{ + assert(vmar); + assert(buf); @@ -607,11 +1381,11 @@ index 0000000000..51dd8fee0e + } + + VmaRestoreState *rstate = &vmar->rstate[dev_id]; -+ BlockDriverState *bs = NULL; ++ BlockBackend *target = NULL; + + if (dev_id != vmar->vmstate_stream) { -+ bs = rstate->bs; -+ if (!bs) { ++ target = rstate->target; ++ if (!verify && !target) { + error_setg(errp, "got wrong dev id %d", dev_id); + return -1; + } @@ -667,10 +1441,13 @@ index 0000000000..51dd8fee0e + return -1; + } + -+ int nb_sectors = end_sector - sector_num; -+ if (restore_write_data(vmar, dev_id, bs, vmstate_fd, buf + start, -+ sector_num, nb_sectors, errp) < 0) { -+ return -1; ++ if (!verify) { ++ int nb_sectors = end_sector - sector_num; ++ if (restore_write_data(vmar, dev_id, target, vmstate_fd, ++ buf + start, sector_num, nb_sectors, ++ errp) < 0) { ++ return -1; ++ } + } + + start += VMA_CLUSTER_SIZE; @@ -700,26 +1477,37 @@ index 0000000000..51dd8fee0e + return -1; + } + -+ int nb_sectors = end_sector - sector_num; -+ if (restore_write_data(vmar, dev_id, bs, vmstate_fd, -+ buf + start, sector_num, -+ nb_sectors, errp) < 0) { -+ return -1; ++ if (!verify) { ++ int nb_sectors = end_sector - sector_num; ++ if (restore_write_data(vmar, dev_id, target, vmstate_fd, ++ buf + start, sector_num, ++ nb_sectors, errp) < 0) { ++ return -1; ++ } + } + + start += VMA_BLOCK_SIZE; + + } else { + -+ if (rstate->write_zeroes && (end_sector > sector_num)) { ++ ++ if (end_sector > sector_num) { + /* Todo: use bdrv_co_write_zeroes (but that need to + * be run inside coroutine?) + */ + int nb_sectors = end_sector - sector_num; -+ if (restore_write_data(vmar, dev_id, bs, vmstate_fd, -+ zero_vma_block, sector_num, -+ nb_sectors, errp) < 0) { -+ return -1; ++ int zero_size = BDRV_SECTOR_SIZE*nb_sectors; ++ vmar->zero_cluster_data += zero_size; ++ if (mask != 0) { ++ vmar->partial_zero_cluster_data += zero_size; ++ } ++ ++ if (rstate->write_zeroes && !verify) { ++ if (restore_write_data(vmar, dev_id, target, vmstate_fd, ++ zero_vma_block, sector_num, ++ nb_sectors, errp) < 0) { ++ return -1; ++ } + } + } + } @@ -737,8 +1525,9 @@ index 0000000000..51dd8fee0e + return 0; +} + -+int vma_reader_restore(VmaReader *vmar, int vmstate_fd, bool verbose, -+ Error **errp) ++static int vma_reader_restore_full(VmaReader *vmar, int vmstate_fd, ++ bool verbose, bool verify, ++ Error **errp) +{ + assert(vmar); + assert(vmar->head_data); @@ -805,7 +1594,7 @@ index 0000000000..51dd8fee0e + } + + if (restore_extent(vmar, buf, extent_size, vmstate_fd, verbose, -+ errp) < 0) { ++ verify, errp) < 0) { + return -1; + } + @@ -822,12 +1611,12 @@ index 0000000000..51dd8fee0e + int i; + for (i = 1; i < 256; i++) { + VmaRestoreState *rstate = &vmar->rstate[i]; -+ if (!rstate->bs) { ++ if (!rstate->target) { + continue; + } + -+ if (bdrv_flush(rstate->bs) < 0) { -+ error_setg(errp, "vma bdrv_flush %s failed", ++ if (blk_flush(rstate->target) < 0) { ++ error_setg(errp, "vma blk_flush %s failed", + vmar->devinfo[i].devname); + return -1; + } @@ -852,15 +1641,51 @@ index 0000000000..51dd8fee0e + } + } + ++ if (verbose) { ++ 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 blocks %.3g%%\n", ++ (double)(100.0*vmar->partial_zero_cluster_data) / datasize); ++ } ++ } else { ++ printf("vma archive contains no image data\n"); ++ } ++ } + return ret; +} + ++int vma_reader_restore(VmaReader *vmar, int vmstate_fd, bool verbose, ++ Error **errp) ++{ ++ return vma_reader_restore_full(vmar, vmstate_fd, verbose, false, errp); ++} ++ ++int vma_reader_verify(VmaReader *vmar, bool verbose, Error **errp) ++{ ++ guint8 dev_id; ++ ++ for (dev_id = 1; dev_id < 255; dev_id++) { ++ if (vma_reader_get_device_info(vmar, dev_id)) { ++ allocate_rstate(vmar, dev_id, NULL, false); ++ } ++ } ++ ++ return vma_reader_restore_full(vmar, -1, verbose, true, errp); ++} ++ diff --git a/vma-writer.c b/vma-writer.c new file mode 100644 -index 0000000000..b0cf529125 +index 0000000000..9001cbdd2b --- /dev/null +++ b/vma-writer.c -@@ -0,0 +1,870 @@ +@@ -0,0 +1,771 @@ +/* + * VMA: Virtual Machine Archive + * @@ -891,14 +1716,8 @@ index 0000000000..b0cf529125 + do { if (DEBUG_VMA) { printf("vma: " fmt, ## __VA_ARGS__); } } while (0) + +#define WRITE_BUFFERS 5 -+ -+typedef struct VmaAIOCB VmaAIOCB; -+struct VmaAIOCB { -+ unsigned char buffer[VMA_MAX_EXTENT_SIZE]; -+ VmaWriter *vmaw; -+ size_t bytes; -+ Coroutine *co; -+}; ++#define HEADER_CLUSTERS 8 ++#define HEADERBUF_SIZE (VMA_CLUSTER_SIZE*HEADER_CLUSTERS) + +struct VmaWriter { + int fd; @@ -910,16 +1729,14 @@ index 0000000000..b0cf529125 + bool closed; + + /* we always write extents */ -+ unsigned char outbuf[VMA_MAX_EXTENT_SIZE]; ++ unsigned char *outbuf; + int outbuf_pos; /* in bytes */ + int outbuf_count; /* in VMA_BLOCKS */ + uint64_t outbuf_block_info[VMA_BLOCKS_PER_EXTENT]; + -+ VmaAIOCB *aiocbs[WRITE_BUFFERS]; -+ CoQueue wqueue; ++ unsigned char *headerbuf; + + GChecksum *md5csum; -+ CoMutex writer_lock; + CoMutex flush_lock; + Coroutine *co_writer; + @@ -1001,7 +1818,6 @@ index 0000000000..b0cf529125 + assert(vmaw->config_count < VMA_MAX_CONFIGS); + assert(name); + assert(data); -+ assert(len); + + gchar *basename = g_path_get_basename(name); + uint32_t name_ptr = allocate_header_string(vmaw, basename); @@ -1080,38 +1896,39 @@ index 0000000000..b0cf529125 +} + +static ssize_t coroutine_fn -+vma_co_write(VmaWriter *vmaw, const void *buf, size_t bytes) ++vma_queue_write(VmaWriter *vmaw, const void *buf, size_t bytes) +{ ++ DPRINTF("vma_queue_write enter %zd\n", bytes); ++ ++ assert(vmaw); ++ assert(buf); ++ assert(bytes <= VMA_MAX_EXTENT_SIZE); ++ + size_t done = 0; + ssize_t ret; + -+ /* atomic writes (we cannot interleave writes) */ -+ qemu_co_mutex_lock(&vmaw->writer_lock); -+ -+ DPRINTF("vma_co_write enter %zd\n", bytes); -+ + assert(vmaw->co_writer == NULL); + + vmaw->co_writer = qemu_coroutine_self(); + -+ aio_set_fd_handler(qemu_get_aio_context(), vmaw->fd, false, NULL, vma_co_continue_write, vmaw); -+ -+ DPRINTF("vma_co_write wait until writable\n"); -+ qemu_coroutine_yield(); -+ DPRINTF("vma_co_write starting %zd\n", bytes); -+ + while (done < bytes) { ++ aio_set_fd_handler(qemu_get_aio_context(), vmaw->fd, false, NULL, vma_co_continue_write, NULL, vmaw); ++ qemu_coroutine_yield(); ++ aio_set_fd_handler(qemu_get_aio_context(), vmaw->fd, false, NULL, NULL, NULL, NULL); ++ if (vmaw->status < 0) { ++ DPRINTF("vma_queue_write detected canceled backup\n"); ++ done = -1; ++ break; ++ } + ret = write(vmaw->fd, buf + done, bytes - done); + if (ret > 0) { + done += ret; -+ DPRINTF("vma_co_write written %zd %zd\n", done, ret); ++ DPRINTF("vma_queue_write written %zd %zd\n", done, ret); + } else if (ret < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { -+ DPRINTF("vma_co_write yield %zd\n", done); -+ qemu_coroutine_yield(); -+ DPRINTF("vma_co_write restart %zd\n", done); -+ } else { -+ vma_writer_set_error(vmaw, "vma_co_write write error - %s", ++ /* try again */ ++ } else { ++ vma_writer_set_error(vmaw, "vma_queue_write: write error - %s", + g_strerror(errno)); + done = -1; /* always return failure for partial writes */ + break; @@ -1121,102 +1938,9 @@ index 0000000000..b0cf529125 + } + } + -+ aio_set_fd_handler(qemu_get_aio_context(), vmaw->fd, false, NULL, NULL, NULL); -+ + vmaw->co_writer = NULL; + -+ qemu_co_mutex_unlock(&vmaw->writer_lock); -+ -+ DPRINTF("vma_co_write leave %zd\n", done); -+ return done; -+} -+ -+static void coroutine_fn vma_co_writer_task(void *opaque) -+{ -+ VmaAIOCB *cb = opaque; -+ -+ DPRINTF("vma_co_writer_task start\n"); -+ -+ int64_t done = vma_co_write(cb->vmaw, cb->buffer, cb->bytes); -+ DPRINTF("vma_co_writer_task write done %zd\n", done); -+ -+ if (done != cb->bytes) { -+ DPRINTF("vma_co_writer_task failed write %zd %zd", cb->bytes, done); -+ vma_writer_set_error(cb->vmaw, "vma_co_writer_task failed write %zd", -+ done); -+ } -+ -+ cb->bytes = 0; -+ -+ qemu_co_queue_next(&cb->vmaw->wqueue); -+ -+ DPRINTF("vma_co_writer_task end\n"); -+} -+ -+static void coroutine_fn vma_queue_flush(VmaWriter *vmaw) -+{ -+ DPRINTF("vma_queue_flush enter\n"); -+ -+ assert(vmaw); -+ -+ while (1) { -+ int i; -+ VmaAIOCB *cb = NULL; -+ for (i = 0; i < WRITE_BUFFERS; i++) { -+ if (vmaw->aiocbs[i]->bytes) { -+ cb = vmaw->aiocbs[i]; -+ DPRINTF("FOUND USED AIO BUFFER %d %zd\n", i, -+ vmaw->aiocbs[i]->bytes); -+ break; -+ } -+ } -+ if (!cb) { -+ break; -+ } -+ qemu_co_queue_wait(&vmaw->wqueue); -+ } -+ -+ DPRINTF("vma_queue_flush leave\n"); -+} -+ -+/** -+ * NOTE: pipe buffer size in only 4096 bytes on linux (see 'ulimit -a') -+ * So we need to create a coroutione to allow 'parallel' execution. -+ */ -+static ssize_t coroutine_fn -+vma_queue_write(VmaWriter *vmaw, const void *buf, size_t bytes) -+{ -+ DPRINTF("vma_queue_write enter %zd\n", bytes); -+ -+ assert(vmaw); -+ assert(buf); -+ assert(bytes <= VMA_MAX_EXTENT_SIZE); -+ -+ VmaAIOCB *cb = NULL; -+ while (!cb) { -+ int i; -+ for (i = 0; i < WRITE_BUFFERS; i++) { -+ if (!vmaw->aiocbs[i]->bytes) { -+ cb = vmaw->aiocbs[i]; -+ break; -+ } -+ } -+ if (!cb) { -+ qemu_co_queue_wait(&vmaw->wqueue); -+ } -+ } -+ -+ memcpy(cb->buffer, buf, bytes); -+ cb->bytes = bytes; -+ cb->vmaw = vmaw; -+ -+ DPRINTF("vma_queue_write start %zd\n", bytes); -+ cb->co = qemu_coroutine_create(vma_co_writer_task); -+ qemu_coroutine_enter(cb->co, cb); -+ -+ DPRINTF("vma_queue_write leave\n"); -+ -+ return bytes; ++ return (done == bytes) ? bytes : -1; +} + +VmaWriter *vma_writer_create(const char *filename, uuid_t uuid, Error **errp) @@ -1247,9 +1971,8 @@ index 0000000000..b0cf529125 + } + vmaw->fd = fileno(vmaw->cmd); + -+ /* try to use O_NONBLOCK and O_DIRECT */ ++ /* try to use O_NONBLOCK */ + 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 { + struct stat st; @@ -1257,19 +1980,18 @@ index 0000000000..b0cf529125 + const char *tmp_id_str; + + if ((stat(filename, &st) == 0) && S_ISFIFO(st.st_mode)) { -+ oflags = O_NONBLOCK|O_DIRECT|O_WRONLY; ++ oflags = O_NONBLOCK|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; ++ oflags = O_NONBLOCK|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 */ ++ /* try to use O_NONBLOCK */ + 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); @@ -1283,20 +2005,16 @@ index 0000000000..b0cf529125 + } + + /* 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 = qemu_memalign(512, VMA_MAX_EXTENT_SIZE); ++ vmaw->headerbuf = qemu_memalign(512, HEADERBUF_SIZE); + + vmaw->outbuf_count = 0; + vmaw->outbuf_pos = VMA_EXTENT_HEADER_SIZE; + + vmaw->header_blob_table_pos = 1; /* start at pos 1 */ + -+ qemu_co_mutex_init(&vmaw->writer_lock); + qemu_co_mutex_init(&vmaw->flush_lock); -+ qemu_co_queue_init(&vmaw->wqueue); + + uuid_copy(vmaw->uuid, uuid); + @@ -1323,8 +2041,7 @@ index 0000000000..b0cf529125 +static int coroutine_fn vma_write_header(VmaWriter *vmaw) +{ + assert(vmaw); -+ int header_clusters = 8; -+ char buf[65536*header_clusters]; ++ unsigned char *buf = vmaw->headerbuf; + VmaHeader *head = (VmaHeader *)buf; + + int i; @@ -1335,7 +2052,7 @@ index 0000000000..b0cf529125 + return vmaw->status; + } + -+ memset(buf, 0, sizeof(buf)); ++ memset(buf, 0, HEADERBUF_SIZE); + + head->magic = VMA_MAGIC; + head->version = GUINT32_TO_BE(1); /* v1 */ @@ -1344,10 +2061,6 @@ index 0000000000..b0cf529125 + 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]); @@ -1370,7 +2083,7 @@ index 0000000000..b0cf529125 + uint32_t header_size = sizeof(VmaHeader) + vmaw->header_blob_table_size; + head->header_size = GUINT32_TO_BE(header_size); + -+ if (header_size > sizeof(buf)) { ++ if (header_size > HEADERBUF_SIZE) { + return -1; /* just to be sure */ + } + @@ -1464,6 +2177,23 @@ index 0000000000..b0cf529125 + 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) @@ -1491,12 +2221,7 @@ index 0000000000..b0cf529125 + + 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; @@ -1655,20 +2380,25 @@ index 0000000000..b0cf529125 + return transferred; +} + ++void vma_writer_error_propagate(VmaWriter *vmaw, Error **errp) ++{ ++ if (vmaw->status < 0 && *errp == NULL) { ++ error_setg(errp, "%s", vmaw->errmsg); ++ } ++} ++ +int vma_writer_close(VmaWriter *vmaw, Error **errp) +{ + g_assert(vmaw != NULL); + + int i; + -+ vma_queue_flush(vmaw); -+ -+ /* this should not happen - just to be sure */ -+ while (!qemu_co_queue_empty(&vmaw->wqueue)) { -+ DPRINTF("vma_writer_close wait\n"); -+ co_aio_sleep_ns(qemu_get_aio_context(), QEMU_CLOCK_REALTIME, 1000000); ++ while (vmaw->co_writer) { ++ aio_poll(qemu_get_aio_context(), true); + } + ++ assert(vmaw->co_writer == NULL); ++ + if (vmaw->cmd) { + if (pclose(vmaw->cmd) < 0) { + vma_writer_set_error(vmaw, "vma_writer_close: " @@ -1725,18 +2455,14 @@ index 0000000000..b0cf529125 + g_checksum_free(vmaw->md5csum); + } + -+ for (i = 0; i < WRITE_BUFFERS; i++) { -+ free(vmaw->aiocbs[i]); -+ } -+ + g_free(vmaw); +} diff --git a/vma.c b/vma.c new file mode 100644 -index 0000000000..8732bfa85e +index 0000000000..04915427c8 --- /dev/null +++ b/vma.c -@@ -0,0 +1,586 @@ +@@ -0,0 +1,757 @@ +/* + * VMA: Virtual Machine Archive + * @@ -1759,6 +2485,7 @@ index 0000000000..8732bfa85e +#include "qemu/main-loop.h" +#include "qapi/qmp/qstring.h" +#include "sysemu/char.h" /* qstring_from_str */ ++#include "sysemu/block-backend.h" + +static void help(void) +{ @@ -1766,8 +2493,10 @@ index 0000000000..8732bfa85e + "usage: vma command [command options]\n" + "\n" + "vma list \n" -+ "vma create [-c config] pathname ...\n" ++ "vma config [-c config]\n" ++ "vma create [-c config] pathname ...\n" + "vma extract [-r ] \n" ++ "vma verify [-v]\n" + ; + + printf("%s", help_msg); @@ -1868,6 +2597,7 @@ index 0000000000..8732bfa85e +typedef struct RestoreMap { + char *devname; + char *path; ++ char *format; + bool write_zero; +} RestoreMap; + @@ -1955,13 +2685,24 @@ index 0000000000..8732bfa85e + } + } + ++ char *format = NULL; ++ if (strncmp(line, "format=", sizeof("format=")-1) == 0) { ++ format = line + sizeof("format=")-1; ++ char *colon = strchr(format, ':'); ++ if (!colon) { ++ g_error("read map failed - found only a format ('%s')", inbuf); ++ } ++ format = g_strndup(format, colon - format); ++ line = colon+1; ++ } ++ + const char *path; + bool write_zero; + if (line[0] == '0' && line[1] == ':') { -+ path = inbuf + 2; ++ path = line + 2; + write_zero = false; + } else if (line[0] == '1' && line[1] == ':') { -+ path = inbuf + 2; ++ path = line + 2; + write_zero = true; + } else { + g_error("read map failed - parse error ('%s')", inbuf); @@ -1977,6 +2718,7 @@ index 0000000000..8732bfa85e + RestoreMap *map = g_new0(RestoreMap, 1); + map->devname = g_strdup(devname); + map->path = g_strdup(path); ++ map->format = format; + map->write_zero = write_zero; + + g_hash_table_insert(devmap, map->devname, map); @@ -1988,6 +2730,8 @@ index 0000000000..8732bfa85e + int vmstate_fd = -1; + guint8 vmstate_stream = 0; + ++ BlockBackend *blk = NULL; ++ + for (i = 1; i < 255; i++) { + VmaDeviceInfo *di = vma_reader_get_device_info(vmar, i); + if (di && (strcmp(di->devname, "vmstate") == 0)) { @@ -2001,7 +2745,8 @@ index 0000000000..8732bfa85e + g_free(statefn); + } else if (di) { + char *devfn = NULL; -+ int flags = BDRV_O_RDWR|BDRV_O_CACHE_WB; ++ const char *format = NULL; ++ int flags = BDRV_O_RDWR | BDRV_O_NO_FLUSH; + bool write_zero = true; + + if (readmap) { @@ -2011,6 +2756,7 @@ index 0000000000..8732bfa85e + g_error("no device name mapping for %s", di->devname); + } + devfn = map->path; ++ format = map->format; + write_zero = map->write_zero; + } else { + devfn = g_strdup_printf("%s/tmp-disk-%s.raw", @@ -2030,12 +2776,30 @@ index 0000000000..8732bfa85e + write_zero = false; + } + -+ BlockDriverState *bs = bdrv_new(); -+ if (errp || bdrv_open(&bs, devfn, NULL, NULL, flags, &errp)) { ++ size_t devlen = strlen(devfn); ++ QDict *options = NULL; ++ if (format) { ++ /* explicit format from commandline */ ++ options = qdict_new(); ++ qdict_put(options, "driver", qstring_from_str(format)); ++ } else if ((devlen > 4 && strcmp(devfn+devlen-4, ".raw") == 0) || ++ strncmp(devfn, "/dev/", 5) == 0) ++ { ++ /* This part is now deprecated for PVE as well (just as qemu ++ * deprecated not specifying an explicit raw format, too. ++ */ ++ /* explicit raw format */ ++ options = qdict_new(); ++ qdict_put(options, "driver", qstring_from_str("raw")); ++ } ++ ++ ++ if (errp || !(blk = blk_new_open(devfn, NULL, options, flags, &errp))) { + g_error("can't open file %s - %s", devfn, + error_get_pretty(errp)); + } -+ if (vma_reader_register_bs(vmar, i, bs, write_zero, &errp) < 0) { ++ ++ if (vma_reader_register_bs(vmar, i, blk, write_zero, &errp) < 0) { + g_error("%s", error_get_pretty(errp)); + } + @@ -2067,13 +2831,67 @@ index 0000000000..8732bfa85e + + vma_reader_destroy(vmar); + ++ blk_unref(blk); ++ ++ bdrv_close_all(); ++ ++ return ret; ++} ++ ++static int verify_content(int argc, char **argv) ++{ ++ int c, ret = 0; ++ int verbose = 0; ++ const char *filename; ++ ++ for (;;) { ++ c = getopt(argc, argv, "hv"); ++ if (c == -1) { ++ break; ++ } ++ switch (c) { ++ case '?': ++ case 'h': ++ help(); ++ break; ++ case 'v': ++ verbose = 1; ++ break; ++ default: ++ help(); ++ } ++ } ++ ++ /* Get the filename */ ++ if ((optind + 1) != argc) { ++ help(); ++ } ++ filename = argv[optind++]; ++ ++ Error *errp = NULL; ++ VmaReader *vmar = vma_reader_create(filename, &errp); ++ ++ if (!vmar) { ++ g_error("%s", error_get_pretty(errp)); ++ } ++ ++ if (verbose) { ++ print_content(vmar); ++ } ++ ++ if (vma_reader_verify(vmar, verbose, &errp) < 0) { ++ g_error("verify failed - %s", error_get_pretty(errp)); ++ } ++ ++ vma_reader_destroy(vmar); ++ + bdrv_close_all(); + + return ret; +} + +typedef struct BackupJob { -+ BlockDriverState *bs; ++ BlockBackend *target; + int64_t len; + VmaWriter *vmaw; + uint8_t dev_id; @@ -2081,6 +2899,18 @@ index 0000000000..8732bfa85e + +#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; @@ -2090,7 +2920,7 @@ index 0000000000..8732bfa85e + int64_t start, end; + int ret = 0; + -+ unsigned char *buf = qemu_blockalign(job->bs, VMA_CLUSTER_SIZE); ++ unsigned char *buf = blk_blockalign(job->target, VMA_CLUSTER_SIZE); + + start = 0; + end = DIV_ROUND_UP(job->len / BDRV_SECTOR_SIZE, @@ -2101,8 +2931,8 @@ index 0000000000..8732bfa85e + iov.iov_len = VMA_CLUSTER_SIZE; + qemu_iovec_init_external(&qiov, &iov, 1); + -+ ret = bdrv_co_readv(job->bs, start * BACKUP_SECTORS_PER_CLUSTER, -+ BACKUP_SECTORS_PER_CLUSTER, &qiov); ++ ret = blk_co_preadv(job->target, start * VMA_CLUSTER_SIZE, ++ VMA_CLUSTER_SIZE, &qiov, 0); + if (ret < 0) { + vma_writer_set_error(job->vmaw, "read error", -1); + goto out; @@ -2154,8 +2984,8 @@ index 0000000000..8732bfa85e + } + + -+ /* 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(); + } + @@ -2190,21 +3020,21 @@ index 0000000000..8732bfa85e + 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++); + + Error *errp = NULL; -+ BlockDriverState *bs; ++ BlockBackend *target; + -+ bs = bdrv_open(path, NULL, NULL, 0, &errp); -+ if (!bs) { ++ target = blk_new_open(path, NULL, NULL, 0, &errp); ++ if (!target) { + unlink(archivename); + g_error("bdrv_open '%s' failed - %s", path, error_get_pretty(errp)); + } -+ int64_t size = bdrv_getlength(bs); ++ int64_t size = blk_getlength(target); + int dev_id = vma_writer_register_stream(vmaw, devname, size); + if (dev_id <= 0) { + unlink(archivename); @@ -2213,7 +3043,7 @@ index 0000000000..8732bfa85e + + BackupJob *job = g_new0(BackupJob, 1); + job->len = size; -+ job->bs = bs; ++ job->target = target; + job->vmaw = vmaw; + job->dev_id = dev_id; + @@ -2225,37 +3055,39 @@ index 0000000000..8732bfa85e + int percent = 0; + int last_percent = -1; + -+ while (1) { -+ main_loop_wait(false); -+ vma_writer_get_status(vmaw, &vmastat); ++ if (devcount) { ++ while (1) { ++ main_loop_wait(false); ++ vma_writer_get_status(vmaw, &vmastat); + -+ if (verbose) { ++ if (verbose) { + -+ uint64_t total = 0; -+ uint64_t transferred = 0; -+ uint64_t zero_bytes = 0; ++ 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; ++ 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); ++ ++ last_percent = percent; + } + } -+ 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; ++ if (vmastat.closed) { ++ break; + } + } -+ -+ if (vmastat.closed) { -+ break; -+ } + } else { + Coroutine *co = qemu_coroutine_create(backup_run_empty, vmaw); + qemu_coroutine_enter(co); @@ -2291,6 +3123,67 @@ index 0000000000..8732bfa85e + return 0; +} + ++static int dump_config(int argc, char **argv) ++{ ++ int c, ret = 0; ++ const char *filename; ++ const char *config_name = "qemu-server.conf"; ++ ++ for (;;) { ++ c = getopt(argc, argv, "hc:"); ++ if (c == -1) { ++ break; ++ } ++ switch (c) { ++ case '?': ++ case 'h': ++ help(); ++ break; ++ case 'c': ++ config_name = optarg; ++ break; ++ default: ++ help(); ++ } ++ } ++ ++ /* Get the filename */ ++ if ((optind + 1) != argc) { ++ help(); ++ } ++ filename = argv[optind++]; ++ ++ Error *errp = NULL; ++ VmaReader *vmar = vma_reader_create(filename, &errp); ++ ++ if (!vmar) { ++ g_error("%s", error_get_pretty(errp)); ++ } ++ ++ int found = 0; ++ GList *l = vma_reader_get_config_data(vmar); ++ while (l && l->data) { ++ VmaConfigData *cdata = (VmaConfigData *)l->data; ++ l = g_list_next(l); ++ if (strcmp(cdata->name, config_name) == 0) { ++ found = 1; ++ fwrite(cdata->data, cdata->len, 1, stdout); ++ break; ++ } ++ } ++ ++ vma_reader_destroy(vmar); ++ ++ bdrv_close_all(); ++ ++ if (!found) { ++ fprintf(stderr, "unable to find configuration data '%s'\n", config_name); ++ return -1; ++ } ++ ++ return ret; ++} ++ +int main(int argc, char **argv) +{ + const char *cmdname; @@ -2318,6 +3211,10 @@ index 0000000000..8732bfa85e + return create_archive(argc, argv); + } else if (!strcmp(cmdname, "extract")) { + return extract_content(argc, argv); ++ } else if (!strcmp(cmdname, "verify")) { ++ return verify_content(argc, argv); ++ } else if (!strcmp(cmdname, "config")) { ++ return dump_config(argc, argv); + } + + help(); @@ -2325,10 +3222,10 @@ index 0000000000..8732bfa85e +} diff --git a/vma.h b/vma.h new file mode 100644 -index 0000000000..6625eb95c6 +index 0000000000..fa6f4df7e7 --- /dev/null +++ b/vma.h -@@ -0,0 +1,146 @@ +@@ -0,0 +1,149 @@ +/* + * VMA: Virtual Machine Archive + * @@ -2447,6 +3344,7 @@ index 0000000000..6625eb95c6 + +VmaWriter *vma_writer_create(const char *filename, uuid_t uuid, Error **errp); +int vma_writer_close(VmaWriter *vmaw, Error **errp); ++void vma_writer_error_propagate(VmaWriter *vmaw, Error **errp); +void vma_writer_destroy(VmaWriter *vmaw); +int vma_writer_add_config(VmaWriter *vmaw, const char *name, gpointer data, + size_t len); @@ -2458,6 +3356,7 @@ index 0000000000..6625eb95c6 + 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, ...); @@ -2469,10 +3368,11 @@ index 0000000000..6625eb95c6 +GList *vma_reader_get_config_data(VmaReader *vmar); +VmaDeviceInfo *vma_reader_get_device_info(VmaReader *vmar, guint8 dev_id); +int vma_reader_register_bs(VmaReader *vmar, guint8 dev_id, -+ BlockDriverState *bs, bool write_zeroes, ++ BlockBackend *target, bool write_zeroes, + Error **errp); +int vma_reader_restore(VmaReader *vmar, int vmstate_fd, bool verbose, + Error **errp); ++int vma_reader_verify(VmaReader *vmar, bool verbose, Error **errp); + +#endif /* BACKUP_VMA_H */ -- diff --git a/debian/patches/pve/0028-savevm-async-migration-and-bdrv_open-update.patch b/debian/patches/pve/0028-savevm-async-migration-and-bdrv_open-update.patch deleted file mode 100644 index 6e859c6..0000000 --- a/debian/patches/pve/0028-savevm-async-migration-and-bdrv_open-update.patch +++ /dev/null @@ -1,101 +0,0 @@ -From c9ec344900b5d2459a70dae88a0e1f309f864775 Mon Sep 17 00:00:00 2001 -From: Wolfgang Bumiller -Date: Thu, 10 Dec 2015 15:14:00 +0100 -Subject: [PATCH 28/49] savevm-async: migration and bdrv_open update - ---- - savevm-async.c | 25 ++++++++++++------------- - 1 file changed, 12 insertions(+), 13 deletions(-) - -diff --git a/savevm-async.c b/savevm-async.c -index 9704a412d9..6ac03af9c8 100644 ---- a/savevm-async.c -+++ b/savevm-async.c -@@ -154,10 +154,10 @@ static int block_state_close(void *opaque) - return bdrv_flush(snap_state.bs); - } - --static int block_state_put_buffer(void *opaque, const uint8_t *buf, -- int64_t pos, int size) -+static ssize_t block_state_put_buffer(void *opaque, const uint8_t *buf, -+ int64_t pos, size_t size) - { -- int ret; -+ ssize_t ret; - - assert(pos == snap_state.bs_pos); - -@@ -201,12 +201,13 @@ static void process_savevm_co(void *opaque) - } - - while (snap_state.state == SAVE_STATE_ACTIVE) { -- uint64_t pending_size; -+ uint64_t pending_size, pend_post, pend_nonpost; - -- pending_size = qemu_savevm_state_pending(snap_state.file, 0); -+ qemu_savevm_state_pending(snap_state.file, 0, &pend_nonpost, &pend_post); -+ pending_size = pend_post + pend_nonpost; - - if (pending_size) { -- ret = qemu_savevm_state_iterate(snap_state.file); -+ ret = qemu_savevm_state_iterate(snap_state.file, false); - if (ret < 0) { - save_snapshot_error("qemu_savevm_state_iterate error %d", ret); - break; -@@ -217,7 +218,7 @@ static void process_savevm_co(void *opaque) - if (store_and_stop()) - break; - DPRINTF("savevm inerate finished\n"); -- qemu_savevm_state_complete_precopy(snap_state.file); -+ qemu_savevm_state_complete_precopy(snap_state.file, false); - DPRINTF("save complete\n"); - save_snapshot_completed(); - break; -@@ -250,7 +251,6 @@ static const QEMUFileOps block_file_ops = { - - void qmp_savevm_start(bool has_statefile, const char *statefile, Error **errp) - { -- BlockDriver *drv = NULL; - Error *local_err = NULL; - - int bdrv_oflags = BDRV_O_RDWR | BDRV_O_RESIZE; -@@ -289,7 +289,7 @@ void qmp_savevm_start(bool has_statefile, const char *statefile, Error **errp) - QDict *options = NULL; - options = qdict_new(); - qdict_put(options, "driver", qstring_from_str("raw")); -- ret = bdrv_open(&snap_state.bs, statefile, NULL, options, bdrv_oflags, drv, &local_err); -+ ret = bdrv_open(&snap_state.bs, statefile, NULL, options, bdrv_oflags, &local_err); - if (ret < 0) { - error_set(errp, ERROR_CLASS_GENERIC_ERROR, "failed to open '%s'", statefile); - goto restart; -@@ -454,8 +454,8 @@ void qmp_delete_drive_snapshot(const char *device, const char *name, - } - } - --static int loadstate_get_buffer(void *opaque, uint8_t *buf, int64_t pos, -- int size) -+static ssize_t loadstate_get_buffer(void *opaque, uint8_t *buf, int64_t pos, -+ size_t size) - { - BlockDriverState *bs = (BlockDriverState *)opaque; - int64_t maxlen = bdrv_getlength(bs); -@@ -478,7 +478,6 @@ static const QEMUFileOps loadstate_file_ops = { - int load_state_from_blockdev(const char *filename) - { - BlockDriverState *bs = NULL; -- BlockDriver *drv = NULL; - Error *local_err = NULL; - Error *blocker = NULL; - -@@ -486,7 +485,7 @@ int load_state_from_blockdev(const char *filename) - int ret; - - bs = bdrv_new(); -- ret = bdrv_open(&bs, filename, NULL, NULL, 0, drv, &local_err); -+ ret = bdrv_open(&bs, filename, NULL, NULL, 0, &local_err); - error_setg(&blocker, "block device is in use by load state"); - bdrv_op_block_all(bs, blocker); - --- -2.11.0 - diff --git a/debian/patches/pve/0031-vma-writer-don-t-bail-out-on-zero-length-files.patch b/debian/patches/pve/0031-vma-writer-don-t-bail-out-on-zero-length-files.patch deleted file mode 100644 index 5e52165..0000000 --- a/debian/patches/pve/0031-vma-writer-don-t-bail-out-on-zero-length-files.patch +++ /dev/null @@ -1,24 +0,0 @@ -From d79bc8c38a8672f894ad20ffed3529b66560c818 Mon Sep 17 00:00:00 2001 -From: Wolfgang Bumiller -Date: Mon, 8 Feb 2016 08:23:34 +0100 -Subject: [PATCH 31/49] vma-writer: don't bail out on zero-length files - ---- - vma-writer.c | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/vma-writer.c b/vma-writer.c -index 0dd668b257..70dcca0771 100644 ---- a/vma-writer.c -+++ b/vma-writer.c -@@ -130,7 +130,6 @@ int vma_writer_add_config(VmaWriter *vmaw, const char *name, gpointer data, - assert(vmaw->config_count < VMA_MAX_CONFIGS); - assert(name); - assert(data); -- assert(len); - - gchar *basename = g_path_get_basename(name); - uint32_t name_ptr = allocate_header_string(vmaw, basename); --- -2.11.0 - diff --git a/debian/patches/pve/0032-vma-better-driver-guessing-for-bdrv_open.patch b/debian/patches/pve/0032-vma-better-driver-guessing-for-bdrv_open.patch deleted file mode 100644 index 2cb14e1..0000000 --- a/debian/patches/pve/0032-vma-better-driver-guessing-for-bdrv_open.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 81e295744d016824a5c756bfc954c63f5a249b5f Mon Sep 17 00:00:00 2001 -From: Wolfgang Bumiller -Date: Tue, 23 Feb 2016 15:48:41 +0100 -Subject: [PATCH 32/49] vma: better driver guessing for bdrv_open - -Only use 'raw' when the file actually ends with .raw and -no protocol has been specified. With protocol pass the -BDRV_O_PROTOCOL flag to tell bdrv_fill_options() to take it -into account. ---- - vma.c | 15 ++++++++++++++- - 1 file changed, 14 insertions(+), 1 deletion(-) - -diff --git a/vma.c b/vma.c -index c7c05385f6..4903568fb4 100644 ---- a/vma.c -+++ b/vma.c -@@ -294,7 +294,20 @@ static int extract_content(int argc, char **argv) - } - - BlockDriverState *bs = bdrv_new(); -- if (errp || bdrv_open(&bs, devfn, NULL, NULL, flags, &errp)) { -+ -+ size_t devlen = strlen(devfn); -+ bool protocol = path_has_protocol(devfn); -+ QDict *options = NULL; -+ if (devlen > 4 && strcmp(devfn+devlen-4, ".raw") == 0 && !protocol) { -+ /* explicit raw format */ -+ options = qdict_new(); -+ qdict_put(options, "driver", qstring_from_str("raw")); -+ } else if (protocol) { -+ /* tell bdrv_open to honor the protocol */ -+ flags |= BDRV_O_PROTOCOL; -+ } -+ -+ if (errp || bdrv_open(&bs, devfn, NULL, options, flags, &errp)) { - g_error("can't open file %s - %s", devfn, - error_get_pretty(errp)); - } --- -2.11.0 - diff --git a/debian/patches/pve/0034-vma-add-format-option-to-device-mapping.patch b/debian/patches/pve/0034-vma-add-format-option-to-device-mapping.patch deleted file mode 100644 index 2901e0e..0000000 --- a/debian/patches/pve/0034-vma-add-format-option-to-device-mapping.patch +++ /dev/null @@ -1,108 +0,0 @@ -From 17e81056ca6835c3b800db8b62f093c7f7571d49 Mon Sep 17 00:00:00 2001 -From: Wolfgang Bumiller -Date: Tue, 12 Apr 2016 13:49:44 +0200 -Subject: [PATCH 34/49] vma: add format option to device mapping - -The BDRV_O_PROTOCOL option breaks non-raw protocol devices, -so we instead now allow the format to be explicitly -specified from the outside. - -In other words we now too deprecate the automatic guessing -of raw formats, just like qemu already does, and have to -silence the warnings by passing the drive mapping. ---- - vma.c | 34 +++++++++++++++++++++++++++------- - 1 file changed, 27 insertions(+), 7 deletions(-) - -diff --git a/vma.c b/vma.c -index 4903568fb4..f71e5a5933 100644 ---- a/vma.c -+++ b/vma.c -@@ -131,6 +131,7 @@ static int list_content(int argc, char **argv) - typedef struct RestoreMap { - char *devname; - char *path; -+ char *format; - bool write_zero; - } RestoreMap; - -@@ -218,13 +219,24 @@ static int extract_content(int argc, char **argv) - } - } - -+ char *format = NULL; -+ if (strncmp(line, "format=", sizeof("format=")-1) == 0) { -+ format = line + sizeof("format=")-1; -+ char *colon = strchr(format, ':'); -+ if (!colon) { -+ g_error("read map failed - found only a format ('%s')", inbuf); -+ } -+ format = g_strndup(format, colon - format); -+ line = colon+1; -+ } -+ - const char *path; - bool write_zero; - if (line[0] == '0' && line[1] == ':') { -- path = inbuf + 2; -+ path = line + 2; - write_zero = false; - } else if (line[0] == '1' && line[1] == ':') { -- path = inbuf + 2; -+ path = line + 2; - write_zero = true; - } else { - g_error("read map failed - parse error ('%s')", inbuf); -@@ -240,6 +252,7 @@ static int extract_content(int argc, char **argv) - RestoreMap *map = g_new0(RestoreMap, 1); - map->devname = g_strdup(devname); - map->path = g_strdup(path); -+ map->format = format; - map->write_zero = write_zero; - - g_hash_table_insert(devmap, map->devname, map); -@@ -264,6 +277,7 @@ static int extract_content(int argc, char **argv) - g_free(statefn); - } else if (di) { - char *devfn = NULL; -+ const char *format = NULL; - int flags = BDRV_O_RDWR; - bool write_zero = true; - -@@ -274,6 +288,7 @@ static int extract_content(int argc, char **argv) - g_error("no device name mapping for %s", di->devname); - } - devfn = map->path; -+ format = map->format; - write_zero = map->write_zero; - } else { - devfn = g_strdup_printf("%s/tmp-disk-%s.raw", -@@ -296,15 +311,20 @@ static int extract_content(int argc, char **argv) - BlockDriverState *bs = bdrv_new(); - - size_t devlen = strlen(devfn); -- bool protocol = path_has_protocol(devfn); - QDict *options = NULL; -- if (devlen > 4 && strcmp(devfn+devlen-4, ".raw") == 0 && !protocol) { -+ if (format) { -+ /* explicit format from commandline */ -+ options = qdict_new(); -+ qdict_put(options, "driver", qstring_from_str(format)); -+ } else if ((devlen > 4 && strcmp(devfn+devlen-4, ".raw") == 0) || -+ strncmp(devfn, "/dev/", 5) == 0) -+ { -+ /* This part is now deprecated for PVE as well (just as qemu -+ * deprecated not specifying an explicit raw format, too. -+ */ - /* explicit raw format */ - options = qdict_new(); - qdict_put(options, "driver", qstring_from_str("raw")); -- } else if (protocol) { -- /* tell bdrv_open to honor the protocol */ -- flags |= BDRV_O_PROTOCOL; - } - - if (errp || bdrv_open(&bs, devfn, NULL, options, flags, &errp)) { --- -2.11.0 - diff --git a/debian/patches/pve/0036-vnc-refactor-to-QIOChannelSocket.patch b/debian/patches/pve/0036-vnc-refactor-to-QIOChannelSocket.patch deleted file mode 100644 index b9ef476..0000000 --- a/debian/patches/pve/0036-vnc-refactor-to-QIOChannelSocket.patch +++ /dev/null @@ -1,87 +0,0 @@ -From dd70c07d8a666f0046a88626249b2567acdc1c26 Mon Sep 17 00:00:00 2001 -From: Thomas Lamprecht -Date: Wed, 6 Apr 2016 16:47:54 +0200 -Subject: [PATCH 36/49] vnc: refactor to QIOChannelSocket - ---- - ui/vnc-auth-vencrypt.c | 31 ++++++++++++++++--------------- - 1 file changed, 16 insertions(+), 15 deletions(-) - -diff --git a/ui/vnc-auth-vencrypt.c b/ui/vnc-auth-vencrypt.c -index de1c1949ba..594ca737a9 100644 ---- a/ui/vnc-auth-vencrypt.c -+++ b/ui/vnc-auth-vencrypt.c -@@ -28,27 +28,23 @@ - #include "vnc.h" - #include "qapi/error.h" - #include "qemu/main-loop.h" --#include "qemu/sockets.h" -+#include "io/channel-socket.h" - - static int protocol_client_auth_plain(VncState *vs, uint8_t *data, size_t len) - { -- const char *err = NULL; -+ Error *err = NULL; - char username[256]; - char passwd[512]; - -- char clientip[256]; -- clientip[0] = 0; -- struct sockaddr_in client; -- socklen_t addrlen = sizeof(client); -- if (getpeername(vs->csock, &client, &addrlen) == 0) { -- inet_ntop(client.sin_family, &client.sin_addr, -- clientip, sizeof(clientip)); -+ SocketAddress *clientip = qio_channel_socket_get_remote_address(vs->sioc, &err); -+ if (err) { -+ goto err; - } - - if ((len != (vs->username_len + vs->password_len)) || - (vs->username_len >= (sizeof(username)-1)) || - (vs->password_len >= (sizeof(passwd)-1)) ) { -- err = "Got unexpected data length"; -+ error_setg(&err, "Got unexpected data length"); - goto err; - } - -@@ -59,26 +55,31 @@ static int protocol_client_auth_plain(VncState *vs, uint8_t *data, size_t len) - - VNC_DEBUG("AUTH PLAIN username: %s pw: %s\n", username, passwd); - -- if (pve_auth_verify(clientip, username, passwd) == 0) { -+ if (pve_auth_verify(clientip->u.inet.data->host, username, passwd) == 0) { - vnc_write_u32(vs, 0); /* Accept auth completion */ - start_client_init(vs); -+ qapi_free_SocketAddress(clientip); - return 0; - } - -- err = "Authentication failed"; -+ error_setg(&err, "Authentication failed"); - err: - if (err) { -- VNC_DEBUG("AUTH PLAIN ERROR: %s\n", err); -+ const char *err_msg = error_get_pretty(err); -+ VNC_DEBUG("AUTH PLAIN ERROR: %s\n", err_msg); - vnc_write_u32(vs, 1); /* Reject auth */ - if (vs->minor >= 8) { -- int elen = strlen(err); -+ int elen = strlen(err_msg); - vnc_write_u32(vs, elen); -- vnc_write(vs, err, elen); -+ vnc_write(vs, err_msg, elen); - } -+ error_free(err); - } - vnc_flush(vs); - vnc_client_error(vs); - -+ qapi_free_SocketAddress(clientip); -+ - return 0; - - } --- -2.11.0 - diff --git a/debian/patches/pve/0037-vma-use-BlockBackend-on-extract.patch b/debian/patches/pve/0037-vma-use-BlockBackend-on-extract.patch deleted file mode 100644 index c6a817b..0000000 --- a/debian/patches/pve/0037-vma-use-BlockBackend-on-extract.patch +++ /dev/null @@ -1,75 +0,0 @@ -From ccc8208669d45d5442d5f0739ce1e6a158942ea3 Mon Sep 17 00:00:00 2001 -From: Thomas Lamprecht -Date: Fri, 1 Jul 2016 15:47:29 +0200 -Subject: [PATCH 37/49] vma: use BlockBackend on extract - -As we else rely on bdrv_close_all() do clean up, which was rewritten -in ca9bd24cf1d53775169ba9adc17e265554d1afed and fails on "dangling" -BDS pointers, such a pointer exists with *bs. -Use the BlockBackend to get our BDS and just unref the BlockBackend -when done, it handles the rest for us. - -The other two calls to bdrv_close_all() happen in verify_content() -and dump_config(), both do not have a BDS so no need to change here. ---- - vma.c | 13 ++++++++++--- - 1 file changed, 10 insertions(+), 3 deletions(-) - -diff --git a/vma.c b/vma.c -index f71e5a5933..ad51090651 100644 ---- a/vma.c -+++ b/vma.c -@@ -20,6 +20,7 @@ - #include "qemu/main-loop.h" - #include "qapi/qmp/qstring.h" - #include "sysemu/char.h" /* qstring_from_str */ -+#include "sysemu/block-backend.h" - - static void help(void) - { -@@ -264,6 +265,8 @@ static int extract_content(int argc, char **argv) - int vmstate_fd = -1; - guint8 vmstate_stream = 0; - -+ BlockBackend *blk = NULL; -+ - for (i = 1; i < 255; i++) { - VmaDeviceInfo *di = vma_reader_get_device_info(vmar, i); - if (di && (strcmp(di->devname, "vmstate") == 0)) { -@@ -308,8 +311,6 @@ static int extract_content(int argc, char **argv) - write_zero = false; - } - -- BlockDriverState *bs = bdrv_new(); -- - size_t devlen = strlen(devfn); - QDict *options = NULL; - if (format) { -@@ -327,10 +328,14 @@ static int extract_content(int argc, char **argv) - qdict_put(options, "driver", qstring_from_str("raw")); - } - -- if (errp || bdrv_open(&bs, devfn, NULL, options, flags, &errp)) { -+ -+ if (errp || !(blk = blk_new_open(devfn, NULL, options, flags, &errp))) { - g_error("can't open file %s - %s", devfn, - error_get_pretty(errp)); - } -+ -+ BlockDriverState *bs = blk_bs(blk); -+ - if (vma_reader_register_bs(vmar, i, bs, write_zero, &errp) < 0) { - g_error("%s", error_get_pretty(errp)); - } -@@ -363,6 +368,8 @@ static int extract_content(int argc, char **argv) - - vma_reader_destroy(vmar); - -+ blk_unref(blk); -+ - bdrv_close_all(); - - return ret; --- -2.11.0 - diff --git a/debian/patches/pve/0038-vma-byte-based-write-calls.patch b/debian/patches/pve/0038-vma-byte-based-write-calls.patch deleted file mode 100644 index 56edb1e..0000000 --- a/debian/patches/pve/0038-vma-byte-based-write-calls.patch +++ /dev/null @@ -1,237 +0,0 @@ -From b6f11a95c56de227d2c66f4049ace7e01369c920 Mon Sep 17 00:00:00 2001 -From: Wolfgang Bumiller -Date: Fri, 9 Sep 2016 14:51:28 +0200 -Subject: [PATCH 38/49] vma: byte based write calls - ---- - vma-reader.c | 42 +++++++++++++++++++++--------------------- - vma.c | 22 ++++++++++------------ - vma.h | 2 +- - 3 files changed, 32 insertions(+), 34 deletions(-) - -diff --git a/vma-reader.c b/vma-reader.c -index 78f1de9499..2000889bd3 100644 ---- a/vma-reader.c -+++ b/vma-reader.c -@@ -25,7 +25,7 @@ - static unsigned char zero_vma_block[VMA_BLOCK_SIZE]; - - typedef struct VmaRestoreState { -- BlockDriverState *bs; -+ BlockBackend *target; - bool write_zeroes; - unsigned long *bitmap; - int bitmap_size; -@@ -423,12 +423,12 @@ VmaDeviceInfo *vma_reader_get_device_info(VmaReader *vmar, guint8 dev_id) - } - - static void allocate_rstate(VmaReader *vmar, guint8 dev_id, -- BlockDriverState *bs, bool write_zeroes) -+ BlockBackend *target, bool write_zeroes) - { - assert(vmar); - assert(dev_id); - -- vmar->rstate[dev_id].bs = bs; -+ vmar->rstate[dev_id].target = target; - vmar->rstate[dev_id].write_zeroes = write_zeroes; - - int64_t size = vmar->devinfo[dev_id].size; -@@ -443,15 +443,15 @@ static void allocate_rstate(VmaReader *vmar, guint8 dev_id, - vmar->cluster_count += size/VMA_CLUSTER_SIZE; - } - --int vma_reader_register_bs(VmaReader *vmar, guint8 dev_id, BlockDriverState *bs, -+int vma_reader_register_bs(VmaReader *vmar, guint8 dev_id, BlockBackend *target, - bool write_zeroes, Error **errp) - { - assert(vmar); -- assert(bs != NULL); -+ assert(target != NULL); - assert(dev_id); -- assert(vmar->rstate[dev_id].bs == NULL); -+ assert(vmar->rstate[dev_id].target == NULL); - -- int64_t size = bdrv_getlength(bs); -+ int64_t size = blk_getlength(target); - int64_t size_diff = size - vmar->devinfo[dev_id].size; - - /* storage types can have different size restrictions, so it -@@ -465,7 +465,7 @@ int vma_reader_register_bs(VmaReader *vmar, guint8 dev_id, BlockDriverState *bs, - return -1; - } - -- allocate_rstate(vmar, dev_id, bs, write_zeroes); -+ allocate_rstate(vmar, dev_id, target, write_zeroes); - - return 0; - } -@@ -507,7 +507,7 @@ static size_t full_write(int fd, void *buf, size_t len) - } - - static int restore_write_data(VmaReader *vmar, guint8 dev_id, -- BlockDriverState *bs, int vmstate_fd, -+ BlockBackend *target, int vmstate_fd, - unsigned char *buf, int64_t sector_num, - int nb_sectors, Error **errp) - { -@@ -523,10 +523,10 @@ static int restore_write_data(VmaReader *vmar, guint8 dev_id, - } - } - } else { -- int res = bdrv_write(bs, sector_num, buf, nb_sectors); -+ int res = blk_pwrite(target, sector_num * BDRV_SECTOR_SIZE, buf, nb_sectors * BDRV_SECTOR_SIZE, 0); - if (res < 0) { -- error_setg(errp, "bdrv_write to %s failed (%d)", -- bdrv_get_device_name(bs), res); -+ error_setg(errp, "blk_pwrite to %s failed (%d)", -+ bdrv_get_device_name(blk_bs(target)), res); - return -1; - } - } -@@ -556,11 +556,11 @@ static int restore_extent(VmaReader *vmar, unsigned char *buf, - } - - VmaRestoreState *rstate = &vmar->rstate[dev_id]; -- BlockDriverState *bs = NULL; -+ BlockBackend *target = NULL; - - if (dev_id != vmar->vmstate_stream) { -- bs = rstate->bs; -- if (!verify && !bs) { -+ target = rstate->target; -+ if (!verify && !target) { - error_setg(errp, "got wrong dev id %d", dev_id); - return -1; - } -@@ -618,7 +618,7 @@ static int restore_extent(VmaReader *vmar, unsigned char *buf, - - if (!verify) { - int nb_sectors = end_sector - sector_num; -- if (restore_write_data(vmar, dev_id, bs, vmstate_fd, -+ if (restore_write_data(vmar, dev_id, target, vmstate_fd, - buf + start, sector_num, nb_sectors, - errp) < 0) { - return -1; -@@ -654,7 +654,7 @@ static int restore_extent(VmaReader *vmar, unsigned char *buf, - - if (!verify) { - int nb_sectors = end_sector - sector_num; -- if (restore_write_data(vmar, dev_id, bs, vmstate_fd, -+ if (restore_write_data(vmar, dev_id, target, vmstate_fd, - buf + start, sector_num, - nb_sectors, errp) < 0) { - return -1; -@@ -678,7 +678,7 @@ static int restore_extent(VmaReader *vmar, unsigned char *buf, - } - - if (rstate->write_zeroes && !verify) { -- if (restore_write_data(vmar, dev_id, bs, vmstate_fd, -+ if (restore_write_data(vmar, dev_id, target, vmstate_fd, - zero_vma_block, sector_num, - nb_sectors, errp) < 0) { - return -1; -@@ -786,12 +786,12 @@ static int vma_reader_restore_full(VmaReader *vmar, int vmstate_fd, - int i; - for (i = 1; i < 256; i++) { - VmaRestoreState *rstate = &vmar->rstate[i]; -- if (!rstate->bs) { -+ if (!rstate->target) { - continue; - } - -- if (bdrv_flush(rstate->bs) < 0) { -- error_setg(errp, "vma bdrv_flush %s failed", -+ if (blk_flush(rstate->target) < 0) { -+ error_setg(errp, "vma blk_flush %s failed", - vmar->devinfo[i].devname); - return -1; - } -diff --git a/vma.c b/vma.c -index ad51090651..aafdc2d7f5 100644 ---- a/vma.c -+++ b/vma.c -@@ -334,9 +334,7 @@ static int extract_content(int argc, char **argv) - error_get_pretty(errp)); - } - -- BlockDriverState *bs = blk_bs(blk); -- -- if (vma_reader_register_bs(vmar, i, bs, write_zero, &errp) < 0) { -+ if (vma_reader_register_bs(vmar, i, blk, write_zero, &errp) < 0) { - g_error("%s", error_get_pretty(errp)); - } - -@@ -428,7 +426,7 @@ static int verify_content(int argc, char **argv) - } - - typedef struct BackupJob { -- BlockDriverState *bs; -+ BlockBackend *target; - int64_t len; - VmaWriter *vmaw; - uint8_t dev_id; -@@ -457,7 +455,7 @@ static void coroutine_fn backup_run(void *opaque) - int64_t start, end; - int ret = 0; - -- unsigned char *buf = qemu_blockalign(job->bs, VMA_CLUSTER_SIZE); -+ unsigned char *buf = blk_blockalign(job->target, VMA_CLUSTER_SIZE); - - start = 0; - end = DIV_ROUND_UP(job->len / BDRV_SECTOR_SIZE, -@@ -468,8 +466,8 @@ static void coroutine_fn backup_run(void *opaque) - iov.iov_len = VMA_CLUSTER_SIZE; - qemu_iovec_init_external(&qiov, &iov, 1); - -- ret = bdrv_co_readv(job->bs, start * BACKUP_SECTORS_PER_CLUSTER, -- BACKUP_SECTORS_PER_CLUSTER, &qiov); -+ ret = blk_co_preadv(job->target, start * BACKUP_SECTORS_PER_CLUSTER, -+ BACKUP_SECTORS_PER_CLUSTER, &qiov, 0); - if (ret < 0) { - vma_writer_set_error(job->vmaw, "read error", -1); - goto out; -@@ -564,14 +562,14 @@ static int create_archive(int argc, char **argv) - path = extract_devname(path, &devname, devcount++); - - Error *errp = NULL; -- BlockDriverState *bs; -+ BlockBackend *target; - -- bs = bdrv_open(path, NULL, NULL, 0, &errp); -- if (!bs) { -+ target = blk_new_open(path, NULL, NULL, 0, &errp); -+ if (!target) { - unlink(archivename); - g_error("bdrv_open '%s' failed - %s", path, error_get_pretty(errp)); - } -- int64_t size = bdrv_getlength(bs); -+ int64_t size = blk_getlength(target); - int dev_id = vma_writer_register_stream(vmaw, devname, size); - if (dev_id <= 0) { - unlink(archivename); -@@ -580,7 +578,7 @@ static int create_archive(int argc, char **argv) - - BackupJob *job = g_new0(BackupJob, 1); - job->len = size; -- job->bs = bs; -+ job->target = target; - job->vmaw = vmaw; - job->dev_id = dev_id; - -diff --git a/vma.h b/vma.h -index 365ceb2bcb..fa6f4df7e7 100644 ---- a/vma.h -+++ b/vma.h -@@ -140,7 +140,7 @@ VmaHeader *vma_reader_get_header(VmaReader *vmar); - GList *vma_reader_get_config_data(VmaReader *vmar); - VmaDeviceInfo *vma_reader_get_device_info(VmaReader *vmar, guint8 dev_id); - int vma_reader_register_bs(VmaReader *vmar, guint8 dev_id, -- BlockDriverState *bs, bool write_zeroes, -+ BlockBackend *target, bool write_zeroes, - Error **errp); - int vma_reader_restore(VmaReader *vmar, int vmstate_fd, bool verbose, - Error **errp); --- -2.11.0 - diff --git a/debian/patches/pve/0040-enable-cache-unsafe-for-vma-extract_content-and-qmp_.patch b/debian/patches/pve/0040-enable-cache-unsafe-for-vma-extract_content-and-qmp_.patch deleted file mode 100644 index 9d69954..0000000 --- a/debian/patches/pve/0040-enable-cache-unsafe-for-vma-extract_content-and-qmp_.patch +++ /dev/null @@ -1,43 +0,0 @@ -From eba97a008e2b0eea7229ba0020b2910f147e545b Mon Sep 17 00:00:00 2001 -From: Wolfgang Bumiller -Date: Mon, 1 Aug 2016 10:52:46 +0200 -Subject: [PATCH 40/49] enable cache=unsafe for vma extract_content and - qmp_savevm_start - -We don't send any flush here, so we need to open with cache=unsafe. - -Signed-off-by: Alexandre Derumier ---- - savevm-async.c | 2 +- - vma.c | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/savevm-async.c b/savevm-async.c -index 6ac03af9c8..46c1be7887 100644 ---- a/savevm-async.c -+++ b/savevm-async.c -@@ -253,7 +253,7 @@ void qmp_savevm_start(bool has_statefile, const char *statefile, Error **errp) - { - Error *local_err = NULL; - -- int bdrv_oflags = BDRV_O_RDWR | BDRV_O_RESIZE; -+ int bdrv_oflags = BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_NO_FLUSH; - int ret; - - if (snap_state.state != SAVE_STATE_DONE) { -diff --git a/vma.c b/vma.c -index aafdc2d7f5..4f55799533 100644 ---- a/vma.c -+++ b/vma.c -@@ -281,7 +281,7 @@ static int extract_content(int argc, char **argv) - } else if (di) { - char *devfn = NULL; - const char *format = NULL; -- int flags = BDRV_O_RDWR; -+ int flags = BDRV_O_RDWR | BDRV_O_NO_FLUSH; - bool write_zero = true; - - if (readmap) { --- -2.11.0 - diff --git a/debian/patches/pve/0041-savevm-async-updates.patch b/debian/patches/pve/0041-savevm-async-updates.patch deleted file mode 100644 index 29ebd7c..0000000 --- a/debian/patches/pve/0041-savevm-async-updates.patch +++ /dev/null @@ -1,215 +0,0 @@ -From 11d6573ad09a304b79c149c4f98e565f789b128d Mon Sep 17 00:00:00 2001 -From: Wolfgang Bumiller -Date: Fri, 9 Sep 2016 15:21:19 +0200 -Subject: [PATCH 41/49] savevm-async updates - ---- - savevm-async.c | 79 +++++++++++++++++++++++++++++----------------------------- - 1 file changed, 39 insertions(+), 40 deletions(-) - -diff --git a/savevm-async.c b/savevm-async.c -index 46c1be7887..2f4766cf6c 100644 ---- a/savevm-async.c -+++ b/savevm-async.c -@@ -20,6 +20,8 @@ - - /* #define DEBUG_SAVEVM_STATE */ - -+#define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */ -+ - #ifdef DEBUG_SAVEVM_STATE - #define DPRINTF(fmt, ...) \ - do { printf("savevm-async: " fmt, ## __VA_ARGS__); } while (0) -@@ -38,7 +40,7 @@ enum { - - - static struct SnapshotState { -- BlockDriverState *bs; -+ BlockBackend *target; - size_t bs_pos; - int state; - Error *error; -@@ -99,17 +101,17 @@ static int save_snapshot_cleanup(void) - ret = qemu_fclose(snap_state.file); - } - -- if (snap_state.bs) { -+ if (snap_state.target) { - /* try to truncate, but ignore errors (will fail on block devices). - * note: bdrv_read() need whole blocks, so we round up - */ - size_t size = (snap_state.bs_pos + BDRV_SECTOR_SIZE) & BDRV_SECTOR_MASK; -- bdrv_truncate(snap_state.bs, size); -- bdrv_op_unblock_all(snap_state.bs, snap_state.blocker); -+ blk_truncate(snap_state.target, size); -+ blk_op_unblock_all(snap_state.target, snap_state.blocker); - error_free(snap_state.blocker); - snap_state.blocker = NULL; -- bdrv_unref(snap_state.bs); -- snap_state.bs = NULL; -+ blk_unref(snap_state.target); -+ snap_state.target = NULL; - } - - return ret; -@@ -151,21 +153,22 @@ static void save_snapshot_completed(void) - static int block_state_close(void *opaque) - { - snap_state.file = NULL; -- return bdrv_flush(snap_state.bs); -+ return blk_flush(snap_state.target); - } - --static ssize_t block_state_put_buffer(void *opaque, const uint8_t *buf, -- int64_t pos, size_t size) -+static ssize_t block_state_writev_buffer(void *opaque, struct iovec *iov, -+ int iovcnt, int64_t pos) - { -- ssize_t ret; -- -- assert(pos == snap_state.bs_pos); -+ int ret; -+ QEMUIOVector qiov; - -- if ((ret = bdrv_pwrite(snap_state.bs, snap_state.bs_pos, buf, size)) > 0) { -- snap_state.bs_pos += ret; -+ qemu_iovec_init_external(&qiov, iov, iovcnt); -+ ret = blk_co_pwritev(snap_state.target, pos, qiov.size, &qiov, 0); -+ if (ret < 0) { -+ return ret; - } -- -- return ret; -+ snap_state.bs_pos += qiov.size; -+ return qiov.size; - } - - static int store_and_stop(void) { -@@ -227,7 +230,7 @@ static void process_savevm_co(void *opaque) - /* stop the VM if we get to the end of available space, - * or if pending_size is just a few MB - */ -- maxlen = bdrv_getlength(snap_state.bs) - 30*1024*1024; -+ maxlen = blk_getlength(snap_state.target) - 30*1024*1024; - if ((pending_size < 100000) || - ((snap_state.bs_pos + pending_size) >= maxlen)) { - if (store_and_stop()) -@@ -244,7 +247,7 @@ static void process_savevm_co(void *opaque) - } - - static const QEMUFileOps block_file_ops = { -- .put_buffer = block_state_put_buffer, -+ .writev_buffer = block_state_writev_buffer, - .close = block_state_close, - }; - -@@ -254,7 +257,6 @@ void qmp_savevm_start(bool has_statefile, const char *statefile, Error **errp) - Error *local_err = NULL; - - int bdrv_oflags = BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_NO_FLUSH; -- int ret; - - if (snap_state.state != SAVE_STATE_DONE) { - error_set(errp, ERROR_CLASS_GENERIC_ERROR, -@@ -284,13 +286,11 @@ void qmp_savevm_start(bool has_statefile, const char *statefile, Error **errp) - } - - /* Open the image */ -- snap_state.bs = bdrv_new(); -- - QDict *options = NULL; - options = qdict_new(); - qdict_put(options, "driver", qstring_from_str("raw")); -- ret = bdrv_open(&snap_state.bs, statefile, NULL, options, bdrv_oflags, &local_err); -- if (ret < 0) { -+ snap_state.target = blk_new_open(statefile, NULL, options, bdrv_oflags, &local_err); -+ if (!snap_state.target) { - error_set(errp, ERROR_CLASS_GENERIC_ERROR, "failed to open '%s'", statefile); - goto restart; - } -@@ -304,9 +304,9 @@ void qmp_savevm_start(bool has_statefile, const char *statefile, Error **errp) - - - error_setg(&snap_state.blocker, "block device is in use by savevm"); -- bdrv_op_block_all(snap_state.bs, snap_state.blocker); -+ blk_op_block_all(snap_state.target, snap_state.blocker); - -- Coroutine *co = qemu_coroutine_create(process_savevm_co); -+ Coroutine *co = qemu_coroutine_create(process_savevm_co, NULL); - qemu_coroutine_enter(co); - - return; -@@ -457,8 +457,8 @@ void qmp_delete_drive_snapshot(const char *device, const char *name, - static ssize_t loadstate_get_buffer(void *opaque, uint8_t *buf, int64_t pos, - size_t size) - { -- BlockDriverState *bs = (BlockDriverState *)opaque; -- int64_t maxlen = bdrv_getlength(bs); -+ BlockBackend *be = opaque; -+ int64_t maxlen = blk_getlength(be); - if (pos > maxlen) { - return -EIO; - } -@@ -468,7 +468,7 @@ static ssize_t loadstate_get_buffer(void *opaque, uint8_t *buf, int64_t pos, - if (size == 0) { - return 0; - } -- return bdrv_pread(bs, pos, buf, size); -+ return blk_pread(be, pos, buf, size); - } - - static const QEMUFileOps loadstate_file_ops = { -@@ -477,28 +477,27 @@ static const QEMUFileOps loadstate_file_ops = { - - int load_state_from_blockdev(const char *filename) - { -- BlockDriverState *bs = NULL; -+ BlockBackend *be; - Error *local_err = NULL; - Error *blocker = NULL; - - QEMUFile *f; -- int ret; -+ int ret = -EINVAL; - -- bs = bdrv_new(); -- ret = bdrv_open(&bs, filename, NULL, NULL, 0, &local_err); -- error_setg(&blocker, "block device is in use by load state"); -- bdrv_op_block_all(bs, blocker); -+ be = blk_new_open(filename, NULL, NULL, 0, &local_err); - -- if (ret < 0) { -+ if (!be) { - error_report("Could not open VM state file"); - goto the_end; - } - -+ error_setg(&blocker, "block device is in use by load state"); -+ blk_op_block_all(be, blocker); -+ - /* restore the VM state */ -- f = qemu_fopen_ops(bs, &loadstate_file_ops); -+ f = qemu_fopen_ops(be, &loadstate_file_ops); - if (!f) { - error_report("Could not open VM state file"); -- ret = -EINVAL; - goto the_end; - } - -@@ -515,10 +514,10 @@ int load_state_from_blockdev(const char *filename) - ret = 0; - - the_end: -- if (bs) { -- bdrv_op_unblock_all(bs, blocker); -+ if (be) { -+ blk_op_unblock_all(be, blocker); - error_free(blocker); -- bdrv_unref(bs); -+ blk_unref(be); - } - return ret; - } --- -2.11.0 - diff --git a/debian/patches/pve/0043-vma-sizes-passed-to-blk_co_preadv-should-be-bytes-no.patch b/debian/patches/pve/0043-vma-sizes-passed-to-blk_co_preadv-should-be-bytes-no.patch deleted file mode 100644 index c53e2db..0000000 --- a/debian/patches/pve/0043-vma-sizes-passed-to-blk_co_preadv-should-be-bytes-no.patch +++ /dev/null @@ -1,27 +0,0 @@ -From e74c523db792c8da65faa680ab6898b58b6cb193 Mon Sep 17 00:00:00 2001 -From: Wolfgang Bumiller -Date: Fri, 21 Oct 2016 09:09:26 +0200 -Subject: [PATCH 43/49] vma: sizes passed to blk_co_preadv should be bytes now - ---- - vma.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/vma.c b/vma.c -index 4f55799533..04915427c8 100644 ---- a/vma.c -+++ b/vma.c -@@ -466,8 +466,8 @@ static void coroutine_fn backup_run(void *opaque) - iov.iov_len = VMA_CLUSTER_SIZE; - qemu_iovec_init_external(&qiov, &iov, 1); - -- ret = blk_co_preadv(job->target, start * BACKUP_SECTORS_PER_CLUSTER, -- BACKUP_SECTORS_PER_CLUSTER, &qiov, 0); -+ ret = blk_co_preadv(job->target, start * VMA_CLUSTER_SIZE, -+ VMA_CLUSTER_SIZE, &qiov, 0); - if (ret < 0) { - vma_writer_set_error(job->vmaw, "read error", -1); - goto out; --- -2.11.0 - diff --git a/debian/patches/pve/0048-vma-don-t-use-O_DIRECT-on-pipes.patch b/debian/patches/pve/0048-vma-don-t-use-O_DIRECT-on-pipes.patch deleted file mode 100644 index ae652fd..0000000 --- a/debian/patches/pve/0048-vma-don-t-use-O_DIRECT-on-pipes.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 47d2445ffc83bba6066beb67fa34075d75b5b4c2 Mon Sep 17 00:00:00 2001 -From: Wolfgang Bumiller -Date: Thu, 30 Mar 2017 16:05:34 +0200 -Subject: [PATCH 48/49] vma: don't use O_DIRECT on pipes - -It puts them in packet mode which potentially discards data. -(since kernel 4.5) ---- - vma-writer.c | 10 ++++------ - 1 file changed, 4 insertions(+), 6 deletions(-) - -diff --git a/vma-writer.c b/vma-writer.c -index 70dcca0771..9001cbdd2b 100644 ---- a/vma-writer.c -+++ b/vma-writer.c -@@ -283,9 +283,8 @@ VmaWriter *vma_writer_create(const char *filename, uuid_t uuid, Error **errp) - } - vmaw->fd = fileno(vmaw->cmd); - -- /* try to use O_NONBLOCK and O_DIRECT */ -+ /* try to use O_NONBLOCK */ - 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 { - struct stat st; -@@ -293,19 +292,18 @@ VmaWriter *vma_writer_create(const char *filename, uuid_t uuid, Error **errp) - const char *tmp_id_str; - - if ((stat(filename, &st) == 0) && S_ISFIFO(st.st_mode)) { -- oflags = O_NONBLOCK|O_DIRECT|O_WRONLY; -+ oflags = O_NONBLOCK|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; -+ oflags = O_NONBLOCK|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 */ -+ /* try to use O_NONBLOCK */ - 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); --- -2.11.0 - diff --git a/debian/patches/pve/0049-block-zeroinit-request-child-permissions.patch b/debian/patches/pve/0049-block-zeroinit-request-child-permissions.patch deleted file mode 100644 index 2a2e941..0000000 --- a/debian/patches/pve/0049-block-zeroinit-request-child-permissions.patch +++ /dev/null @@ -1,25 +0,0 @@ -From bc3ed255d5a8e9737abe7ba053de2492164f490a Mon Sep 17 00:00:00 2001 -From: Wolfgang Bumiller -Date: Fri, 31 Mar 2017 09:27:58 +0200 -Subject: [PATCH 49/49] block: zeroinit: request child permissions - -See d7010dfb685 ---- - block/zeroinit.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/block/zeroinit.c b/block/zeroinit.c -index 0a8c7f9622..a857ec3c62 100644 ---- a/block/zeroinit.c -+++ b/block/zeroinit.c -@@ -191,6 +191,7 @@ static BlockDriver bdrv_zeroinit = { - .bdrv_file_open = zeroinit_open, - .bdrv_close = zeroinit_close, - .bdrv_getlength = zeroinit_getlength, -+ .bdrv_child_perm = bdrv_filter_default_perms, - .bdrv_co_flush_to_disk = zeroinit_co_flush, - - .bdrv_co_pwrite_zeroes = zeroinit_co_pwrite_zeroes, --- -2.11.0 - diff --git a/debian/patches/series b/debian/patches/series index 0b7f343..3cd3e4b 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,53 +1,31 @@ pve/0001-fr-ca-keymap-corrections.patch pve/0002-Adjust-network-script-path-to-etc-kvm.patch -pve/0003-vnc-altgr-emulation.patch -pve/0004-qemu-img-return-success-on-info-without-snapshots.patch -pve/0005-use-kvm-by-default.patch -pve/0006-virtio-balloon-fix-query.patch -pve/0007-set-the-CPU-model-to-kvm64-32-instead-of-qemu64-32.patch -pve/0008-qapi-modify-query-machines.patch -pve/0009-qapi-modify-spice-query.patch -pve/0010-ui-spice-default-to-pve-certs-unless-otherwise-speci.patch -pve/0011-introduce-new-vma-archive-format.patch -pve/0012-vma-add-verify-command.patch -pve/0013-vma-add-config-command-to-dump-the-config.patch -pve/0014-backup-modify-job-api.patch -pve/0015-backup-add-pve-monitor-commands.patch -pve/0016-backup-vma-add-dir-format.patch -pve/0017-backup-do-not-return-errors-in-dump-callback.patch -pve/0018-backup-vma-correctly-propagate-error.patch -pve/0019-backup-vma-remove-async-queue.patch -pve/0020-backup-vma-run-flush-inside-coroutine.patch -pve/0021-backup-do-not-use-bdrv_drain_all.patch -pve/0022-internal-snapshot-async.patch -pve/0023-backup-vma-allow-empty-backups.patch -pve/0024-qmp-add-get_link_status.patch -pve/0025-smm_available-false.patch -pve/0026-use-whitespace-between-VERSION-and-PKGVERSION.patch -pve/0027-vma-add-firewall.patch -pve/0028-savevm-async-migration-and-bdrv_open-update.patch -pve/0029-vnc-make-x509-imply-tls-again.patch -pve/0030-PVE-VNC-authentication.patch -pve/0031-vma-writer-don-t-bail-out-on-zero-length-files.patch -pve/0032-vma-better-driver-guessing-for-bdrv_open.patch -pve/0033-block-add-the-zeroinit-block-driver-filter.patch -pve/0034-vma-add-format-option-to-device-mapping.patch -pve/0035-fix-possible-unitialised-return-value.patch -pve/0036-vnc-refactor-to-QIOChannelSocket.patch -pve/0037-vma-use-BlockBackend-on-extract.patch -pve/0038-vma-byte-based-write-calls.patch -pve/0039-rbd-disable-rbd_cache_writethrough_until_flush-with-.patch -pve/0040-enable-cache-unsafe-for-vma-extract_content-and-qmp_.patch -pve/0041-savevm-async-updates.patch -pve/0042-qmp_snapshot_drive-add-aiocontext.patch -pve/0043-vma-sizes-passed-to-blk_co_preadv-should-be-bytes-no.patch -pve/0044-glusterfs-no-default-logfile-if-daemonized.patch -pve/0045-qmp_delete_drive_snapshot-add-aiocontext.patch -pve/0046-convert-savevm-async-to-threads.patch -pve/0047-glusterfs-allow-partial-reads.patch -pve/0048-vma-don-t-use-O_DIRECT-on-pipes.patch -pve/0049-block-zeroinit-request-child-permissions.patch -pve/0050-qemu-img-dd-add-osize-and-read-from-to-stdin-stdout.patch +pve/0003-qemu-img-return-success-on-info-without-snapshots.patch +pve/0004-use-kvm-by-default.patch +pve/0005-virtio-balloon-fix-query.patch +pve/0006-set-the-CPU-model-to-kvm64-32-instead-of-qemu64-32.patch +pve/0007-qapi-modify-query-machines.patch +pve/0008-qapi-modify-spice-query.patch +pve/0009-ui-spice-default-to-pve-certs-unless-otherwise-speci.patch +pve/0010-internal-snapshot-async.patch +pve/0011-convert-savevm-async-to-threads.patch +pve/0012-qmp-add-get_link_status.patch +pve/0013-smm_available-false.patch +pve/0014-use-whitespace-between-VERSION-and-PKGVERSION.patch +pve/0015-vnc-altgr-emulation.patch +pve/0016-vnc-make-x509-imply-tls-again.patch +pve/0017-vnc-PVE-VNC-authentication.patch +pve/0018-migrate-fix-possible-unitialised-return-value.patch +pve/0019-block-rbd-disable-rbd_cache_writethrough_until_flush.patch +pve/0020-block-snapshot-qmp_snapshot_drive-add-aiocontext.patch +pve/0021-block-snapshot-qmp_delete_drive_snapshot-add-aiocont.patch +pve/0022-glusterfs-no-default-logfile-if-daemonized.patch +pve/0023-glusterfs-allow-partial-reads.patch +pve/0024-block-add-the-zeroinit-block-driver-filter.patch +pve/0025-qemu-img-dd-add-osize-and-read-from-to-stdin-stdout.patch +pve/0026-backup-modify-job-api.patch +pve/0027-backup-introduce-vma-archive-format.patch +pve/0028-adding-old-vma-files.patch extra/0001-Revert-target-i386-disable-LINT0-after-reset.patch extra/0002-qemu-img-wait-for-convert-coroutines-to-complete.patch extra/0003-block-Do-not-unref-bs-file-on-error-in-BD-s-open.patch