]> git.proxmox.com Git - pve-qemu-kvm.git/commitdiff
update to 2.7
authorWolfgang Bumiller <w.bumiller@proxmox.com>
Fri, 9 Sep 2016 13:53:07 +0000 (15:53 +0200)
committerWolfgang Bumiller <w.bumiller@proxmox.com>
Mon, 10 Oct 2016 13:05:47 +0000 (15:05 +0200)
108 files changed:
Makefile
debian/changelog
debian/patches/extra/0001-Revert-target-i386-disable-LINT0-after-reset.patch
debian/patches/extra/0002-net-vmxnet-initialise-local-tx-descriptor.patch [new file with mode: 0644]
debian/patches/extra/0002-net-vmxnet3-check-for-device_active-before-write.patch [deleted file]
debian/patches/extra/0002-scsi-esp-fix-migration.patch [deleted file]
debian/patches/extra/0003-net-limit-allocation-in-nc_sendv_compat.patch [new file with mode: 0644]
debian/patches/extra/0005-net-vmxnet-initialise-local-tx-descriptor.patch [deleted file]
debian/patches/extra/0009-net-limit-allocation-in-nc_sendv_compat.patch [deleted file]
debian/patches/extra/CVE-2016-6490-virtio-check-vring-descriptor-buffer-length.patch [deleted file]
debian/patches/extra/CVE-2016-7155-scsi-check-page-count-while-initialising-descriptor-.patch [new file with mode: 0644]
debian/patches/extra/CVE-2016-7157-scsi-mptconfig-fix-an-assert-expression.patch [new file with mode: 0644]
debian/patches/extra/CVE-2016-7421-scsi-pvscsi-limit-process-IO-loop-to-ring-size.patch [new file with mode: 0644]
debian/patches/extra/CVE-2016-7422-virtio-add-check-for-descriptor-s-mapped-address.patch
debian/patches/extra/CVE-2016-7423-scsi-mptsas-use-g_new0-to-allocate-MPTSASRequest-obj.patch [new file with mode: 0644]
debian/patches/extra/CVE-2016-7907-net-imx-limit-buffer-descriptor-count.patch
debian/patches/extra/CVE-2016-7908-net-mcf-limit-buffer-descriptor-count.patch
debian/patches/extra/CVE-2016-7909-net-pcnet-check-rx-tx-descriptor-ring-length.patch
debian/patches/extra/CVE-2016-7994-virtio-gpu-fix-memory-leak-in-virtio_gpu_resource_cr.patch [new file with mode: 0644]
debian/patches/extra/CVE-2016-7995-usb-ehci-fix-memory-leak-in-ehci_process_itd.patch [new file with mode: 0644]
debian/patches/pve/0001-fr-ca-keymap-corrections.patch
debian/patches/pve/0002-Adjust-network-script-path-to-etc-kvm.patch
debian/patches/pve/0003-vnc-altgr-emulation.patch
debian/patches/pve/0004-qemu-img-return-success-on-info-without-snapshots.patch
debian/patches/pve/0005-use-kvm-by-default.patch
debian/patches/pve/0006-virtio-balloon-fix-query.patch
debian/patches/pve/0007-set-the-CPU-model-to-kvm64-32-instead-of-qemu64-32.patch
debian/patches/pve/0008-qapi-modify-query-machines.patch
debian/patches/pve/0009-qapi-modify-spice-query.patch
debian/patches/pve/0010-ui-spice-default-to-pve-certs-unless-otherwise-speci.patch
debian/patches/pve/0011-introduce-new-vma-archive-format.patch
debian/patches/pve/0012-vma-add-verify-command.patch
debian/patches/pve/0013-vma-add-config-command-to-dump-the-config.patch
debian/patches/pve/0014-backup-modify-job-api.patch [new file with mode: 0644]
debian/patches/pve/0014-vma-restore-tolerate-a-size-difference-up-to-4M.patch [deleted file]
debian/patches/pve/0015-backup-add-pve-monitor-commands.patch [new file with mode: 0644]
debian/patches/pve/0015-backup-modify-job-api.patch [deleted file]
debian/patches/pve/0016-backup-add-pve-monitor-commands.patch [deleted file]
debian/patches/pve/0016-backup-vma-add-dir-format.patch [new file with mode: 0644]
debian/patches/pve/0017-backup-do-not-return-errors-in-dump-callback.patch [new file with mode: 0644]
debian/patches/pve/0017-backup-vma-add-dir-format.patch [deleted file]
debian/patches/pve/0018-backup-do-not-return-errors-in-dump-callback.patch [deleted file]
debian/patches/pve/0018-backup-vma-correctly-propagate-error.patch [new file with mode: 0644]
debian/patches/pve/0019-backup-vma-correctly-propagate-error.patch [deleted file]
debian/patches/pve/0019-backup-vma-remove-async-queue.patch [new file with mode: 0644]
debian/patches/pve/0020-backup-vma-remove-async-queue.patch [deleted file]
debian/patches/pve/0020-backup-vma-run-flush-inside-coroutine.patch [new file with mode: 0644]
debian/patches/pve/0021-backup-do-not-use-bdrv_drain_all.patch [new file with mode: 0644]
debian/patches/pve/0021-backup-vma-run-flush-inside-coroutine.patch [deleted file]
debian/patches/pve/0022-backup-do-not-use-bdrv_drain_all.patch [deleted file]
debian/patches/pve/0022-internal-snapshot-async.patch [new file with mode: 0644]
debian/patches/pve/0023-backup-vma-allow-empty-backups.patch [new file with mode: 0644]
debian/patches/pve/0023-internal-snapshot-async.patch [deleted file]
debian/patches/pve/0024-backup-vma-allow-empty-backups.patch [deleted file]
debian/patches/pve/0024-qmp-add-get_link_status.patch [new file with mode: 0644]
debian/patches/pve/0025-backup-vma-add-BlockDriver-to-bdrv_open-in-extract_c.patch [deleted file]
debian/patches/pve/0025-smm_available-false.patch [new file with mode: 0644]
debian/patches/pve/0026-glusterfs-daemonize.patch [deleted file]
debian/patches/pve/0026-use-whitespace-between-VERSION-and-PKGVERSION.patch [new file with mode: 0644]
debian/patches/pve/0027-gluster-possiblity-to-specify-a-secondary-server.patch [deleted file]
debian/patches/pve/0027-vma-add-firewall.patch [new file with mode: 0644]
debian/patches/pve/0028-qmp-add-get_link_status.patch [deleted file]
debian/patches/pve/0028-savevm-async-migration-and-bdrv_open-update.patch [new file with mode: 0644]
debian/patches/pve/0029-smm_available-false.patch [deleted file]
debian/patches/pve/0029-vnc-make-x509-imply-tls-again.patch [new file with mode: 0644]
debian/patches/pve/0030-PVE-VNC-authentication.patch [new file with mode: 0644]
debian/patches/pve/0030-use-whitespace-between-VERSION-and-PKGVERSION.patch [deleted file]
debian/patches/pve/0031-vma-add-firewall.patch [deleted file]
debian/patches/pve/0031-vma-writer-don-t-bail-out-on-zero-length-files.patch [new file with mode: 0644]
debian/patches/pve/0032-vma-better-driver-guessing-for-bdrv_open.patch [new file with mode: 0644]
debian/patches/pve/0032-vma-writer-aio_set_fd_handler-update.patch [deleted file]
debian/patches/pve/0033-block-add-the-zeroinit-block-driver-filter.patch [new file with mode: 0644]
debian/patches/pve/0033-vma-bdrv_open-dropped-the-drv-parameter.patch [deleted file]
debian/patches/pve/0034-blockdev-bdrv_open-dropped-the-drv-parameter.patch [deleted file]
debian/patches/pve/0034-vma-add-format-option-to-device-mapping.patch [new file with mode: 0644]
debian/patches/pve/0035-blockdev-backup_start-now-takes-a-BlockJobTxn.patch [deleted file]
debian/patches/pve/0035-fix-possible-unitialised-return-value.patch [new file with mode: 0644]
debian/patches/pve/0036-savevm-async-migration-and-bdrv_open-update.patch [deleted file]
debian/patches/pve/0036-vnc-refactor-to-QIOChannelSocket.patch [new file with mode: 0644]
debian/patches/pve/0037-qapi-qmp_marshal_-renames-for-pve-monitor-commands.patch [deleted file]
debian/patches/pve/0037-vma-use-BlockBackend-on-extract.patch [new file with mode: 0644]
debian/patches/pve/0038-qapi-qmp_mashal_-renames-for-async-snapshot.patch [deleted file]
debian/patches/pve/0038-vma-byte-based-write-calls.patch [new file with mode: 0644]
debian/patches/pve/0039-qapi-qmp_mashal_-renames-for-get_link_status.patch [deleted file]
debian/patches/pve/0039-rbd-disable-rbd_cache_writethrough_until_flush-with-.patch [new file with mode: 0644]
debian/patches/pve/0040-enable-cache-unsafe-for-vma-extract_content-and-qmp_.patch [new file with mode: 0644]
debian/patches/pve/0040-vnc-make-x509-imply-tls-again.patch [deleted file]
debian/patches/pve/0041-PVE-VNC-authentication.patch [deleted file]
debian/patches/pve/0041-savevm-async-updates.patch [new file with mode: 0644]
debian/patches/pve/0042-qmp_snapshot_drive-add-aiocontext.patch [new file with mode: 0644]
debian/patches/pve/0042-vma-writer-don-t-bail-out-on-zero-length-files.patch [deleted file]
debian/patches/pve/0043-vma-better-driver-guessing-for-bdrv_open.patch [deleted file]
debian/patches/pve/0044-block-add-the-zeroinit-block-driver-filter.patch [deleted file]
debian/patches/pve/0045-vma-add-format-option-to-device-mapping.patch [deleted file]
debian/patches/pve/0046-pve-cleanup-includes-all-over-the-place.patch [deleted file]
debian/patches/pve/0047-zeroinit-bdrv_get_block_status-got-a-new-param.patch [deleted file]
debian/patches/pve/0048-BDRV_O_CACHE_WB-was-removed.patch [deleted file]
debian/patches/pve/0049-backup-bdrv_set_enable_write_cache-is-no-more.patch [deleted file]
debian/patches/pve/0050-fix-possible-unitialised-return-value.patch [deleted file]
debian/patches/pve/0051-net-NET_CLIENT_OPTIONS_KIND_MAX-changed.patch [deleted file]
debian/patches/pve/0052-vnc-refactor-to-QIOChannelSocket.patch [deleted file]
debian/patches/pve/0053-vma-use-BlockBackend-on-extract.patch [deleted file]
debian/patches/pve/0054-rbd-disable-rbd_cache_writethrough_until_flush-with-.patch [deleted file]
debian/patches/pve/0055-enable-cache-unsafe-for-vma-extract_content-and-qmp_.patch [deleted file]
debian/patches/pve/0056-qmp_snapshot_drive-add-aiocontext.patch [deleted file]
debian/patches/series
debian/rules
qemu-kvm-src.tar.gz

index cd6d26277ba1a5d3a2502539b4c0ece90f21b63b..750580a3a414fcdd0cdad385b2e5cdffb1e0c844 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,8 @@
 RELEASE=4.2
 
 # also update debian/changelog
-KVMVER=2.6.2
-KVMPKGREL=2
+KVMVER=2.7.0
+KVMPKGREL=1
 
 KVMPACKAGE=pve-qemu-kvm
 KVMDIR=qemu-kvm
index 70ac5d59da85363f5b6f651e898535920a2da1ce..2a2124131a5016a558d0aa1a45d6a452ac882da3 100644 (file)
@@ -1,3 +1,9 @@
+pve-qemu-kvm (2.7.0-1) unstable; urgency=medium
+
+  * update to qemu 2.7.0
+
+ -- Proxmox Support Team <support@proxmox.com>  Fri, 09 Sep 2016 15:55:35 +0200
+
 pve-qemu-kvm (2.6.2-2) unstable; urgency=medium
 
   * fix CVE-2016-7466: memory leak in usb_xhci_exit
index 5c0533f310a8fd87c703a024761613ccacfbf710..fdf5b7b66ad19a6dd8a19e45b1daae9d364f759f 100644 (file)
@@ -1,19 +1,18 @@
-From 3f89d6f1f3ba9b316e3f17c78c8c6f06a8f9c974 Mon Sep 17 00:00:00 2001
+From 603c472d61c354c30bc898b0e9ff1914302cbca9 Mon Sep 17 00:00:00 2001
 From: Wolfgang Bumiller <w.bumiller@proxmox.com>
 Date: Mon, 4 Jul 2016 15:02:26 +0200
-Subject: [PATCH] Revert "target-i386: disable LINT0 after reset"
+Subject: [PATCH 1/3] Revert "target-i386: disable LINT0 after reset"
 
 This reverts commit b8eb5512fd8a115f164edbbe897cdf8884920ccb.
 ---
-see https://bugs.launchpad.net/qemu/+bug/1488363?comments=all
  hw/intc/apic_common.c | 9 +++++++++
  1 file changed, 9 insertions(+)
 
 diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c
-index ad959c4..0264a88 100644
+index 14ac43c..1ed0511 100644
 --- a/hw/intc/apic_common.c
 +++ b/hw/intc/apic_common.c
-@@ -242,6 +242,15 @@ static void apic_reset_common(DeviceState *dev)
+@@ -246,6 +246,15 @@ static void apic_reset_common(DeviceState *dev)
      info->vapic_base_update(s);
  
      apic_init_reset(dev);
diff --git a/debian/patches/extra/0002-net-vmxnet-initialise-local-tx-descriptor.patch b/debian/patches/extra/0002-net-vmxnet-initialise-local-tx-descriptor.patch
new file mode 100644 (file)
index 0000000..5090662
--- /dev/null
@@ -0,0 +1,31 @@
+From 1313d27fc347633d0cf6fc2ff8cbe17a740dd658 Mon Sep 17 00:00:00 2001
+From: Li Qiang <liqiang6-s@360.cn>
+Date: Thu, 11 Aug 2016 00:42:20 +0530
+Subject: [PATCH 2/3] net: vmxnet: initialise local tx descriptor
+
+In Vmxnet3 device emulator while processing transmit(tx) queue,
+when it reaches end of packet, it calls vmxnet3_complete_packet.
+In that local 'txcq_descr' object is not initialised, which could
+leak host memory bytes a guest.
+
+Reported-by: Li Qiang <liqiang6-s@360.cn>
+Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
+---
+ hw/net/vmxnet3.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c
+index 90f6943..92f6af9 100644
+--- a/hw/net/vmxnet3.c
++++ b/hw/net/vmxnet3.c
+@@ -531,6 +531,7 @@ static void vmxnet3_complete_packet(VMXNET3State *s, int qidx, uint32_t tx_ridx)
+     VMXNET3_RING_DUMP(VMW_RIPRN, "TXC", qidx, &s->txq_descr[qidx].comp_ring);
++    memset(&txcq_descr, 0, sizeof(txcq_descr));
+     txcq_descr.txdIdx = tx_ridx;
+     txcq_descr.gen = vmxnet3_ring_curr_gen(&s->txq_descr[qidx].comp_ring);
+-- 
+2.1.4
+
diff --git a/debian/patches/extra/0002-net-vmxnet3-check-for-device_active-before-write.patch b/debian/patches/extra/0002-net-vmxnet3-check-for-device_active-before-write.patch
deleted file mode 100644 (file)
index 7b1060d..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-From 89636d45af75c102a7b893d8cc34a51be76e88b5 Mon Sep 17 00:00:00 2001
-From: Li Qiang <liqiang6-s@360.cn>
-Date: Mon, 8 Aug 2016 18:08:31 +0530
-Subject: [PATCH 2/5] net: vmxnet3: check for device_active before write
-
-Vmxnet3 device emulator does not check if the device is active,
-before using it for write. It leads to a use after free issue,
-if the vmxnet3_io_bar0_write routine is called after the device is
-deactivated. Add check to avoid it.
-
-Reported-by: Li Qiang <liqiang6-s@360.cn>
-Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
-Acked-by: Dmitry Fleytman <dmitry@daynix.com>
-Signed-off-by: Jason Wang <jasowang@redhat.com>
----
- hw/net/vmxnet3.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
-diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c
-index 20f26b7..a6ce16e 100644
---- a/hw/net/vmxnet3.c
-+++ b/hw/net/vmxnet3.c
-@@ -1158,6 +1158,10 @@ vmxnet3_io_bar0_write(void *opaque, hwaddr addr,
- {
-     VMXNET3State *s = opaque;
-+    if (!s->device_active) {
-+        return;
-+    }
-+
-     if (VMW_IS_MULTIREG_ADDR(addr, VMXNET3_REG_TXPROD,
-                         VMXNET3_DEVICE_MAX_TX_QUEUES, VMXNET3_REG_ALIGN)) {
-         int tx_queue_idx =
--- 
-2.1.4
-
diff --git a/debian/patches/extra/0002-scsi-esp-fix-migration.patch b/debian/patches/extra/0002-scsi-esp-fix-migration.patch
deleted file mode 100644 (file)
index 0ddaed0..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-From 10cf6bf50d000a1b0dad1d5f2b931d1d1b1ff7f3 Mon Sep 17 00:00:00 2001
-From: Paolo Bonzini <pbonzini@redhat.com>
-Date: Mon, 20 Jun 2016 16:32:39 +0200
-Subject: [PATCH 2/2] scsi: esp: fix migration
-
-Commit 926cde5 ("scsi: esp: make cmdbuf big enough for maximum CDB size",
-2016-06-16) changed the size of a migrated field.  Split it in two
-parts, and only migrate the second part in a new vmstate version.
-
-Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
----
- hw/scsi/esp.c               | 5 +++--
- include/migration/vmstate.h | 5 ++++-
- 2 files changed, 7 insertions(+), 3 deletions(-)
-
-diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
-index e533522..8cff94b 100644
---- a/hw/scsi/esp.c
-+++ b/hw/scsi/esp.c
-@@ -573,7 +573,7 @@ static bool esp_mem_accepts(void *opaque, hwaddr addr,
- const VMStateDescription vmstate_esp = {
-     .name ="esp",
--    .version_id = 3,
-+    .version_id = 4,
-     .minimum_version_id = 3,
-     .fields = (VMStateField[]) {
-         VMSTATE_BUFFER(rregs, ESPState),
-@@ -584,7 +584,8 @@ const VMStateDescription vmstate_esp = {
-         VMSTATE_BUFFER(ti_buf, ESPState),
-         VMSTATE_UINT32(status, ESPState),
-         VMSTATE_UINT32(dma, ESPState),
--        VMSTATE_BUFFER(cmdbuf, ESPState),
-+        VMSTATE_PARTIAL_BUFFER(cmdbuf, ESPState, 16),
-+        VMSTATE_BUFFER_START_MIDDLE_V(cmdbuf, ESPState, 16, 4),
-         VMSTATE_UINT32(cmdlen, ESPState),
-         VMSTATE_UINT32(do_cmd, ESPState),
-         VMSTATE_UINT32(dma_left, ESPState),
-diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
-index 84ee355..853a2bd 100644
---- a/include/migration/vmstate.h
-+++ b/include/migration/vmstate.h
-@@ -888,8 +888,11 @@ extern const VMStateInfo vmstate_info_bitmap;
- #define VMSTATE_PARTIAL_BUFFER(_f, _s, _size)                         \
-     VMSTATE_STATIC_BUFFER(_f, _s, 0, NULL, 0, _size)
-+#define VMSTATE_BUFFER_START_MIDDLE_V(_f, _s, _start, _v) \
-+    VMSTATE_STATIC_BUFFER(_f, _s, _v, NULL, _start, sizeof(typeof_field(_s, _f)))
-+
- #define VMSTATE_BUFFER_START_MIDDLE(_f, _s, _start) \
--    VMSTATE_STATIC_BUFFER(_f, _s, 0, NULL, _start, sizeof(typeof_field(_s, _f)))
-+    VMSTATE_BUFFER_START_MIDDLE_V(_f, _s, _start, 0)
- #define VMSTATE_PARTIAL_VBUFFER(_f, _s, _size)                        \
-     VMSTATE_VBUFFER(_f, _s, 0, NULL, 0, _size)
--- 
-2.1.4
-
diff --git a/debian/patches/extra/0003-net-limit-allocation-in-nc_sendv_compat.patch b/debian/patches/extra/0003-net-limit-allocation-in-nc_sendv_compat.patch
new file mode 100644 (file)
index 0000000..0bdb236
--- /dev/null
@@ -0,0 +1,37 @@
+From 2705772316ff905f3ed08871c602fca1c636f332 Mon Sep 17 00:00:00 2001
+From: Peter Lieven <pl@kamp.de>
+Date: Thu, 30 Jun 2016 11:49:40 +0200
+Subject: [PATCH 3/3] net: limit allocation in nc_sendv_compat
+
+we only need to allocate enough memory to hold the packet. This might be
+less than NET_BUFSIZE. Additionally fail early if the packet is larger
+than NET_BUFSIZE.
+
+Signed-off-by: Peter Lieven <pl@kamp.de>
+---
+ net/net.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/net/net.c b/net/net.c
+index c94d93d..2ac46a6 100644
+--- a/net/net.c
++++ b/net/net.c
+@@ -690,9 +690,13 @@ static ssize_t nc_sendv_compat(NetClientState *nc, const struct iovec *iov,
+         buffer = iov[0].iov_base;
+         offset = iov[0].iov_len;
+     } else {
+-        buf = g_new(uint8_t, NET_BUFSIZE);
++        offset = iov_size(iov, iovcnt);
++        if (offset > NET_BUFSIZE) {
++            return -1;
++        }
++        buf = g_malloc(offset);
+         buffer = buf;
+-        offset = iov_to_buf(iov, iovcnt, 0, buf, NET_BUFSIZE);
++        offset = iov_to_buf(iov, iovcnt, 0, buf, offset);
+     }
+     if (flags & QEMU_NET_PACKET_FLAG_RAW && nc->info->receive_raw) {
+-- 
+2.1.4
+
diff --git a/debian/patches/extra/0005-net-vmxnet-initialise-local-tx-descriptor.patch b/debian/patches/extra/0005-net-vmxnet-initialise-local-tx-descriptor.patch
deleted file mode 100644 (file)
index 7459d26..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-From 4fa993ee1f127eee2862f1779565aea0b760647a Mon Sep 17 00:00:00 2001
-From: Li Qiang <liqiang6-s@360.cn>
-Date: Thu, 11 Aug 2016 00:42:20 +0530
-Subject: [PATCH 5/5] net: vmxnet: initialise local tx descriptor
-
-In Vmxnet3 device emulator while processing transmit(tx) queue,
-when it reaches end of packet, it calls vmxnet3_complete_packet.
-In that local 'txcq_descr' object is not initialised, which could
-leak host memory bytes a guest.
-
-Reported-by: Li Qiang <liqiang6-s@360.cn>
-Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
----
- hw/net/vmxnet3.c | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c
-index a6ce16e..360290d 100644
---- a/hw/net/vmxnet3.c
-+++ b/hw/net/vmxnet3.c
-@@ -529,6 +529,7 @@ static void vmxnet3_complete_packet(VMXNET3State *s, int qidx, uint32_t tx_ridx)
-     VMXNET3_RING_DUMP(VMW_RIPRN, "TXC", qidx, &s->txq_descr[qidx].comp_ring);
-+    memset(&txcq_descr, 0, sizeof(txcq_descr));
-     txcq_descr.txdIdx = tx_ridx;
-     txcq_descr.gen = vmxnet3_ring_curr_gen(&s->txq_descr[qidx].comp_ring);
--- 
-2.1.4
-
diff --git a/debian/patches/extra/0009-net-limit-allocation-in-nc_sendv_compat.patch b/debian/patches/extra/0009-net-limit-allocation-in-nc_sendv_compat.patch
deleted file mode 100644 (file)
index 881e34a..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-From 1419429813905c95e2648516a8a23ad43e2c7297 Mon Sep 17 00:00:00 2001
-From: Peter Lieven <pl@kamp.de>
-Date: Thu, 30 Jun 2016 11:49:40 +0200
-Subject: [PATCH 09/10] net: limit allocation in nc_sendv_compat
-
-we only need to allocate enough memory to hold the packet. This might be
-less than NET_BUFSIZE. Additionally fail early if the packet is larger
-than NET_BUFSIZE.
-
-Signed-off-by: Peter Lieven <pl@kamp.de>
----
- net/net.c | 8 ++++++--
- 1 file changed, 6 insertions(+), 2 deletions(-)
-
-diff --git a/net/net.c b/net/net.c
-index 2b9de86..af36a2a 100644
---- a/net/net.c
-+++ b/net/net.c
-@@ -692,9 +692,13 @@ static ssize_t nc_sendv_compat(NetClientState *nc, const struct iovec *iov,
-         buffer = iov[0].iov_base;
-         offset = iov[0].iov_len;
-     } else {
--        buf = g_new(uint8_t, NET_BUFSIZE);
-+        offset = iov_size(iov, iovcnt);
-+        if (offset > NET_BUFSIZE) {
-+            return -1;
-+        }
-+        buf = g_malloc(offset);
-         buffer = buf;
--        offset = iov_to_buf(iov, iovcnt, 0, buf, NET_BUFSIZE);
-+        offset = iov_to_buf(iov, iovcnt, 0, buf, offset);
-     }
-     if (flags & QEMU_NET_PACKET_FLAG_RAW && nc->info->receive_raw) {
--- 
-2.1.4
-
diff --git a/debian/patches/extra/CVE-2016-6490-virtio-check-vring-descriptor-buffer-length.patch b/debian/patches/extra/CVE-2016-6490-virtio-check-vring-descriptor-buffer-length.patch
deleted file mode 100644 (file)
index d776e54..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-From 3f8bf5846151f173361966cb4869ab5a1306ad37 Mon Sep 17 00:00:00 2001
-From: Prasad J Pandit <pjp@fedoraproject.org>
-Date: Wed, 27 Jul 2016 21:07:56 +0530
-Subject: [PATCH] virtio: check vring descriptor buffer length
-
-virtio back end uses set of buffers to facilitate I/O operations.
-An infinite loop unfolds in virtqueue_pop() if a buffer was
-of zero size. Add check to avoid it.
-
-Reported-by: Li Qiang <liqiang6-s@360.cn>
-Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
-Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
-Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
-Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
----
- hw/virtio/virtio.c | 5 +++++
- 1 file changed, 5 insertions(+)
-
-diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
-index 30ede3d..8de896c 100644
---- a/hw/virtio/virtio.c
-+++ b/hw/virtio/virtio.c
-@@ -457,6 +457,11 @@ static void virtqueue_map_desc(unsigned int *p_num_sg, hwaddr *addr, struct iove
-     unsigned num_sg = *p_num_sg;
-     assert(num_sg <= max_num_sg);
-+    if (!sz) {
-+        error_report("virtio: zero sized buffers are not allowed");
-+        exit(1);
-+    }
-+
-     while (sz) {
-         hwaddr len = sz;
--- 
-2.1.4
-
diff --git a/debian/patches/extra/CVE-2016-7155-scsi-check-page-count-while-initialising-descriptor-.patch b/debian/patches/extra/CVE-2016-7155-scsi-check-page-count-while-initialising-descriptor-.patch
new file mode 100644 (file)
index 0000000..54df061
--- /dev/null
@@ -0,0 +1,83 @@
+From 7c7e45d2bd1a77fbe89dff83fabf89a46479111f Mon Sep 17 00:00:00 2001
+From: Prasad J Pandit <pjp@fedoraproject.org>
+Date: Thu, 1 Sep 2016 16:30:51 +0530
+Subject: [PATCH 4/6] scsi: check page count while initialising descriptor
+ rings
+
+Vmware Paravirtual SCSI emulation uses command descriptors to
+process SCSI commands. These descriptors come with their ring
+buffers. A guest could set the page count for these rings to
+an arbitrary value, leading to infinite loop or OOB access.
+Add check to avoid it.
+
+Reported-by: Tom Victor <vv474172261@gmail.com>
+Reported-by: Li Qiang <liqiang6-s@360.cn>
+Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
+---
+ hw/scsi/vmw_pvscsi.c | 19 +++++++++----------
+ 1 file changed, 9 insertions(+), 10 deletions(-)
+
+diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c
+index 2d7528d..22f872c 100644
+--- a/hw/scsi/vmw_pvscsi.c
++++ b/hw/scsi/vmw_pvscsi.c
+@@ -153,7 +153,7 @@ pvscsi_log2(uint32_t input)
+     return log;
+ }
+-static int
++static void
+ pvscsi_ring_init_data(PVSCSIRingInfo *m, PVSCSICmdDescSetupRings *ri)
+ {
+     int i;
+@@ -161,10 +161,6 @@ pvscsi_ring_init_data(PVSCSIRingInfo *m, PVSCSICmdDescSetupRings *ri)
+     uint32_t req_ring_size, cmp_ring_size;
+     m->rs_pa = ri->ringsStatePPN << VMW_PAGE_SHIFT;
+-    if ((ri->reqRingNumPages > PVSCSI_SETUP_RINGS_MAX_NUM_PAGES)
+-        || (ri->cmpRingNumPages > PVSCSI_SETUP_RINGS_MAX_NUM_PAGES)) {
+-        return -1;
+-    }
+     req_ring_size = ri->reqRingNumPages * PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE;
+     cmp_ring_size = ri->cmpRingNumPages * PVSCSI_MAX_NUM_CMP_ENTRIES_PER_PAGE;
+     txr_len_log2 = pvscsi_log2(req_ring_size - 1);
+@@ -196,8 +192,6 @@ pvscsi_ring_init_data(PVSCSIRingInfo *m, PVSCSICmdDescSetupRings *ri)
+     /* Flush ring state page changes */
+     smp_wmb();
+-
+-    return 0;
+ }
+ static int
+@@ -747,7 +741,7 @@ pvscsi_dbg_dump_tx_rings_config(PVSCSICmdDescSetupRings *rc)
+     trace_pvscsi_tx_rings_num_pages("Confirm Ring", rc->cmpRingNumPages);
+     for (i = 0; i < rc->cmpRingNumPages; i++) {
+-        trace_pvscsi_tx_rings_ppn("Confirm Ring", rc->reqRingPPNs[i]);
++        trace_pvscsi_tx_rings_ppn("Confirm Ring", rc->cmpRingPPNs[i]);
+     }
+ }
+@@ -780,11 +774,16 @@ pvscsi_on_cmd_setup_rings(PVSCSIState *s)
+     trace_pvscsi_on_cmd_arrived("PVSCSI_CMD_SETUP_RINGS");
+-    pvscsi_dbg_dump_tx_rings_config(rc);
+-    if (pvscsi_ring_init_data(&s->rings, rc) < 0) {
++    if (!rc->reqRingNumPages
++        || rc->reqRingNumPages > PVSCSI_SETUP_RINGS_MAX_NUM_PAGES
++        || !rc->cmpRingNumPages
++        || rc->cmpRingNumPages > PVSCSI_SETUP_RINGS_MAX_NUM_PAGES) {
+         return PVSCSI_COMMAND_PROCESSING_FAILED;
+     }
++    pvscsi_dbg_dump_tx_rings_config(rc);
++    pvscsi_ring_init_data(&s->rings, rc);
++
+     s->rings_info_valid = TRUE;
+     return PVSCSI_COMMAND_PROCESSING_SUCCEEDED;
+ }
+-- 
+2.1.4
+
diff --git a/debian/patches/extra/CVE-2016-7157-scsi-mptconfig-fix-an-assert-expression.patch b/debian/patches/extra/CVE-2016-7157-scsi-mptconfig-fix-an-assert-expression.patch
new file mode 100644 (file)
index 0000000..f74c99b
--- /dev/null
@@ -0,0 +1,35 @@
+From a0e2a28c08472ad3468c2f75d20fe1ca02ef8c0b Mon Sep 17 00:00:00 2001
+From: Prasad J Pandit <pjp@fedoraproject.org>
+Date: Wed, 31 Aug 2016 17:36:07 +0530
+Subject: [PATCH 6/6] scsi: mptconfig: fix an assert expression
+
+When LSI SAS1068 Host Bus emulator builds configuration page
+headers, mptsas_config_pack() should assert that the size
+fits in a byte.  However, the size is expressed in 32-bit
+units, so up to 1020 bytes fit.  The assertion was only
+allowing replies up to 252 bytes, so fix it.
+
+Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
+Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
+Message-Id: <1472645167-30765-2-git-send-email-ppandit@redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+---
+ hw/scsi/mptconfig.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/hw/scsi/mptconfig.c b/hw/scsi/mptconfig.c
+index 7071854..3e4f400 100644
+--- a/hw/scsi/mptconfig.c
++++ b/hw/scsi/mptconfig.c
+@@ -158,7 +158,7 @@ static size_t mptsas_config_pack(uint8_t **data, const char *fmt, ...)
+     va_end(ap);
+     if (data) {
+-        assert(ret < 256 && (ret % 4) == 0);
++        assert(ret / 4 < 256 && (ret % 4) == 0);
+         stb_p(*data + 1, ret / 4);
+     }
+     return ret;
+-- 
+2.1.4
+
diff --git a/debian/patches/extra/CVE-2016-7421-scsi-pvscsi-limit-process-IO-loop-to-ring-size.patch b/debian/patches/extra/CVE-2016-7421-scsi-pvscsi-limit-process-IO-loop-to-ring-size.patch
new file mode 100644 (file)
index 0000000..05ab4a5
--- /dev/null
@@ -0,0 +1,38 @@
+From d251157ac1928191af851d199a9ff255d330bec9 Mon Sep 17 00:00:00 2001
+From: Prasad J Pandit <pjp@fedoraproject.org>
+Date: Wed, 14 Sep 2016 15:09:12 +0530
+Subject: [PATCH] scsi: pvscsi: limit process IO loop to ring size
+
+Vmware Paravirtual SCSI emulator while processing IO requests
+could run into an infinite loop if 'pvscsi_ring_pop_req_descr'
+always returned positive value. Limit IO loop to the ring size.
+
+Cc: qemu-stable@nongnu.org
+Reported-by: Li Qiang <liqiang6-s@360.cn>
+Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
+Message-Id: <1473845952-30785-1-git-send-email-ppandit@redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+---
+ hw/scsi/vmw_pvscsi.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c
+index babac5a..a5ce7de 100644
+--- a/hw/scsi/vmw_pvscsi.c
++++ b/hw/scsi/vmw_pvscsi.c
+@@ -247,8 +247,11 @@ static hwaddr
+ pvscsi_ring_pop_req_descr(PVSCSIRingInfo *mgr)
+ {
+     uint32_t ready_ptr = RS_GET_FIELD(mgr, reqProdIdx);
++    uint32_t ring_size = PVSCSI_MAX_NUM_PAGES_REQ_RING
++                            * PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE;
+-    if (ready_ptr != mgr->consumed_ptr) {
++    if (ready_ptr != mgr->consumed_ptr
++        && ready_ptr - mgr->consumed_ptr < ring_size) {
+         uint32_t next_ready_ptr =
+             mgr->consumed_ptr++ & mgr->txr_len_mask;
+         uint32_t next_ready_page =
+-- 
+2.1.4
+
index 47e5135ddd3cba217a66cabd2420ee1f49fb146d..6ee65d14c9d69098f5879e66a659e4bc08c8f6ba 100644 (file)
@@ -1,7 +1,7 @@
-From 77b365c29e9bf143ee4c024daa9f6f0a13213376 Mon Sep 17 00:00:00 2001
+From 1723b5e7962eb077353bab0772ca8114774b6c60 Mon Sep 17 00:00:00 2001
 From: Prasad J Pandit <pjp@fedoraproject.org>
 Date: Mon, 19 Sep 2016 23:55:45 +0530
-Subject: [PATCH 1/5] virtio: add check for descriptor's mapped address
+Subject: [PATCH 4/7] virtio: add check for descriptor's mapped address
 
 virtio back end uses set of buffers to facilitate I/O operations.
 If its size is too large, 'cpu_physical_memory_map' could return
@@ -18,10 +18,10 @@ Reviewed-by: Laszlo Ersek <lersek@redhat.com>
  1 file changed, 5 insertions(+)
 
 diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
-index 111ad8e..75f5ada 100644
+index 74c085c..eabe573 100644
 --- a/hw/virtio/virtio.c
 +++ b/hw/virtio/virtio.c
-@@ -471,6 +471,11 @@ static void virtqueue_map_desc(unsigned int *p_num_sg, hwaddr *addr, struct iove
+@@ -473,6 +473,11 @@ static void virtqueue_map_desc(unsigned int *p_num_sg, hwaddr *addr, struct iove
          }
  
          iov[num_sg].iov_base = cpu_physical_memory_map(pa, &len, is_write);
diff --git a/debian/patches/extra/CVE-2016-7423-scsi-mptsas-use-g_new0-to-allocate-MPTSASRequest-obj.patch b/debian/patches/extra/CVE-2016-7423-scsi-mptsas-use-g_new0-to-allocate-MPTSASRequest-obj.patch
new file mode 100644 (file)
index 0000000..f1ba947
--- /dev/null
@@ -0,0 +1,35 @@
+From 670e56d3ed2918b3861d9216f2c0540d9e9ae0d5 Mon Sep 17 00:00:00 2001
+From: Li Qiang <liqiang6-s@360.cn>
+Date: Mon, 12 Sep 2016 18:14:11 +0530
+Subject: [PATCH] scsi: mptsas: use g_new0 to allocate MPTSASRequest object
+
+When processing IO request in mptsas, it uses g_new to allocate
+a 'req' object. If an error occurs before 'req->sreq' is
+allocated, It could lead to an OOB write in mptsas_free_request
+function. Use g_new0 to avoid it.
+
+Reported-by: Li Qiang <liqiang6-s@360.cn>
+Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
+Message-Id: <1473684251-17476-1-git-send-email-ppandit@redhat.com>
+Cc: qemu-stable@nongnu.org
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+---
+ hw/scsi/mptsas.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/hw/scsi/mptsas.c b/hw/scsi/mptsas.c
+index 0e0a22f..eaae1bb 100644
+--- a/hw/scsi/mptsas.c
++++ b/hw/scsi/mptsas.c
+@@ -304,7 +304,7 @@ static int mptsas_process_scsi_io_request(MPTSASState *s,
+         goto bad;
+     }
+-    req = g_new(MPTSASRequest, 1);
++    req = g_new0(MPTSASRequest, 1);
+     QTAILQ_INSERT_TAIL(&s->pending, req, next);
+     req->scsi_io = *scsi_io;
+     req->dev = s;
+-- 
+2.1.4
+
index 303a481bbb5698cf5d11020ea22a8de9e59305dc..108219cd123b62bdb84099e064d90c684fc29afc 100644 (file)
@@ -1,7 +1,7 @@
-From 53102ff7c9c928e2c778a6440f7039ee29dc5acf Mon Sep 17 00:00:00 2001
+From 3798522afcf58abbce6de67446fcae7a34ae919d Mon Sep 17 00:00:00 2001
 From: Prasad J Pandit <pjp@fedoraproject.org>
 Date: Thu, 22 Sep 2016 16:01:38 +0530
-Subject: [PATCH 3/5] net: imx: limit buffer descriptor count
+Subject: [PATCH 5/7] net: imx: limit buffer descriptor count
 
 i.MX Fast Ethernet Controller uses buffer descriptors to manage
 data flow to/fro receive & transmit queues. While transmitting
@@ -16,25 +16,25 @@ Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
  1 file changed, 4 insertions(+), 2 deletions(-)
 
 diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c
-index e60e338..547fa99 100644
+index 1c415ab..1d74827 100644
 --- a/hw/net/imx_fec.c
 +++ b/hw/net/imx_fec.c
-@@ -94,6 +94,8 @@ static const VMStateDescription vmstate_imx_fec = {
+@@ -220,6 +220,8 @@ static const VMStateDescription vmstate_imx_eth = {
  #define PHY_INT_PARFAULT            (1 << 2)
  #define PHY_INT_AUTONEG_PAGE        (1 << 1)
  
 +#define IMX_MAX_DESC                1024
 +
- static void imx_fec_update(IMXFECState *s);
+ static void imx_eth_update(IMXFECState *s);
  
  /*
-@@ -264,12 +266,12 @@ static void imx_fec_update(IMXFECState *s)
+@@ -402,12 +404,12 @@ static void imx_eth_update(IMXFECState *s)
  
  static void imx_fec_do_tx(IMXFECState *s)
  {
 -    int frame_size = 0;
 +    int frame_size = 0, descnt = 0;
-     uint8_t frame[FEC_MAX_FRAME_SIZE];
+     uint8_t frame[ENET_MAX_FRAME_SIZE];
      uint8_t *ptr = frame;
      uint32_t addr = s->tx_descriptor;
  
index 2985778f6ddc91ada7df569b725d28a4c5daf6cb..fc15768e5934b178fb4cfe9baca9a95494ffc5ef 100644 (file)
@@ -1,7 +1,7 @@
-From 50e74d1c748bde8d667e452d4d7cac3d8f869520 Mon Sep 17 00:00:00 2001
+From 94087c0cbe014b4a60d96930d7cb43d54a05c701 Mon Sep 17 00:00:00 2001
 From: Prasad J Pandit <pjp@fedoraproject.org>
 Date: Thu, 22 Sep 2016 16:02:37 +0530
-Subject: [PATCH 4/5] net: mcf: limit buffer descriptor count
+Subject: [PATCH 6/7] net: mcf: limit buffer descriptor count
 
 ColdFire Fast Ethernet Controller uses buffer descriptors to manage
 data flow to/fro receive & transmit queues. While transmitting
@@ -18,7 +18,7 @@ Signed-off-by: Jason Wang <jasowang@redhat.com>
  1 file changed, 3 insertions(+), 2 deletions(-)
 
 diff --git a/hw/net/mcf_fec.c b/hw/net/mcf_fec.c
-index 7c0398e..6d3418e 100644
+index 0ee8ad9..d31fea1 100644
 --- a/hw/net/mcf_fec.c
 +++ b/hw/net/mcf_fec.c
 @@ -23,6 +23,7 @@ do { printf("mcf_fec: " fmt , ## __VA_ARGS__); } while (0)
index fab98babd24df36b56639c468b05319831a66b6b..c25587155288e8c03c445f48ab2da45433b33a9d 100644 (file)
@@ -1,7 +1,7 @@
-From 9d315a91caeb359045b2c730294bba3889911127 Mon Sep 17 00:00:00 2001
+From ed825b783750cbe88aa67bbe83cf662082828efa Mon Sep 17 00:00:00 2001
 From: Prasad J Pandit <pjp@fedoraproject.org>
 Date: Fri, 30 Sep 2016 00:27:33 +0530
-Subject: [PATCH 5/5] net: pcnet: check rx/tx descriptor ring length
+Subject: [PATCH 7/7] net: pcnet: check rx/tx descriptor ring length
 
 The AMD PC-Net II emulator has set of control and status(CSR)
 registers. Of these, CSR76 and CSR78 hold receive and transmit
diff --git a/debian/patches/extra/CVE-2016-7994-virtio-gpu-fix-memory-leak-in-virtio_gpu_resource_cr.patch b/debian/patches/extra/CVE-2016-7994-virtio-gpu-fix-memory-leak-in-virtio_gpu_resource_cr.patch
new file mode 100644 (file)
index 0000000..cddc70f
--- /dev/null
@@ -0,0 +1,30 @@
+From 594fa98211f92ab07ee6d6b6a9eda93a416a1f57 Mon Sep 17 00:00:00 2001
+From: Li Qiang <liqiang6-s@360.cn>
+Date: Sun, 18 Sep 2016 19:07:11 -0700
+Subject: [PATCH 1/2] virtio-gpu: fix memory leak in
+ virtio_gpu_resource_create_2d
+
+In virtio gpu resource create dispatch, if the pixman format is zero
+it doesn't free the resource object allocated previously. Thus leading
+a host memory leak issue. This patch avoid this.
+
+Signed-off-by: Li Qiang <liqiang6-s@360.cn>
+---
+ hw/display/virtio-gpu.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
+index 7fe6ed8..5b6d17b 100644
+--- a/hw/display/virtio-gpu.c
++++ b/hw/display/virtio-gpu.c
+@@ -333,6 +333,7 @@ static void virtio_gpu_resource_create_2d(VirtIOGPU *g,
+         qemu_log_mask(LOG_GUEST_ERROR,
+                       "%s: host couldn't handle guest format %d\n",
+                       __func__, c2d.format);
++        g_free(res);
+         cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
+         return;
+     }
+-- 
+2.1.4
+
diff --git a/debian/patches/extra/CVE-2016-7995-usb-ehci-fix-memory-leak-in-ehci_process_itd.patch b/debian/patches/extra/CVE-2016-7995-usb-ehci-fix-memory-leak-in-ehci_process_itd.patch
new file mode 100644 (file)
index 0000000..fc1c382
--- /dev/null
@@ -0,0 +1,32 @@
+From 91a16e6e51a4e046d59379fc83b9dfc1e860e9c7 Mon Sep 17 00:00:00 2001
+From: Li Qiang <liqiang6-s@360.cn>
+Date: Sat, 8 Oct 2016 11:58:03 +0300
+Subject: [PATCH 2/2] usb: ehci: fix memory leak in ehci_process_itd
+
+While processing isochronous transfer descriptors(iTD), if the page
+select(PG) field value is out of bands it will return. In this
+situation the ehci's sg list is not freed thus leading to a memory
+leak issue. This patch avoid this.
+
+Signed-off-by: Li Qiang <liqiang6-s@360.cn>
+Reviewed-by: Thomas Huth <thuth@redhat.com>
+Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
+---
+ hw/usb/hcd-ehci.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
+index b093db7..f4ece9a 100644
+--- a/hw/usb/hcd-ehci.c
++++ b/hw/usb/hcd-ehci.c
+@@ -1426,6 +1426,7 @@ static int ehci_process_itd(EHCIState *ehci,
+             if (off + len > 4096) {
+                 /* transfer crosses page border */
+                 if (pg == 6) {
++                    qemu_sglist_destroy(&ehci->isgl);
+                     return -1;  /* avoid page pg + 1 */
+                 }
+                 ptr2 = (itd->bufptr[pg + 1] & ITD_BUFPTR_MASK);
+-- 
+2.1.4
+
index 19aac7a042c760072bc2187aec82d1963bdf1b65..4066de81298c8c7121f821b4eb31554fb66ca4eb 100644 (file)
@@ -1,7 +1,7 @@
-From 0dc734b8304318e7a4f9a0ca756f72fc7d0f543e Mon Sep 17 00:00:00 2001
+From 9e0dc08fa276f0f758d9c5fe1e47ef96ee59b069 Mon Sep 17 00:00:00 2001
 From: Wolfgang Bumiller <w.bumiller@proxmox.com>
 Date: Wed, 9 Dec 2015 14:15:49 +0100
-Subject: [PATCH 01/55] fr-ca keymap corrections
+Subject: [PATCH 01/41] fr-ca keymap corrections
 
 ---
  pc-bios/keymaps/fr-ca | 9 +++++++++
index 485db2d330a97de6f4615747ade24a492d78a5e7..7491f06e3778a957bc1391d5c7495908c359e97e 100644 (file)
@@ -1,17 +1,17 @@
-From 896141c8e486d45be140e53b395f81866b7af776 Mon Sep 17 00:00:00 2001
+From 3f71a11efda66b9145afa0015af1d5a2bc5e5bb2 Mon Sep 17 00:00:00 2001
 From: Wolfgang Bumiller <w.bumiller@proxmox.com>
 Date: Wed, 9 Dec 2015 14:16:49 +0100
-Subject: [PATCH 02/55] Adjust network script path to /etc/kvm/
+Subject: [PATCH 02/41] Adjust network script path to /etc/kvm/
 
 ---
  include/net/net.h | 5 +++--
  1 file changed, 3 insertions(+), 2 deletions(-)
 
 diff --git a/include/net/net.h b/include/net/net.h
-index 73e4c46..4267008 100644
+index e8d9e9e..375e81d 100644
 --- a/include/net/net.h
 +++ b/include/net/net.h
-@@ -198,8 +198,9 @@ void qmp_netdev_add(QDict *qdict, QObject **ret, Error **errp);
+@@ -216,8 +216,9 @@ void qmp_netdev_add(QDict *qdict, QObject **ret, Error **errp);
  int net_hub_id_for_client(NetClientState *nc, int *id);
  NetClientState *net_hub_port_find(int hub_id);
  
index 6a48ef98550b33bf0516c7da35e7a318b61685bc..fac0fd1a69087546849466c86e7f75c1269f03dd 100644 (file)
@@ -1,17 +1,17 @@
-From 4d774ad7b71342c5e3ba2f1f5ac9d051eb835270 Mon Sep 17 00:00:00 2001
+From 4429be6a1a4ba5320f4ce61ac8f874bfc4ec196e Mon Sep 17 00:00:00 2001
 From: Wolfgang Bumiller <w.bumiller@proxmox.com>
 Date: Wed, 9 Dec 2015 14:17:38 +0100
-Subject: [PATCH 03/55] vnc: altgr emulation
+Subject: [PATCH 03/41] vnc: altgr emulation
 
 ---
- ui/vnc.c | 2+++++++++++++++++++++++-
- 1 file changed, 23 insertions(+), 1 deletion(-)
+ ui/vnc.c | 26 +++++++++++++++++++++++++-
+ 1 file changed, 25 insertions(+), 1 deletion(-)
 
 diff --git a/ui/vnc.c b/ui/vnc.c
-index 3e89dad..88a5824 100644
+index d1087c9..8d7d435 100644
 --- a/ui/vnc.c
 +++ b/ui/vnc.c
-@@ -1711,6 +1711,10 @@ static void kbd_leds(void *opaque, int ledstate)
+@@ -1729,6 +1729,10 @@ static void kbd_leds(void *opaque, int ledstate)
  
  static void do_key_event(VncState *vs, int down, int keycode, int sym)
  {
@@ -22,7 +22,7 @@ index 3e89dad..88a5824 100644
      /* QEMU console switch */
      switch(keycode) {
      case 0x2a:                          /* Left Shift */
-@@ -1791,7 +1795,24 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
+@@ -1809,8 +1813,27 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
      }
  
      if (qemu_console_is_graphic(NULL)) {
@@ -36,18 +36,21 @@ index 3e89dad..88a5824 100644
 +      if (emul_altgr) {
 +            reset_keys(vs);
 +            qemu_input_event_send_key_number(vs->vd->dcl.con, 0xb8, true);
++            qemu_input_event_send_key_delay(vs->vd->key_delay_ms);
 +      }
 +
          qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, down);
+         qemu_input_event_send_key_delay(vs->vd->key_delay_ms);
 +
 +      if (emul_altgr) {
 +             qemu_input_event_send_key_number(vs->vd->dcl.con, 0xb8, false);
++             qemu_input_event_send_key_delay(vs->vd->key_delay_ms);
 +      }
 +
      } else {
          bool numlock = vs->modifiers_state[0x45];
          bool control = (vs->modifiers_state[0x1d] ||
-@@ -1930,7 +1951,8 @@ static void key_event(VncState *vs, int down, uint32_t sym)
+@@ -1950,7 +1973,8 @@ static void key_event(VncState *vs, int down, uint32_t sym)
          lsym = lsym - 'A' + 'a';
      }
  
index 62eb5dc97b6c3b1da78c899ef1348ee5c5d48677..faa665df5a3b5abd1ad9480404014f83d020e396 100644 (file)
@@ -1,17 +1,17 @@
-From bf9ce905d69ec3ac335d69a5ac578a52a96da204 Mon Sep 17 00:00:00 2001
+From 060fc3faed82c4f1bfe7fea3bea8b7bd39f4de81 Mon Sep 17 00:00:00 2001
 From: Wolfgang Bumiller <w.bumiller@proxmox.com>
 Date: Wed, 9 Dec 2015 14:18:46 +0100
-Subject: [PATCH 04/55] qemu-img: return success on info without snapshots
+Subject: [PATCH 04/41] qemu-img: return success on info without snapshots
 
 ---
  qemu-img.c | 3 ++-
  1 file changed, 2 insertions(+), 1 deletion(-)
 
 diff --git a/qemu-img.c b/qemu-img.c
-index 46f2a6d..418e2d6 100644
+index f204d041..99be68f 100644
 --- a/qemu-img.c
 +++ b/qemu-img.c
-@@ -2361,7 +2361,8 @@ static int img_info(int argc, char **argv)
+@@ -2389,7 +2389,8 @@ static int img_info(int argc, char **argv)
  
      list = collect_image_info_list(image_opts, filename, fmt, chain);
      if (!list) {
index 5c97e2344e593e36a68ab74cc49beb7a67e81cca..71519cfe9259b24f6ff2e46d81b2b57932ef3566 100644 (file)
@@ -1,17 +1,17 @@
-From c727dd8049e617a814e6b537648e0145190084e2 Mon Sep 17 00:00:00 2001
+From ebe8b0bb12b1725e9a56e5e65fe5b295d5ac90aa Mon Sep 17 00:00:00 2001
 From: Wolfgang Bumiller <w.bumiller@proxmox.com>
 Date: Wed, 9 Dec 2015 14:27:05 +0100
-Subject: [PATCH 05/55] use kvm by default
+Subject: [PATCH 05/41] use kvm by default
 
 ---
  accel.c | 4 ++--
  1 file changed, 2 insertions(+), 2 deletions(-)
 
 diff --git a/accel.c b/accel.c
-index 0510b90..afe9a0d 100644
+index 403eb5e..dd2ebea 100644
 --- a/accel.c
 +++ b/accel.c
-@@ -88,8 +88,8 @@ int configure_accelerator(MachineState *ms)
+@@ -88,8 +88,8 @@ void configure_accelerator(MachineState *ms)
  
      p = qemu_opt_get(qemu_get_machine_opts(), "accel");
      if (p == NULL) {
index 398d67e62292b4d74caaa144b18a07026c45dde5..87e4d4197f0acd8c402ad3f61cf911acf7da65fc 100644 (file)
@@ -1,7 +1,7 @@
-From 08cbc3ac32dfefc5557bf62ea230a10ad46083b1 Mon Sep 17 00:00:00 2001
+From ff496e015b9b53c2d49a0110d247223872d5a582 Mon Sep 17 00:00:00 2001
 From: Wolfgang Bumiller <w.bumiller@proxmox.com>
 Date: Wed, 9 Dec 2015 14:27:49 +0100
-Subject: [PATCH 06/55] virtio-balloon: fix query
+Subject: [PATCH 06/41] virtio-balloon: fix query
 
 Actually provide memory information via the query-balloon
 command.
@@ -13,10 +13,10 @@ command.
  4 files changed, 94 insertions(+), 5 deletions(-)
 
 diff --git a/hmp.c b/hmp.c
-index d510236..fe80757 100644
+index cc2056e..aa1395d 100644
 --- a/hmp.c
 +++ b/hmp.c
-@@ -686,7 +686,35 @@ void hmp_info_balloon(Monitor *mon, const QDict *qdict)
+@@ -704,7 +704,35 @@ void hmp_info_balloon(Monitor *mon, const QDict *qdict)
          return;
      }
  
@@ -54,10 +54,10 @@ index d510236..fe80757 100644
      qapi_free_BalloonInfo(info);
  }
 diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
-index 9dbe681..50b20f1 100644
+index 5af429a..d87b971 100644
 --- a/hw/virtio/virtio-balloon.c
 +++ b/hw/virtio/virtio-balloon.c
-@@ -379,8 +379,37 @@ static uint64_t virtio_balloon_get_features(VirtIODevice *vdev, uint64_t f,
+@@ -376,8 +376,37 @@ static uint64_t virtio_balloon_get_features(VirtIODevice *vdev, uint64_t f,
  static void virtio_balloon_stat(void *opaque, BalloonInfo *info)
  {
      VirtIOBalloon *dev = opaque;
@@ -98,10 +98,10 @@ index 9dbe681..50b20f1 100644
  
  static void virtio_balloon_to_target(void *opaque, ram_addr_t target)
 diff --git a/qapi-schema.json b/qapi-schema.json
-index 54634c4..639f7b6 100644
+index 5658723..4bf7222 100644
 --- a/qapi-schema.json
 +++ b/qapi-schema.json
-@@ -1217,10 +1217,29 @@
+@@ -1278,10 +1278,29 @@
  #
  # @actual: the number of bytes the balloon currently contains
  #
@@ -134,10 +134,10 @@ index 54634c4..639f7b6 100644
  ##
  # @query-balloon:
 diff --git a/qmp-commands.hx b/qmp-commands.hx
-index de896a5..9388578 100644
+index 6866264..6de28d4 100644
 --- a/qmp-commands.hx
 +++ b/qmp-commands.hx
-@@ -3815,6 +3815,13 @@ Make an asynchronous request for balloon info. When the request completes a
+@@ -3854,6 +3854,13 @@ Make an asynchronous request for balloon info. When the request completes a
  json-object will be returned containing the following data:
  
  - "actual": current balloon value in bytes (json-int)
@@ -151,7 +151,7 @@ index de896a5..9388578 100644
  
  Example:
  
-@@ -3822,6 +3829,12 @@ Example:
+@@ -3861,6 +3868,12 @@ Example:
  <- {
        "return":{
           "actual":1073741824,
index 368b1baaaa9049d939cf8383182be9d56e9df9cb..5cb42c62b109d4d68889dfc13d9776a2e1ff9676 100644 (file)
@@ -1,17 +1,17 @@
-From cfeb66f21383c31c70e69165c80e65c1901e7fa1 Mon Sep 17 00:00:00 2001
+From 058dbe22c0c172032264e25faa45278569a326ff Mon Sep 17 00:00:00 2001
 From: Wolfgang Bumiller <w.bumiller@proxmox.com>
 Date: Wed, 9 Dec 2015 14:30:21 +0100
-Subject: [PATCH 07/55] set the CPU model to kvm64/32 instead of qemu64/32
+Subject: [PATCH 07/41] set the CPU model to kvm64/32 instead of qemu64/32
 
 ---
  hw/i386/pc.c | 4 ++--
  1 file changed, 2 insertions(+), 2 deletions(-)
 
 diff --git a/hw/i386/pc.c b/hw/i386/pc.c
-index 99437e0..1225a99 100644
+index 022dd1b..ba8a5a1 100644
 --- a/hw/i386/pc.c
 +++ b/hw/i386/pc.c
-@@ -1111,9 +1111,9 @@ void pc_cpus_init(PCMachineState *pcms)
+@@ -1160,9 +1160,9 @@ void pc_cpus_init(PCMachineState *pcms)
      /* init CPUs */
      if (machine->cpu_model == NULL) {
  #ifdef TARGET_X86_64
index 227ef07874fbbba6881af70ed084a0967acac20d..6152f06626bc516b4348af9cbdb579d7a2e05e55 100644 (file)
@@ -1,7 +1,7 @@
-From 7ec55edfacec8698e6fde6e8be0163e57526be2b Mon Sep 17 00:00:00 2001
+From a9503229ca99454a94045c1bf0cd285228ed2863 Mon Sep 17 00:00:00 2001
 From: Wolfgang Bumiller <w.bumiller@proxmox.com>
 Date: Wed, 9 Dec 2015 14:31:18 +0100
-Subject: [PATCH 08/55] qapi: modify query machines
+Subject: [PATCH 08/41] qapi: modify query machines
 
 provide '*is-current' in MachineInfo struct
 ---
@@ -10,10 +10,10 @@ provide '*is-current' in MachineInfo struct
  2 files changed, 8 insertions(+), 1 deletion(-)
 
 diff --git a/qapi-schema.json b/qapi-schema.json
-index 639f7b6..0e97da1 100644
+index 4bf7222..63507f5 100644
 --- a/qapi-schema.json
 +++ b/qapi-schema.json
-@@ -2941,6 +2941,8 @@
+@@ -3027,6 +3027,8 @@
  #
  # @default: #optional whether the machine is default
  #
@@ -22,22 +22,22 @@ index 639f7b6..0e97da1 100644
  # @cpu-max: maximum number of CPUs supported by the machine type
  #           (since 1.5.0)
  #
-@@ -2948,7 +2950,7 @@
+@@ -3036,7 +3038,7 @@
  ##
  { 'struct': 'MachineInfo',
    'data': { 'name': 'str', '*alias': 'str',
--            '*is-default': 'bool', 'cpu-max': 'int' } }
-+            '*is-default': 'bool', '*is-current': 'bool', 'cpu-max': 'int' } }
+-            '*is-default': 'bool', 'cpu-max': 'int',
++            '*is-default': 'bool', '*is-current': 'bool', 'cpu-max': 'int',
+             'hotpluggable-cpus': 'bool'} }
  
  ##
- # @query-machines:
 diff --git a/vl.c b/vl.c
-index 5db5dc2..feeb2c4 100644
+index b3c80d5..bdf4fdc 100644
 --- a/vl.c
 +++ b/vl.c
-@@ -1538,6 +1538,11 @@ MachineInfoList *qmp_query_machines(Error **errp)
-         info->name = g_strdup(mc->name);
+@@ -1508,6 +1508,11 @@ MachineInfoList *qmp_query_machines(Error **errp)
          info->cpu_max = !mc->max_cpus ? 1 : mc->max_cpus;
+         info->hotpluggable_cpus = !!mc->query_hotpluggable_cpus;
  
 +        if (strcmp(mc->name, MACHINE_GET_CLASS(current_machine)->name) == 0) {
 +            info->has_is_current = true;
index 64deb6bf1735850eb2605bd9892e143dab210a6c..bce641fdeec4cf0d565776c488afd8c6a20e9c42 100644 (file)
@@ -1,7 +1,7 @@
-From 63b3b17a2ae5d373f49191bb0828b5dc9128b04b Mon Sep 17 00:00:00 2001
+From 42cf33b03e7f20cd9fe3f7cefbc3cc39f7a7cdeb Mon Sep 17 00:00:00 2001
 From: Wolfgang Bumiller <w.bumiller@proxmox.com>
 Date: Wed, 9 Dec 2015 14:32:11 +0100
-Subject: [PATCH 09/55] qapi: modify spice query
+Subject: [PATCH 09/41] qapi: modify spice query
 
 Provide the last ticket in the SpiceInfo struct optionally.
 ---
@@ -10,10 +10,10 @@ Provide the last ticket in the SpiceInfo struct optionally.
  2 files changed, 8 insertions(+)
 
 diff --git a/qapi-schema.json b/qapi-schema.json
-index 0e97da1..f9ccfe4 100644
+index 63507f5..518c2ea 100644
 --- a/qapi-schema.json
 +++ b/qapi-schema.json
-@@ -1192,11 +1192,14 @@
+@@ -1253,11 +1253,14 @@
  #
  # @channels: a list of @SpiceChannel for each active spice channel
  #
index 7bf6a2adcf58d7565a32520af977126fec0f7f75..05581fc420c16bd3e51412cb54a98bd5c811a46c 100644 (file)
@@ -1,7 +1,7 @@
-From 46cd19688c9134e5fa0eef9d31d005430bdae29a Mon Sep 17 00:00:00 2001
+From bc64f439e741d3d5d615fb9314f0e4b471eaeba1 Mon Sep 17 00:00:00 2001
 From: Wolfgang Bumiller <w.bumiller@proxmox.com>
 Date: Wed, 9 Dec 2015 14:33:34 +0100
-Subject: [PATCH 10/55] ui/spice: default to pve certs unless otherwise
+Subject: [PATCH 10/41] ui/spice: default to pve certs unless otherwise
  specified
 
 ---
index 3ffd33d5b7241c5fd516be02e2909c75f959f64f..ffb6108d05cb1f8e40407365ee33e5be6a4b8b83 100644 (file)
@@ -1,7 +1,7 @@
-From 1ef80c8a5ce360bbff1a9daa1c191e9238855408 Mon Sep 17 00:00:00 2001
+From 9cb2f2d61ebf1c28b19bc2df78879431b735f460 Mon Sep 17 00:00:00 2001
 From: Dietmar Maurer <dietmar@proxmox.com>
 Date: Tue, 13 Nov 2012 11:11:38 +0100
-Subject: [PATCH 11/55] introduce new vma archive format
+Subject: [PATCH 11/41] introduce new vma archive format
 
 This is a very simple archive format, see docs/specs/vma_spec.txt
 
@@ -9,30 +9,30 @@ Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>
 ---
  Makefile      |   3 +-
  Makefile.objs |   1 +
- vma-reader.c  | 79++++++++++++++++++++++++++++++++++++++++++++++++++++
- vma-writer.c  | 876 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- vma.c         | 58++++++++++++++++++++++++++++++++++++++
+ vma-reader.c  | 797 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ vma-writer.c  | 870 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ vma.c         | 585 +++++++++++++++++++++++++++++++++++++++
  vma.h         | 146 ++++++++++
- 6 files changed, 2406 insertions(+), 1 deletion(-)
+ 6 files changed, 2401 insertions(+), 1 deletion(-)
  create mode 100644 vma-reader.c
  create mode 100644 vma-writer.c
  create mode 100644 vma.c
  create mode 100644 vma.h
 
 diff --git a/Makefile b/Makefile
-index 1d076a9..4e41399 100644
+index 50b4b3a..d92d905 100644
 --- a/Makefile
 +++ b/Makefile
-@@ -167,7 +167,7 @@ ifneq ($(wildcard config-host.mak),)
- include $(SRC_PATH)/tests/Makefile
+@@ -165,7 +165,7 @@ ifneq ($(wildcard config-host.mak),)
+ include $(SRC_PATH)/tests/Makefile.include
  endif
  
 -all: $(DOCS) $(TOOLS) $(HELPERS-y) recurse-all modules
 +all: $(DOCS) $(TOOLS) vma$(EXESUF) $(HELPERS-y) recurse-all modules
  
- config-host.h: config-host.h-timestamp
- config-host.h-timestamp: config-host.mak
-@@ -237,6 +237,7 @@ qemu-img.o: qemu-img-cmds.h
+ qemu-version.h: FORCE
+       $(call quiet-command, \
+@@ -256,6 +256,7 @@ qemu-img.o: qemu-img-cmds.h
  qemu-img$(EXESUF): qemu-img.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) libqemuutil.a libqemustub.a
  qemu-nbd$(EXESUF): qemu-nbd.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) libqemuutil.a libqemustub.a
  qemu-io$(EXESUF): qemu-io.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) libqemuutil.a libqemustub.a
@@ -41,7 +41,7 @@ index 1d076a9..4e41399 100644
  qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o libqemuutil.a libqemustub.a
  
 diff --git a/Makefile.objs b/Makefile.objs
-index 8f705f6..5fd0bc4 100644
+index 6d5ddcf..845edd0 100644
 --- a/Makefile.objs
 +++ b/Makefile.objs
 @@ -15,6 +15,7 @@ block-obj-$(CONFIG_POSIX) += aio-posix.o
@@ -54,10 +54,10 @@ index 8f705f6..5fd0bc4 100644
  
 diff --git a/vma-reader.c b/vma-reader.c
 new file mode 100644
-index 0000000..bc36cba
+index 0000000..51dd8fe
 --- /dev/null
 +++ b/vma-reader.c
-@@ -0,0 +1,799 @@
+@@ -0,0 +1,797 @@
 +/*
 + * VMA: Virtual Machine Archive
 + *
@@ -71,14 +71,7 @@ index 0000000..bc36cba
 + *
 + */
 +
-+#include <stdio.h>
-+#include <errno.h>
-+#include <unistd.h>
-+#include <stdio.h>
-+#include <string.h>
-+#include <sys/types.h>
-+#include <sys/stat.h>
-+#include <fcntl.h>
++#include "qemu/osdep.h"
 +#include <glib.h>
 +#include <uuid/uuid.h>
 +
@@ -87,8 +80,7 @@ index 0000000..bc36cba
 +#include "qemu/ratelimit.h"
 +#include "vma.h"
 +#include "block/block.h"
-+
-+#define BITS_PER_LONG  (sizeof(unsigned long) * CHAR_BIT)
++#include "sysemu/block-backend.h"
 +
 +static unsigned char zero_vma_block[VMA_BLOCK_SIZE];
 +
@@ -502,7 +494,13 @@ index 0000000..bc36cba
 +    assert(vmar->rstate[dev_id].bs == NULL);
 +
 +    int64_t size = bdrv_getlength(bs);
-+    if (size != vmar->devinfo[dev_id].size) {
++    int64_t size_diff = size - vmar->devinfo[dev_id].size;
++
++    /* storage types can have different size restrictions, so it
++     * is not always possible to create an image with exact size.
++     * So we tolerate a size difference up to 4MB.
++     */
++    if ((size_diff < 0) || (size_diff > 4*1024*1024)) {
 +        error_setg(errp, "vma_reader_register_bs for stream %s failed - "
 +                   "unexpected size %zd != %zd", vmar->devinfo[dev_id].devname,
 +                   size, vmar->devinfo[dev_id].size);
@@ -859,10 +857,10 @@ index 0000000..bc36cba
 +
 diff --git a/vma-writer.c b/vma-writer.c
 new file mode 100644
-index 0000000..8a3fa1c
+index 0000000..b0cf529
 --- /dev/null
 +++ b/vma-writer.c
-@@ -0,0 +1,876 @@
+@@ -0,0 +1,870 @@
 +/*
 + * VMA: Virtual Machine Archive
 + *
@@ -876,22 +874,16 @@ index 0000000..8a3fa1c
 + *
 + */
 +
-+#include <stdio.h>
-+#include <errno.h>
-+#include <unistd.h>
-+#include <stdio.h>
-+#include <string.h>
-+#include <sys/types.h>
-+#include <sys/stat.h>
-+#include <fcntl.h>
++#include "qemu/osdep.h"
 +#include <glib.h>
 +#include <uuid/uuid.h>
 +
-+#include "qemu-common.h"
 +#include "vma.h"
 +#include "block/block.h"
 +#include "monitor/monitor.h"
 +#include "qemu/main-loop.h"
++#include "qemu/coroutine.h"
++#include "qemu/cutils.h"
 +
 +#define DEBUG_VMA 0
 +
@@ -1084,7 +1076,7 @@ index 0000000..8a3fa1c
 +    VmaWriter *vmaw = opaque;
 +
 +    DPRINTF("vma_co_continue_write\n");
-+    qemu_coroutine_enter(vmaw->co_writer, NULL);
++    qemu_coroutine_enter(vmaw->co_writer);
 +}
 +
 +static ssize_t coroutine_fn
@@ -1102,7 +1094,7 @@ index 0000000..8a3fa1c
 +
 +    vmaw->co_writer = qemu_coroutine_self();
 +
-+    aio_set_fd_handler(qemu_get_aio_context(), vmaw->fd, NULL, vma_co_continue_write, vmaw);
++    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();
@@ -1129,7 +1121,7 @@ index 0000000..8a3fa1c
 +        }
 +    }
 +
-+    aio_set_fd_handler(qemu_get_aio_context(), vmaw->fd, NULL, NULL, NULL);
++    aio_set_fd_handler(qemu_get_aio_context(), vmaw->fd, false, NULL, NULL, NULL);
 +
 +    vmaw->co_writer = NULL;
 +
@@ -1741,10 +1733,10 @@ index 0000000..8a3fa1c
 +}
 diff --git a/vma.c b/vma.c
 new file mode 100644
-index 0000000..86c117b
+index 0000000..8014090
 --- /dev/null
 +++ b/vma.c
-@@ -0,0 +1,582 @@
+@@ -0,0 +1,585 @@
 +/*
 + * VMA: Virtual Machine Archive
 + *
@@ -1758,20 +1750,14 @@ index 0000000..86c117b
 + *
 + */
 +
-+#include <stdio.h>
-+#include <errno.h>
-+#include <unistd.h>
-+#include <stdio.h>
-+#include <string.h>
-+#include <sys/types.h>
-+#include <sys/stat.h>
-+#include <fcntl.h>
++#include "qemu/osdep.h"
 +#include <glib.h>
 +
 +#include "vma.h"
 +#include "qemu-common.h"
 +#include "qemu/error-report.h"
 +#include "qemu/main-loop.h"
++#include "sysemu/char.h" /* qstring_from_str */
 +
 +static void help(void)
 +{
@@ -2044,7 +2030,7 @@ index 0000000..86c117b
 +            }
 +
 +            BlockDriverState *bs = bdrv_new();
-+            if (errp || bdrv_open(&bs, devfn, NULL, NULL, flags, NULL, &errp)) {
++            if (errp || bdrv_open(&bs, devfn, NULL, NULL, flags, &errp)) {
 +                g_error("can't open file %s - %s", devfn,
 +                        error_get_pretty(errp));
 +            }
@@ -2140,7 +2126,7 @@ index 0000000..86c117b
 +
 +static int create_archive(int argc, char **argv)
 +{
-+    int i, c, res;
++    int i, c;
 +    int verbose = 0;
 +    const char *archivename;
 +    GList *config_files = NULL;
@@ -2209,12 +2195,11 @@ index 0000000..86c117b
 +        char *devname = NULL;
 +        path = extract_devname(path, &devname, ind++);
 +
-+        BlockDriver *drv = NULL;
 +        Error *errp = NULL;
-+        BlockDriverState *bs = bdrv_new();
++        BlockDriverState *bs;
 +
-+        res = bdrv_open(&bs, path, NULL, NULL, BDRV_O_CACHE_WB , drv, &errp);
-+        if (res < 0) {
++        bs = bdrv_open(path, NULL, NULL, 0, &errp);
++        if (!bs) {
 +            unlink(archivename);
 +            g_error("bdrv_open '%s' failed - %s", path, error_get_pretty(errp));
 +        }
@@ -2231,8 +2216,8 @@ index 0000000..86c117b
 +        job->vmaw = vmaw;
 +        job->dev_id = dev_id;
 +
-+        Coroutine *co = qemu_coroutine_create(backup_run);
-+        qemu_coroutine_enter(co, job);
++        Coroutine *co = qemu_coroutine_create(backup_run, job);
++        qemu_coroutine_enter(co);
 +    }
 +
 +    VmaStatus vmastat;
@@ -2270,6 +2255,16 @@ index 0000000..86c117b
 +        if (vmastat.closed) {
 +            break;
 +        }
++    } else {
++        Coroutine *co = qemu_coroutine_create(backup_run_empty, vmaw);
++        qemu_coroutine_enter(co);
++        while (1) {
++            main_loop_wait(false);
++            vma_writer_get_status(vmaw, &vmastat);
++            if (vmastat.closed) {
++                    break;
++            }
++        }
 +    }
 +
 +    bdrv_drain_all();
index 18cf5aa77b6dabf79bdda63641f424cd97cdb74b..3f63387df14ae201cb580c094233ab65c8576bb7 100644 (file)
@@ -1,7 +1,7 @@
-From 5a03baace683a297371dbe36795a517d68fc2727 Mon Sep 17 00:00:00 2001
+From 6dad22d8b527594d14987d1118f95179c0ff5aaa Mon Sep 17 00:00:00 2001
 From: Dietmar Maurer <dietmar@proxmox.com>
 Date: Mon, 11 Mar 2013 07:07:46 +0100
-Subject: [PATCH 12/55] vma: add verify command
+Subject: [PATCH 12/41] vma: add verify command
 
 Users wants to verify the archive after backup.
 
@@ -19,10 +19,10 @@ Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>
  3 files changed, 147 insertions(+), 30 deletions(-)
 
 diff --git a/vma-reader.c b/vma-reader.c
-index bc36cba..9d92c6a 100644
+index 51dd8fe..2aafb26 100644
 --- a/vma-reader.c
 +++ b/vma-reader.c
-@@ -53,6 +53,8 @@ struct VmaReader {
+@@ -45,6 +45,8 @@ struct VmaReader {
      time_t start_time;
      int64_t cluster_count;
      int64_t clusters_read;
@@ -31,7 +31,7 @@ index bc36cba..9d92c6a 100644
      int clusters_read_per;
  };
  
-@@ -433,6 +435,27 @@ VmaDeviceInfo *vma_reader_get_device_info(VmaReader *vmar, guint8 dev_id)
+@@ -425,6 +427,27 @@ VmaDeviceInfo *vma_reader_get_device_info(VmaReader *vmar, guint8 dev_id)
      return NULL;
  }
  
@@ -59,7 +59,7 @@ index bc36cba..9d92c6a 100644
  int vma_reader_register_bs(VmaReader *vmar, guint8 dev_id, BlockDriverState *bs,
                             bool write_zeroes, Error **errp)
  {
-@@ -449,17 +472,7 @@ int vma_reader_register_bs(VmaReader *vmar, guint8 dev_id, BlockDriverState *bs,
+@@ -447,17 +470,7 @@ int vma_reader_register_bs(VmaReader *vmar, guint8 dev_id, BlockDriverState *bs,
          return -1;
      }
  
@@ -78,7 +78,7 @@ index bc36cba..9d92c6a 100644
  
      return 0;
  }
-@@ -526,9 +539,10 @@ static int restore_write_data(VmaReader *vmar, guint8 dev_id,
+@@ -524,9 +537,10 @@ static int restore_write_data(VmaReader *vmar, guint8 dev_id,
      }
      return 0;
  }
@@ -90,7 +90,7 @@ index bc36cba..9d92c6a 100644
  {
      assert(vmar);
      assert(buf);
-@@ -553,7 +567,7 @@ static int restore_extent(VmaReader *vmar, unsigned char *buf,
+@@ -551,7 +565,7 @@ static int restore_extent(VmaReader *vmar, unsigned char *buf,
  
          if (dev_id != vmar->vmstate_stream) {
              bs = rstate->bs;
@@ -99,7 +99,7 @@ index bc36cba..9d92c6a 100644
                  error_setg(errp, "got wrong dev id %d", dev_id);
                  return -1;
              }
-@@ -609,10 +623,13 @@ static int restore_extent(VmaReader *vmar, unsigned char *buf,
+@@ -607,10 +621,13 @@ static int restore_extent(VmaReader *vmar, unsigned char *buf,
                  return -1;
              }
  
@@ -117,7 +117,7 @@ index bc36cba..9d92c6a 100644
              }
  
              start += VMA_CLUSTER_SIZE;
-@@ -642,26 +659,37 @@ static int restore_extent(VmaReader *vmar, unsigned char *buf,
+@@ -640,26 +657,37 @@ static int restore_extent(VmaReader *vmar, unsigned char *buf,
                          return -1;
                      }
  
@@ -165,7 +165,7 @@ index bc36cba..9d92c6a 100644
                          }
                      }
                  }
-@@ -679,8 +707,9 @@ static int restore_extent(VmaReader *vmar, unsigned char *buf,
+@@ -677,8 +705,9 @@ static int restore_extent(VmaReader *vmar, unsigned char *buf,
      return 0;
  }
  
@@ -177,7 +177,7 @@ index bc36cba..9d92c6a 100644
  {
      assert(vmar);
      assert(vmar->head_data);
-@@ -747,7 +776,7 @@ int vma_reader_restore(VmaReader *vmar, int vmstate_fd, bool verbose,
+@@ -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,
@@ -186,7 +186,7 @@ index bc36cba..9d92c6a 100644
              return -1;
          }
  
-@@ -794,6 +823,38 @@ int vma_reader_restore(VmaReader *vmar, int vmstate_fd, bool verbose,
+@@ -792,6 +821,38 @@ int vma_reader_restore(VmaReader *vmar, int vmstate_fd, bool verbose,
          }
      }
  
@@ -226,10 +226,10 @@ index bc36cba..9d92c6a 100644
 +}
 +
 diff --git a/vma.c b/vma.c
-index 86c117b..3ad2f18 100644
+index 8014090..d55874a 100644
 --- a/vma.c
 +++ b/vma.c
-@@ -34,6 +34,7 @@ static void help(void)
+@@ -28,6 +28,7 @@ static void help(void)
          "vma list <filename>\n"
          "vma create <filename> [-c config] <archive> pathname ...\n"
          "vma extract <filename> [-r <fifo>] <targetdir>\n"
@@ -237,7 +237,7 @@ index 86c117b..3ad2f18 100644
          ;
  
      printf("%s", help_msg);
-@@ -338,6 +339,58 @@ static int extract_content(int argc, char **argv)
+@@ -332,6 +333,58 @@ static int extract_content(int argc, char **argv)
      return ret;
  }
  
@@ -296,7 +296,7 @@ index 86c117b..3ad2f18 100644
  typedef struct BackupJob {
      BlockDriverState *bs;
      int64_t len;
-@@ -575,6 +628,8 @@ int main(int argc, char **argv)
+@@ -578,6 +631,8 @@ int main(int argc, char **argv)
          return create_archive(argc, argv);
      } else if (!strcmp(cmdname, "extract")) {
          return extract_content(argc, argv);
index a268a154d72d75cad4cf31ca700eac45da7e88d0..1dbbaa0bf29877ac74fd1d86e2142d8678676960 100644 (file)
@@ -1,17 +1,17 @@
-From 4cf741ef0ec95b62dab484f5630e0f5fd608220a Mon Sep 17 00:00:00 2001
+From fbe4db594bee11864b82c5839425348bc4133c9b Mon Sep 17 00:00:00 2001
 From: Wolfgang Bumiller <w.bumiller@proxmox.com>
 Date: Wed, 9 Dec 2015 14:46:49 +0100
-Subject: [PATCH 13/55] vma: add 'config' command to dump the config
+Subject: [PATCH 13/41] 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 3ad2f18..6a33352 100644
+index d55874a..79bdd00 100644
 --- a/vma.c
 +++ b/vma.c
-@@ -32,6 +32,7 @@ static void help(void)
+@@ -26,6 +26,7 @@ static void help(void)
          "usage: vma command [command options]\n"
          "\n"
          "vma list <filename>\n"
@@ -19,7 +19,7 @@ index 3ad2f18..6a33352 100644
          "vma create <filename> [-c config] <archive> pathname ...\n"
          "vma extract <filename> [-r <fifo>] <targetdir>\n"
          "vma verify <filename> [-v]\n"
-@@ -601,6 +602,67 @@ static int create_archive(int argc, char **argv)
+@@ -604,6 +605,67 @@ static int create_archive(int argc, char **argv)
      return 0;
  }
  
@@ -87,7 +87,7 @@ index 3ad2f18..6a33352 100644
  int main(int argc, char **argv)
  {
      const char *cmdname;
-@@ -630,6 +692,8 @@ int main(int argc, char **argv)
+@@ -633,6 +695,8 @@ int main(int argc, char **argv)
          return extract_content(argc, argv);
      } else if (!strcmp(cmdname, "verify")) {
          return verify_content(argc, argv);
diff --git a/debian/patches/pve/0014-backup-modify-job-api.patch b/debian/patches/pve/0014-backup-modify-job-api.patch
new file mode 100644 (file)
index 0000000..c724241
--- /dev/null
@@ -0,0 +1,236 @@
+From dbdd959063e8f5d13c3051607a0fb7a2e0e178e6 Mon Sep 17 00:00:00 2001
+From: Wolfgang Bumiller <w.bumiller@proxmox.com>
+Date: Wed, 9 Dec 2015 15:04:57 +0100
+Subject: [PATCH 14/41] 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            | 82 +++++++++++++++++++++++++++++++----------------
+ blockdev.c                |  6 ++--
+ include/block/block_int.h |  5 +++
+ 3 files changed, 63 insertions(+), 30 deletions(-)
+
+diff --git a/block/backup.c b/block/backup.c
+index 2c05323..f3c0ba3 100644
+--- a/block/backup.c
++++ b/block/backup.c
+@@ -41,6 +41,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;
+@@ -149,12 +150,23 @@ 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, 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, 0);
++            }
+         }
+         if (ret < 0) {
+             trace_backup_do_cow_write_fail(job, start, ret);
+@@ -268,9 +280,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;
+     }
+ }
+@@ -393,6 +407,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);
+@@ -467,7 +482,9 @@ static void coroutine_fn backup_run(void *opaque)
+     qemu_co_rwlock_unlock(&job->flush_rwlock);
+     g_free(job->done_bitmap);
+-    bdrv_op_unblock_all(blk_bs(target), job->common.blocker);
++    if (target) {
++        bdrv_op_unblock_all(blk_bs(target), job->common.blocker);
++    }
+     data = g_malloc(sizeof(*data));
+     data->ret = ret;
+@@ -479,7 +496,9 @@ void backup_start(const char *job_id, BlockDriverState *bs,
+                   MirrorSyncMode sync_mode, BdrvDirtyBitmap *sync_bitmap,
+                   BlockdevOnError on_source_error,
+                   BlockdevOnError on_target_error,
++                  BackupDumpFunc *dump_cb,
+                   BlockCompletionFunc *cb, void *opaque,
++                  int pause_count,
+                   BlockJobTxn *txn, Error **errp)
+ {
+     int64_t len;
+@@ -488,7 +507,7 @@ void backup_start(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");
+@@ -501,7 +520,7 @@ void backup_start(const char *job_id, BlockDriverState *bs,
+         return;
+     }
+-    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;
+@@ -511,7 +530,7 @@ void backup_start(const char *job_id, BlockDriverState *bs,
+         return;
+     }
+-    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;
+     }
+@@ -547,34 +566,43 @@ void backup_start(const char *job_id, BlockDriverState *bs,
+         goto error;
+     }
+-    job->target = blk_new();
+-    blk_insert_bs(job->target, target);
++    if (target) {
++        job->target = blk_new();
++        blk_insert_bs(job->target, target);
++    }
++    job->dump_cb = dump_cb;
+     job->on_source_error = on_source_error;
+     job->on_target_error = on_target_error;
+     job->sync_mode = sync_mode;
+     job->sync_bitmap = sync_mode == MIRROR_SYNC_MODE_INCREMENTAL ?
+                        sync_bitmap : NULL;
+-    /* 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 < 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 < 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);
++        }
++
++        bdrv_op_block_all(target, job->common.blocker);
+     } else {
+-        job->cluster_size = MAX(BACKUP_CLUSTER_SIZE_DEFAULT, bdi.cluster_size);
++        job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT;
+     }
+-    bdrv_op_block_all(target, job->common.blocker);
++    job->common.pause_count = pause_count;
+     job->common.len = len;
+     job->common.co = qemu_coroutine_create(backup_run, job);
+     block_job_txn_add_job(txn, &job->common);
+diff --git a/blockdev.c b/blockdev.c
+index 2161400..5e3707d 100644
+--- a/blockdev.c
++++ b/blockdev.c
+@@ -3277,8 +3277,8 @@ static void do_drive_backup(const char *job_id, const char *device,
+     }
+     backup_start(job_id, bs, target_bs, speed, sync, bmap,
+-                 on_source_error, on_target_error,
+-                 block_job_cb, bs, txn, &local_err);
++                 on_source_error, on_target_error, NULL,
++                 block_job_cb, bs, 0, txn, &local_err);
+     bdrv_unref(target_bs);
+     if (local_err != NULL) {
+         error_propagate(errp, local_err);
+@@ -3371,7 +3371,7 @@ void do_blockdev_backup(const char *job_id, const char *device,
+         }
+     }
+     backup_start(job_id, bs, target_bs, speed, sync, NULL, on_source_error,
+-                 on_target_error, block_job_cb, bs, txn, &local_err);
++                 on_target_error, NULL, block_job_cb, bs, 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 1e939de..db4650e 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,
+@@ -767,7 +770,9 @@ void backup_start(const char *job_id, BlockDriverState *bs,
+                   MirrorSyncMode sync_mode, BdrvDirtyBitmap *sync_bitmap,
+                   BlockdevOnError on_source_error,
+                   BlockdevOnError on_target_error,
++                  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.1.4
+
diff --git a/debian/patches/pve/0014-vma-restore-tolerate-a-size-difference-up-to-4M.patch b/debian/patches/pve/0014-vma-restore-tolerate-a-size-difference-up-to-4M.patch
deleted file mode 100644 (file)
index d9ff52d..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-From b60a9ba781fc9e4f1a8c7d177f20933340cf4fc4 Mon Sep 17 00:00:00 2001
-From: Dietmar Maurer <dietmar@proxmox.com>
-Date: Tue, 26 Mar 2013 06:21:16 +0100
-Subject: [PATCH 14/55] vma restore: tolerate a size difference up to 4M
-
-Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>
----
- vma-reader.c | 8 +++++++-
- 1 file changed, 7 insertions(+), 1 deletion(-)
-
-diff --git a/vma-reader.c b/vma-reader.c
-index 9d92c6a..d9f43fe 100644
---- a/vma-reader.c
-+++ b/vma-reader.c
-@@ -465,7 +465,13 @@ int vma_reader_register_bs(VmaReader *vmar, guint8 dev_id, BlockDriverState *bs,
-     assert(vmar->rstate[dev_id].bs == NULL);
-     int64_t size = bdrv_getlength(bs);
--    if (size != vmar->devinfo[dev_id].size) {
-+    int64_t size_diff = size - vmar->devinfo[dev_id].size;
-+
-+    /* storage types can have different size restrictions, so it
-+     * is not always possible to create an image with exact size.
-+     * So we tolerate a size difference up to 4MB.
-+     */
-+    if ((size_diff < 0) || (size_diff > 4*1024*1024)) {
-         error_setg(errp, "vma_reader_register_bs for stream %s failed - "
-                    "unexpected size %zd != %zd", vmar->devinfo[dev_id].devname,
-                    size, vmar->devinfo[dev_id].size);
--- 
-2.1.4
-
diff --git a/debian/patches/pve/0015-backup-add-pve-monitor-commands.patch b/debian/patches/pve/0015-backup-add-pve-monitor-commands.patch
new file mode 100644 (file)
index 0000000..05a22cd
--- /dev/null
@@ -0,0 +1,797 @@
+From 83fc57d04020d8d9aebd7b9676bee0be099421d8 Mon Sep 17 00:00:00 2001
+From: Wolfgang Bumiller <w.bumiller@proxmox.com>
+Date: Wed, 9 Dec 2015 15:20:56 +0100
+Subject: [PATCH 15/41] backup: add pve monitor commands
+
+---
+ blockdev.c                | 439 ++++++++++++++++++++++++++++++++++++++++++++++
+ blockjob.c                |   3 +-
+ hmp-commands-info.hx      |  13 ++
+ hmp-commands.hx           |  29 +++
+ hmp.c                     |  61 +++++++
+ hmp.h                     |   3 +
+ include/block/block_int.h |   2 +-
+ qapi-schema.json          |  89 ++++++++++
+ qmp-commands.hx           |  18 ++
+ 9 files changed, 655 insertions(+), 2 deletions(-)
+
+diff --git a/blockdev.c b/blockdev.c
+index 5e3707d..5417bb0 100644
+--- a/blockdev.c
++++ b/blockdev.c
+@@ -52,6 +52,7 @@
+ #include "sysemu/arch_init.h"
+ #include "qemu/cutils.h"
+ #include "qemu/help_option.h"
++#include "vma.h"
+ static QTAILQ_HEAD(, BlockDriverState) monitor_bdrv_states =
+     QTAILQ_HEAD_INITIALIZER(monitor_bdrv_states);
+@@ -2976,6 +2977,444 @@ static void block_job_cb(void *opaque, int ret)
+     }
+ }
++/* 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_start(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_backing_file, const char *backing_file,
+diff --git a/blockjob.c b/blockjob.c
+index a5ba3be..a550458 100644
+--- a/blockjob.c
++++ b/blockjob.c
+@@ -331,7 +331,8 @@ void block_job_pause(BlockJob *job)
+     job->pause_count++;
+ }
+-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;
+ }
+diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
+index 74446c6..7616fe2 100644
+--- a/hmp-commands-info.hx
++++ b/hmp-commands-info.hx
+@@ -502,6 +502,19 @@ STEXI
+ Show CPU statistics.
+ ETEXI
++    {
++        .name       = "backup",
++        .args_type  = "",
++        .params     = "",
++        .help       = "show backup status",
++        .mhandler.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 848efee..8f2f3e0 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.",
++        .mhandler.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",
++        .mhandler.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 aa1395d..88cb4e5 100644
+--- a/hmp.c
++++ b/hmp.c
+@@ -149,6 +149,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;
+@@ -1492,6 +1530,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 0876ec0..9a4c1f6 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);
+@@ -76,6 +77,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 db4650e..0f79b51 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 518c2ea..89d9ea6 100644
+--- a/qapi-schema.json
++++ b/qapi-schema.json
+@@ -356,6 +356,95 @@
+ ##
+ { 'command': 'query-events', 'returns': ['EventInfo'] }
++# @BackupStatus:
++#
++# Detailed backup status.
++#
++# @status: #optional 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: #optional error message (only returned if status is 'error')
++#
++# @total: #optional total amount of bytes involved in the backup process
++#
++# @transferred: #optional amount of bytes already backed up.
++#
++# @zero-bytes: #optional amount of 'zero' bytes detected.
++#
++# @start-time: #optional time (epoch) when backup job started.
++#
++# @end-time: #optional time (epoch) when backup job finished.
++#
++# @backupfile: #optional backup file name
++#
++# @uuid: #optional 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-filename: #optional name of a configuration file to include into
++# the backup archive.
++#
++# @speed: #optional the maximum speed, in bytes per second
++#
++# @devlist: #optional 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
+ #
+diff --git a/qmp-commands.hx b/qmp-commands.hx
+index 6de28d4..a8e8522 100644
+--- a/qmp-commands.hx
++++ b/qmp-commands.hx
+@@ -1314,6 +1314,24 @@ Example:
+ EQMP
+     {
++        .name       = "backup",
++        .args_type  = "backup-file:s,format:s?,config-file:F?,speed:o?,devlist:s?",
++        .mhandler.cmd_new = qmp_marshal_backup,
++    },
++
++    {
++        .name       = "backup-cancel",
++        .args_type  = "",
++        .mhandler.cmd_new = qmp_marshal_backup_cancel,
++    },
++
++    {
++        .name       = "query-backup",
++        .args_type  = "",
++        .mhandler.cmd_new = qmp_marshal_query_backup,
++    },
++
++    {
+         .name       = "block-job-set-speed",
+         .args_type  = "device:B,speed:o",
+         .mhandler.cmd_new = qmp_marshal_block_job_set_speed,
+-- 
+2.1.4
+
diff --git a/debian/patches/pve/0015-backup-modify-job-api.patch b/debian/patches/pve/0015-backup-modify-job-api.patch
deleted file mode 100644 (file)
index 08d7d44..0000000
+++ /dev/null
@@ -1,252 +0,0 @@
-From 621e6e6521a550fd3be48ee33b0d1e9a39c0ed5c Mon Sep 17 00:00:00 2001
-From: Wolfgang Bumiller <w.bumiller@proxmox.com>
-Date: Wed, 9 Dec 2015 15:04:57 +0100
-Subject: [PATCH 15/55] 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            | 90 ++++++++++++++++++++++++++++++-----------------
- blockdev.c                |  6 ++--
- include/block/block_int.h |  5 +++
- 3 files changed, 65 insertions(+), 36 deletions(-)
-
-diff --git a/block/backup.c b/block/backup.c
-index 370c285..c38b520 100644
---- a/block/backup.c
-+++ b/block/backup.c
-@@ -41,6 +41,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;
-@@ -153,14 +154,21 @@ static int coroutine_fn backup_do_cow(BlockDriverState *bs,
-             goto out;
-         }
-+        int64_t start_sec = start * sectors_per_cluster;
-         if (buffer_is_zero(iov.iov_base, iov.iov_len)) {
--            ret = bdrv_co_write_zeroes(job->target,
--                                       start * sectors_per_cluster,
--                                       n, 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 = bdrv_co_write_zeroes(job->target, start_sec, n, BDRV_REQ_MAY_UNMAP);
-+            }
-         } else {
--            ret = bdrv_co_writev(job->target,
--                                 start * sectors_per_cluster, n,
--                                 &bounce_qiov);
-+            if (job->dump_cb) {
-+                ret = job->dump_cb(job->common.opaque, job->target, start_sec, n, bounce_buffer);
-+            }
-+            if (job->target) {
-+                ret = bdrv_co_writev(job->target, start_sec, n, &bounce_qiov);
-+            }
-         }
-         if (ret < 0) {
-             trace_backup_do_cow_write_fail(job, start, ret);
-@@ -222,7 +230,7 @@ static void backup_iostatus_reset(BlockJob *job)
- {
-     BackupBlockJob *s = container_of(job, BackupBlockJob, common);
--    if (s->target->blk) {
-+    if (s->target && s->target->blk) {
-         blk_iostatus_reset(s->target->blk);
-     }
- }
-@@ -274,9 +282,11 @@ static BlockErrorAction backup_error_action(BackupBlockJob *job,
-     if (read) {
-         return block_job_error_action(&job->common, job->common.bs,
-                                       job->on_source_error, true, error);
--    } else {
-+    } else if (job->target) {
-         return block_job_error_action(&job->common, job->target,
-                                       job->on_target_error, false, error);
-+    } else {
-+        return BLOCK_ERROR_ACTION_REPORT;
-     }
- }
-@@ -404,9 +414,12 @@ static void coroutine_fn backup_run(void *opaque)
-     job->done_bitmap = bitmap_new(end);
--    if (target->blk) {
--        blk_set_on_error(target->blk, on_target_error, on_target_error);
--        blk_iostatus_enable(target->blk);
-+    if (target) {
-+        bdrv_set_enable_write_cache(target, true);
-+        if (target->blk) {
-+            blk_set_on_error(target->blk, on_target_error, on_target_error);
-+            blk_iostatus_enable(target->blk);
-+        }
-     }
-     bdrv_add_before_write_notifier(bs, &before_write);
-@@ -484,10 +497,12 @@ static void coroutine_fn backup_run(void *opaque)
-     qemu_co_rwlock_unlock(&job->flush_rwlock);
-     g_free(job->done_bitmap);
--    if (target->blk) {
--        blk_iostatus_disable(target->blk);
-+    if (target) {
-+        if (target->blk) {
-+            blk_iostatus_disable(target->blk);
-+        }
-+        bdrv_op_unblock_all(target, job->common.blocker);
-     }
--    bdrv_op_unblock_all(target, job->common.blocker);
-     data = g_malloc(sizeof(*data));
-     data->ret = ret;
-@@ -499,7 +514,9 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
-                   BdrvDirtyBitmap *sync_bitmap,
-                   BlockdevOnError on_source_error,
-                   BlockdevOnError on_target_error,
-+                  BackupDumpFunc *dump_cb,
-                   BlockCompletionFunc *cb, void *opaque,
-+                  int pause_count,
-                   BlockJobTxn *txn, Error **errp)
- {
-     int64_t len;
-@@ -508,7 +525,7 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
-     int ret;
-     assert(bs);
--    assert(target);
-+    assert(target || dump_cb);
-     assert(cb);
-     if (bs == target) {
-@@ -529,7 +546,7 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
-         return;
-     }
--    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;
-@@ -539,7 +556,7 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
-         return;
-     }
--    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;
-     }
-@@ -574,6 +591,7 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
-         goto error;
-     }
-+    job->dump_cb = dump_cb;
-     job->on_source_error = on_source_error;
-     job->on_target_error = on_target_error;
-     job->target = target;
-@@ -581,25 +599,31 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
-     job->sync_bitmap = sync_mode == MIRROR_SYNC_MODE_INCREMENTAL ?
-                        sync_bitmap : NULL;
--    /* 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(job->target, &bdi);
--    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(job->target, &bdi);
-+        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);
-+        }
-+
-+        bdrv_op_block_all(target, job->common.blocker);
-     } else {
--        job->cluster_size = MAX(BACKUP_CLUSTER_SIZE_DEFAULT, bdi.cluster_size);
-+        job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT;
-     }
--    bdrv_op_block_all(target, job->common.blocker);
-+    job->common.pause_count = pause_count;
-     job->common.len = len;
-     job->common.co = qemu_coroutine_create(backup_run);
-     block_job_txn_add_job(txn, &job->common);
-diff --git a/blockdev.c b/blockdev.c
-index 260a6f5..dfc5204 100644
---- a/blockdev.c
-+++ b/blockdev.c
-@@ -3292,8 +3292,8 @@ static void do_drive_backup(const char *device, const char *target,
-     }
-     backup_start(bs, target_bs, speed, sync, bmap,
--                 on_source_error, on_target_error,
--                 block_job_cb, bs, txn, &local_err);
-+                 on_source_error, on_target_error, NULL,
-+                 block_job_cb, bs, 0, txn, &local_err);
-     if (local_err != NULL) {
-         bdrv_unref(target_bs);
-         error_propagate(errp, local_err);
-@@ -3382,7 +3382,7 @@ void do_blockdev_backup(const char *device, const char *target,
-     bdrv_ref(target_bs);
-     bdrv_set_aio_context(target_bs, aio_context);
-     backup_start(bs, target_bs, speed, sync, NULL, on_source_error,
--                 on_target_error, block_job_cb, bs, txn, &local_err);
-+                 on_target_error, NULL, block_job_cb, bs, 0, txn, &local_err);
-     if (local_err != NULL) {
-         bdrv_unref(target_bs);
-         error_propagate(errp, local_err);
-diff --git a/include/block/block_int.h b/include/block/block_int.h
-index 10d8759..2dd866b 100644
---- a/include/block/block_int.h
-+++ b/include/block/block_int.h
-@@ -60,6 +60,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,
-@@ -703,7 +706,9 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
-                   BdrvDirtyBitmap *sync_bitmap,
-                   BlockdevOnError on_source_error,
-                   BlockdevOnError on_target_error,
-+                  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.1.4
-
diff --git a/debian/patches/pve/0016-backup-add-pve-monitor-commands.patch b/debian/patches/pve/0016-backup-add-pve-monitor-commands.patch
deleted file mode 100644 (file)
index 32f0683..0000000
+++ /dev/null
@@ -1,767 +0,0 @@
-From 30e5d63f13a3f7adcd1f473fa0238c3e2e915114 Mon Sep 17 00:00:00 2001
-From: Wolfgang Bumiller <w.bumiller@proxmox.com>
-Date: Wed, 9 Dec 2015 15:20:56 +0100
-Subject: [PATCH 16/55] backup: add pve monitor commands
-
----
- blockdev.c           | 438 +++++++++++++++++++++++++++++++++++++++++++++++++++
- hmp-commands-info.hx |  13 ++
- hmp-commands.hx      |  29 ++++
- hmp.c                |  61 +++++++
- hmp.h                |   3 +
- qapi-schema.json     |  89 +++++++++++
- qmp-commands.hx      |  18 +++
- 7 files changed, 651 insertions(+)
-
-diff --git a/blockdev.c b/blockdev.c
-index dfc5204..115524f 100644
---- a/blockdev.c
-+++ b/blockdev.c
-@@ -52,6 +52,7 @@
- #include "sysemu/arch_init.h"
- #include "qemu/cutils.h"
- #include "qemu/help_option.h"
-+#include "vma.h"
- static QTAILQ_HEAD(, BlockDriverState) monitor_bdrv_states =
-     QTAILQ_HEAD_INITIALIZER(monitor_bdrv_states);
-@@ -2989,6 +2990,443 @@ static void block_job_cb(void *opaque, int ret)
-     }
- }
-+/* 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, BlockDriverState *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);
-+    qemu_coroutine_enter(co, NULL);
-+
-+    while (backup_state.vmaw) {
-+        /* vma writer use main aio context */
-+        aio_poll(qemu_get_aio_context(), true);
-+    }
-+}
-+
-+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_is_paused(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 {
-+
-+        bs = NULL;
-+        while ((bs = bdrv_next(bs))) {
-+
-+            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_start(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, &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(const char *device,
-                       bool has_base, const char *base,
-                       bool has_backing_file, const char *backing_file,
-diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
-index 52539c3..f872262 100644
---- a/hmp-commands-info.hx
-+++ b/hmp-commands-info.hx
-@@ -502,6 +502,19 @@ STEXI
- Show CPU statistics.
- ETEXI
-+    {
-+        .name       = "backup",
-+        .args_type  = "",
-+        .params     = "",
-+        .help       = "show backup status",
-+        .mhandler.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 4f4f60a..63c44f5 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.",
-+        .mhandler.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",
-+        .mhandler.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 fe80757..2d4bf97 100644
---- a/hmp.c
-+++ b/hmp.c
-@@ -148,6 +148,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;
-@@ -1476,6 +1514,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 093d65f..c708b3f 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);
-@@ -76,6 +77,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 f9ccfe4..4f673d4 100644
---- a/qapi-schema.json
-+++ b/qapi-schema.json
-@@ -356,6 +356,95 @@
- ##
- { 'command': 'query-events', 'returns': ['EventInfo'] }
-+# @BackupStatus:
-+#
-+# Detailed backup status.
-+#
-+# @status: #optional 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: #optional error message (only returned if status is 'error')
-+#
-+# @total: #optional total amount of bytes involved in the backup process
-+#
-+# @transferred: #optional amount of bytes already backed up.
-+#
-+# @zero-bytes: #optional amount of 'zero' bytes detected.
-+#
-+# @start-time: #optional time (epoch) when backup job started.
-+#
-+# @end-time: #optional time (epoch) when backup job finished.
-+#
-+# @backupfile: #optional backup file name
-+#
-+# @uuid: #optional 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-filename: #optional name of a configuration file to include into
-+# the backup archive.
-+#
-+# @speed: #optional the maximum speed, in bytes per second
-+#
-+# @devlist: #optional 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
- #
-diff --git a/qmp-commands.hx b/qmp-commands.hx
-index 9388578..3f03c0d 100644
---- a/qmp-commands.hx
-+++ b/qmp-commands.hx
-@@ -1279,6 +1279,24 @@ Example:
- EQMP
-     {
-+        .name       = "backup",
-+        .args_type  = "backup-file:s,format:s?,config-file:F?,speed:o?,devlist:s?",
-+        .mhandler.cmd_new = qmp_marshal_input_backup,
-+    },
-+
-+    {
-+        .name       = "backup-cancel",
-+        .args_type  = "",
-+        .mhandler.cmd_new = qmp_marshal_input_backup_cancel,
-+    },
-+
-+    {
-+        .name       = "query-backup",
-+        .args_type  = "",
-+        .mhandler.cmd_new = qmp_marshal_input_query_backup,
-+    },
-+
-+    {
-         .name       = "block-job-set-speed",
-         .args_type  = "device:B,speed:o",
-         .mhandler.cmd_new = qmp_marshal_block_job_set_speed,
--- 
-2.1.4
-
diff --git a/debian/patches/pve/0016-backup-vma-add-dir-format.patch b/debian/patches/pve/0016-backup-vma-add-dir-format.patch
new file mode 100644 (file)
index 0000000..9078604
--- /dev/null
@@ -0,0 +1,286 @@
+From 996797aac7aa6bc93ed934a14fa3f8425e711318 Mon Sep 17 00:00:00 2001
+From: Wolfgang Bumiller <w.bumiller@proxmox.com>
+Date: Wed, 9 Dec 2015 15:21:54 +0100
+Subject: [PATCH 16/41] backup: vma: add dir format
+
+---
+ blockdev.c       | 124 +++++++++++++++++++++++++++++++++++++++++--------------
+ hmp-commands.hx  |   8 ++--
+ hmp.c            |   4 +-
+ qapi-schema.json |   2 +-
+ vma.c            |   2 +-
+ 5 files changed, 103 insertions(+), 37 deletions(-)
+
+diff --git a/blockdev.c b/blockdev.c
+index 5417bb0..d8b1db8 100644
+--- a/blockdev.c
++++ b/blockdev.c
+@@ -3001,6 +3001,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);
+@@ -3069,8 +3071,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) {
+@@ -3081,8 +3081,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);
+@@ -3162,6 +3165,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;
+@@ -3179,11 +3183,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);
+@@ -3252,27 +3251,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 */
+@@ -3285,12 +3319,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);
+     }
+@@ -3330,7 +3379,7 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
+         PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
+         l = g_list_next(l);
+-        backup_start(NULL, di->bs, NULL, speed, MIRROR_SYNC_MODE_FULL, NULL,
++        backup_start(NULL, di->bs, di->target, 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);
+@@ -3352,8 +3401,17 @@ 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);
+@@ -3367,6 +3425,10 @@ err:
+         unlink(backup_file);
+     }
++    if (backup_dir) {
++        rmdir(backup_dir);
++    }
++
+     return NULL;
+ }
+diff --git a/hmp-commands.hx b/hmp-commands.hx
+index 8f2f3e0..0e20ef9 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.",
+         .mhandler.cmd = hmp_backup,
+     },
+diff --git a/hmp.c b/hmp.c
+index 88cb4e5..c292354 100644
+--- a/hmp.c
++++ b/hmp.c
+@@ -1543,11 +1543,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 89d9ea6..147137d 100644
+--- a/qapi-schema.json
++++ b/qapi-schema.json
+@@ -395,7 +395,7 @@
+ # @vma: Proxmox vma backup format
+ ##
+ { 'enum': 'BackupFormat',
+-  'data': [ 'vma' ] }
++  'data': [ 'vma', 'dir' ] }
+ ##
+ # @backup:
+diff --git a/vma.c b/vma.c
+index 79bdd00..c88a4358 100644
+--- a/vma.c
++++ b/vma.c
+@@ -263,7 +263,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.1.4
+
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
new file mode 100644 (file)
index 0000000..5900420
--- /dev/null
@@ -0,0 +1,77 @@
+From 042b664cc0237d51f188f7feed962df1e8a26910 Mon Sep 17 00:00:00 2001
+From: Wolfgang Bumiller <w.bumiller@proxmox.com>
+Date: Wed, 9 Dec 2015 15:22:19 +0100
+Subject: [PATCH 17/41] 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 d8b1db8..fb71cdc 100644
+--- a/blockdev.c
++++ b/blockdev.c
+@@ -3013,6 +3013,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,
+@@ -3023,7 +3028,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;
+@@ -3031,17 +3035,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)
+@@ -3113,7 +3127,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.1.4
+
diff --git a/debian/patches/pve/0017-backup-vma-add-dir-format.patch b/debian/patches/pve/0017-backup-vma-add-dir-format.patch
deleted file mode 100644 (file)
index f1bf20c..0000000
+++ /dev/null
@@ -1,277 +0,0 @@
-From 0ea55080ddb9b9503dae8c35671a76fa5578572f Mon Sep 17 00:00:00 2001
-From: Wolfgang Bumiller <w.bumiller@proxmox.com>
-Date: Wed, 9 Dec 2015 15:21:54 +0100
-Subject: [PATCH 17/55] backup: vma: add dir format
-
----
- blockdev.c       | 126 +++++++++++++++++++++++++++++++++++++++++--------------
- hmp-commands.hx  |   8 ++--
- hmp.c            |   4 +-
- qapi-schema.json |   2 +-
- 4 files changed, 104 insertions(+), 36 deletions(-)
-
-diff --git a/blockdev.c b/blockdev.c
-index 115524f..0537a53 100644
---- a/blockdev.c
-+++ b/blockdev.c
-@@ -3014,6 +3014,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);
-@@ -3082,8 +3084,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) {
-@@ -3094,8 +3094,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);
-@@ -3174,6 +3177,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;
-@@ -3191,11 +3195,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);
-@@ -3264,27 +3263,63 @@ 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_O_CACHE_WB;
-+            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_new();
-+            if (bdrv_open(&di->target, di->targetfile, NULL, NULL, flags, NULL, &local_err) < 0) {
-+                bdrv_unref(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 */
-@@ -3297,12 +3332,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);
-     }
-@@ -3342,10 +3392,11 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
-         PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
-         l = g_list_next(l);
--        backup_start(di->bs, NULL, speed, MIRROR_SYNC_MODE_FULL, NULL,
-+        backup_start(di->bs, di->target, speed, MIRROR_SYNC_MODE_FULL, NULL,
-                      BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT,
-                      pvebackup_dump_cb, pvebackup_complete_cb, di,
-                      1, &local_err);
-+
-         if (local_err != NULL) {
-             error_setg(&backup_state.error, "backup_job_create failed");
-             pvebackup_cancel(NULL);
-@@ -3364,8 +3415,17 @@ 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);
-@@ -3379,6 +3439,10 @@ err:
-         unlink(backup_file);
-     }
-+    if (backup_dir) {
-+        rmdir(backup_dir);
-+    }
-+
-     return NULL;
- }
-diff --git a/hmp-commands.hx b/hmp-commands.hx
-index 63c44f5..8a94e36 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.",
-         .mhandler.cmd = hmp_backup,
-     },
-diff --git a/hmp.c b/hmp.c
-index 2d4bf97..040909e 100644
---- a/hmp.c
-+++ b/hmp.c
-@@ -1527,11 +1527,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 4f673d4..3427d50 100644
---- a/qapi-schema.json
-+++ b/qapi-schema.json
-@@ -395,7 +395,7 @@
- # @vma: Proxmox vma backup format
- ##
- { 'enum': 'BackupFormat',
--  'data': [ 'vma' ] }
-+  'data': [ 'vma', 'dir' ] }
- ##
- # @backup:
--- 
-2.1.4
-
diff --git a/debian/patches/pve/0018-backup-do-not-return-errors-in-dump-callback.patch b/debian/patches/pve/0018-backup-do-not-return-errors-in-dump-callback.patch
deleted file mode 100644 (file)
index eaff295..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-From 0db7b5b9c1799414788a43c3181c5b965d1b4be7 Mon Sep 17 00:00:00 2001
-From: Wolfgang Bumiller <w.bumiller@proxmox.com>
-Date: Wed, 9 Dec 2015 15:22:19 +0100
-Subject: [PATCH 18/55] 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 0537a53..157cc44 100644
---- a/blockdev.c
-+++ b/blockdev.c
-@@ -3026,6 +3026,11 @@ static int pvebackup_dump_cb(void *opaque, BlockDriverState *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,
-@@ -3036,7 +3041,6 @@ static int pvebackup_dump_cb(void *opaque, BlockDriverState *target,
-     }
-     int64_t cluster_num = sector_num >> 7;
--    int size = n_sectors * BDRV_SECTOR_SIZE;
-     int ret = -1;
-@@ -3044,17 +3048,27 @@ static int pvebackup_dump_cb(void *opaque, BlockDriverState *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)
-@@ -3126,7 +3140,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.1.4
-
diff --git a/debian/patches/pve/0018-backup-vma-correctly-propagate-error.patch b/debian/patches/pve/0018-backup-vma-correctly-propagate-error.patch
new file mode 100644 (file)
index 0000000..033bebc
--- /dev/null
@@ -0,0 +1,57 @@
+From 7f74494cc36b70074bbdf8aaaca7eb7d0ad6c5e5 Mon Sep 17 00:00:00 2001
+From: Wolfgang Bumiller <w.bumiller@proxmox.com>
+Date: Wed, 9 Dec 2015 15:39:36 +0100
+Subject: [PATCH 18/41] 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 fb71cdc..2e51913 100644
+--- a/blockdev.c
++++ b/blockdev.c
+@@ -3037,7 +3037,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 b0cf529..689e988 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 9bb6ea4..98377e4 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.1.4
+
diff --git a/debian/patches/pve/0019-backup-vma-correctly-propagate-error.patch b/debian/patches/pve/0019-backup-vma-correctly-propagate-error.patch
deleted file mode 100644 (file)
index 4e652c6..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-From c6b074069e25ec722879f09672df89a446ef4f0a Mon Sep 17 00:00:00 2001
-From: Wolfgang Bumiller <w.bumiller@proxmox.com>
-Date: Wed, 9 Dec 2015 15:39:36 +0100
-Subject: [PATCH 19/55] 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 157cc44..0ea8189 100644
---- a/blockdev.c
-+++ b/blockdev.c
-@@ -3050,7 +3050,7 @@ static int pvebackup_dump_cb(void *opaque, BlockDriverState *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 8a3fa1c..425c4b9 100644
---- a/vma-writer.c
-+++ b/vma-writer.c
-@@ -798,6 +798,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 9bb6ea4..98377e4 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.1.4
-
diff --git a/debian/patches/pve/0019-backup-vma-remove-async-queue.patch b/debian/patches/pve/0019-backup-vma-remove-async-queue.patch
new file mode 100644 (file)
index 0000000..8baaeb3
--- /dev/null
@@ -0,0 +1,317 @@
+From 12c8cbb8628da0b828492005639bbbd170d26409 Mon Sep 17 00:00:00 2001
+From: Wolfgang Bumiller <w.bumiller@proxmox.com>
+Date: Wed, 9 Dec 2015 15:40:00 +0100
+Subject: [PATCH 19/41] 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 2e51913..1491c2d 100644
+--- a/blockdev.c
++++ b/blockdev.c
+@@ -3116,6 +3116,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();
+@@ -3128,6 +3133,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 689e988..6d3119d 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, vmaw);
++        qemu_coroutine_yield();
++        aio_set_fd_handler(qemu_get_aio_context(), vmaw->fd, false, 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.1.4
+
diff --git a/debian/patches/pve/0020-backup-vma-remove-async-queue.patch b/debian/patches/pve/0020-backup-vma-remove-async-queue.patch
deleted file mode 100644 (file)
index 43f9cb6..0000000
+++ /dev/null
@@ -1,317 +0,0 @@
-From 850534378187f82c34d962d35654dde6a47d956c Mon Sep 17 00:00:00 2001
-From: Wolfgang Bumiller <w.bumiller@proxmox.com>
-Date: Wed, 9 Dec 2015 15:40:00 +0100
-Subject: [PATCH 20/55] 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 0ea8189..55c80c0 100644
---- a/blockdev.c
-+++ b/blockdev.c
-@@ -3129,6 +3129,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();
-@@ -3141,6 +3146,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 425c4b9..2558fe1 100644
---- a/vma-writer.c
-+++ b/vma-writer.c
-@@ -34,14 +34,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;
-@@ -53,16 +47,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;
-@@ -223,38 +215,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, 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, NULL, vma_co_continue_write, vmaw);
-+        qemu_coroutine_yield();
-+        aio_set_fd_handler(qemu_get_aio_context(), vmaw->fd, 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;
-@@ -264,102 +257,9 @@ vma_co_write(VmaWriter *vmaw, const void *buf, size_t bytes)
-         }
-     }
--    aio_set_fd_handler(qemu_get_aio_context(), vmaw->fd, 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)
-@@ -426,20 +326,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);
-@@ -466,8 +362,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;
-@@ -478,7 +373,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 */
-@@ -513,7 +408,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 */
-     }
-@@ -811,13 +706,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) {
-@@ -875,9 +764,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.1.4
-
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
new file mode 100644 (file)
index 0000000..a830c2f
--- /dev/null
@@ -0,0 +1,56 @@
+From e201ffde70d82ae541d7aa14ea16e307fd3b3f76 Mon Sep 17 00:00:00 2001
+From: Wolfgang Bumiller <w.bumiller@proxmox.com>
+Date: Wed, 9 Dec 2015 15:40:42 +0100
+Subject: [PATCH 20/41] 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 1491c2d..f3c0c58 100644
+--- a/blockdev.c
++++ b/blockdev.c
+@@ -3081,6 +3081,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;
+@@ -3098,7 +3105,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 6d3119d..79b7fd4 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.1.4
+
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
new file mode 100644 (file)
index 0000000..e3ce8d2
--- /dev/null
@@ -0,0 +1,36 @@
+From 120827907beae1a28dbdc98e5d3ebf43ce7156da Mon Sep 17 00:00:00 2001
+From: Wolfgang Bumiller <w.bumiller@proxmox.com>
+Date: Wed, 9 Dec 2015 15:41:13 +0100
+Subject: [PATCH 21/41] 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 f3c0c58..2371cf3 100644
+--- a/blockdev.c
++++ b/blockdev.c
+@@ -3129,9 +3129,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;
+@@ -3140,8 +3137,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.1.4
+
diff --git a/debian/patches/pve/0021-backup-vma-run-flush-inside-coroutine.patch b/debian/patches/pve/0021-backup-vma-run-flush-inside-coroutine.patch
deleted file mode 100644 (file)
index a1a9a7b..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-From 60e4cc553c6ed53dd86e91ac143ad3aa8edcdbe7 Mon Sep 17 00:00:00 2001
-From: Wolfgang Bumiller <w.bumiller@proxmox.com>
-Date: Wed, 9 Dec 2015 15:40:42 +0100
-Subject: [PATCH 21/55] 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 55c80c0..2c51b95 100644
---- a/blockdev.c
-+++ b/blockdev.c
-@@ -3094,6 +3094,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;
-@@ -3111,7 +3118,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);
-+        qemu_coroutine_enter(co, di);
-     }
-     block_job_cb(bs, ret);
-diff --git a/vma-writer.c b/vma-writer.c
-index 2558fe1..3c77e98 100644
---- a/vma-writer.c
-+++ b/vma-writer.c
-@@ -706,6 +706,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.1.4
-
diff --git a/debian/patches/pve/0022-backup-do-not-use-bdrv_drain_all.patch b/debian/patches/pve/0022-backup-do-not-use-bdrv_drain_all.patch
deleted file mode 100644 (file)
index 7c84955..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-From 5848b90ad434c9c697e32cdd00a34708cfce24c5 Mon Sep 17 00:00:00 2001
-From: Wolfgang Bumiller <w.bumiller@proxmox.com>
-Date: Wed, 9 Dec 2015 15:41:13 +0100
-Subject: [PATCH 22/55] 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 2c51b95..0131e92 100644
---- a/blockdev.c
-+++ b/blockdev.c
-@@ -3142,9 +3142,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;
-@@ -3153,8 +3150,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.1.4
-
diff --git a/debian/patches/pve/0022-internal-snapshot-async.patch b/debian/patches/pve/0022-internal-snapshot-async.patch
new file mode 100644 (file)
index 0000000..6dfb8a3
--- /dev/null
@@ -0,0 +1,1000 @@
+From 3c93adeb6d594c56619fd34dc345dffa3139c2cb Mon Sep 17 00:00:00 2001
+From: Wolfgang Bumiller <w.bumiller@proxmox.com>
+Date: Wed, 9 Dec 2015 16:04:32 +0100
+Subject: [PATCH 22/41] internal snapshot async
+
+---
+ Makefile.objs           |   1 +
+ block.c                 |   2 +-
+ hmp-commands-info.hx    |  13 ++
+ hmp-commands.hx         |  32 +++
+ hmp.c                   |  57 ++++++
+ hmp.h                   |   5 +
+ include/block/block.h   |   1 +
+ include/sysemu/sysemu.h |   5 +-
+ migration/savevm.c      |  12 +-
+ qapi-schema.json        |  46 +++++
+ qemu-options.hx         |  13 ++
+ qmp-commands.hx         |  30 +++
+ savevm-async.c          | 526 ++++++++++++++++++++++++++++++++++++++++++++++++
+ vl.c                    |   8 +
+ 14 files changed, 743 insertions(+), 8 deletions(-)
+ create mode 100644 savevm-async.c
+
+diff --git a/Makefile.objs b/Makefile.objs
+index 845edd0..7d9d2d7 100644
+--- a/Makefile.objs
++++ b/Makefile.objs
+@@ -53,6 +53,7 @@ common-obj-$(CONFIG_LINUX) += fsdev/
+ common-obj-y += migration/
+ common-obj-y += qemu-char.o #aio.o
+ common-obj-y += page_cache.o
++common-obj-y += savevm-async.o
+ common-obj-$(CONFIG_SPICE) += spice-qemu-char.o
+diff --git a/block.c b/block.c
+index 30d64e6..95c1d32 100644
+--- a/block.c
++++ b/block.c
+@@ -2288,7 +2288,7 @@ void bdrv_replace_in_backing_chain(BlockDriverState *old, BlockDriverState *new)
+     bdrv_unref(old);
+ }
+-static void bdrv_delete(BlockDriverState *bs)
++void bdrv_delete(BlockDriverState *bs)
+ {
+     assert(!bs->job);
+     assert(bdrv_op_blocker_is_empty(bs));
+diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
+index 7616fe2..3046f9d 100644
+--- a/hmp-commands-info.hx
++++ b/hmp-commands-info.hx
+@@ -588,6 +588,19 @@ Show current migration xbzrle cache size.
+ ETEXI
+     {
++        .name       = "savevm",
++        .args_type  = "",
++        .params     = "",
++        .help       = "show savevm status",
++        .mhandler.cmd = hmp_info_savevm,
++    },
++
++STEXI
++@item info savevm
++show savevm status
++ETEXI
++
++    {
+         .name       = "balloon",
+         .args_type  = "",
+         .params     = "",
+diff --git a/hmp-commands.hx b/hmp-commands.hx
+index 0e20ef9..4d735cb 100644
+--- a/hmp-commands.hx
++++ b/hmp-commands.hx
+@@ -1791,3 +1791,35 @@ ETEXI
+ STEXI
+ @end table
+ ETEXI
++
++    {
++        .name       = "savevm-start",
++        .args_type  = "statefile:s?",
++        .params     = "[statefile]",
++        .help       = "Prepare for snapshot and halt VM. Save VM state to statefile.",
++        .mhandler.cmd = hmp_savevm_start,
++    },
++
++    {
++        .name       = "snapshot-drive",
++        .args_type  = "device:s,name:s",
++        .params     = "device name",
++        .help       = "Create internal snapshot.",
++        .mhandler.cmd = hmp_snapshot_drive,
++    },
++
++    {
++        .name       = "delete-drive-snapshot",
++        .args_type  = "device:s,name:s",
++        .params     = "device name",
++        .help       = "Delete internal snapshot.",
++        .mhandler.cmd = hmp_delete_drive_snapshot,
++    },
++
++    {
++        .name       = "savevm-end",
++        .args_type  = "",
++        .params     = "",
++        .help       = "Resume VM after snaphot.",
++        .mhandler.cmd = hmp_savevm_end,
++    },
+diff --git a/hmp.c b/hmp.c
+index c292354..7bd319f 100644
+--- a/hmp.c
++++ b/hmp.c
+@@ -2116,6 +2116,63 @@ void hmp_info_memory_devices(Monitor *mon, const QDict *qdict)
+     qapi_free_MemoryDeviceInfoList(info_list);
+ }
++void hmp_savevm_start(Monitor *mon, const QDict *qdict)
++{
++    Error *errp = NULL;
++    const char *statefile = qdict_get_try_str(qdict, "statefile");
++
++    qmp_savevm_start(statefile != NULL, statefile, &errp);
++    hmp_handle_error(mon, &errp);
++}
++
++void hmp_snapshot_drive(Monitor *mon, const QDict *qdict)
++{
++    Error *errp = NULL;
++    const char *name = qdict_get_str(qdict, "name");
++    const char *device = qdict_get_str(qdict, "device");
++
++    qmp_snapshot_drive(device, name, &errp);
++    hmp_handle_error(mon, &errp);
++}
++
++void hmp_delete_drive_snapshot(Monitor *mon, const QDict *qdict)
++{
++    Error *errp = NULL;
++    const char *name = qdict_get_str(qdict, "name");
++    const char *device = qdict_get_str(qdict, "device");
++
++    qmp_delete_drive_snapshot(device, name, &errp);
++    hmp_handle_error(mon, &errp);
++}
++
++void hmp_savevm_end(Monitor *mon, const QDict *qdict)
++{
++    Error *errp = NULL;
++
++    qmp_savevm_end(&errp);
++    hmp_handle_error(mon, &errp);
++}
++
++void hmp_info_savevm(Monitor *mon, const QDict *qdict)
++{
++    SaveVMInfo *info;
++    info = qmp_query_savevm(NULL);
++
++    if (info->has_status) {
++        monitor_printf(mon, "savevm status: %s\n", info->status);
++        monitor_printf(mon, "total time: %" PRIu64 " milliseconds\n",
++                       info->total_time);
++    } else {
++        monitor_printf(mon, "savevm status: not running\n");
++    }
++    if (info->has_bytes) {
++        monitor_printf(mon, "Bytes saved: %"PRIu64"\n", info->bytes);
++    }
++    if (info->has_error) {
++        monitor_printf(mon, "Error: %s\n", info->error);
++    }
++}
++
+ void hmp_info_iothreads(Monitor *mon, const QDict *qdict)
+ {
+     IOThreadInfoList *info_list = qmp_query_iothreads(NULL);
+diff --git a/hmp.h b/hmp.h
+index 9a4c1f6..b74ddbf 100644
+--- a/hmp.h
++++ b/hmp.h
+@@ -26,6 +26,7 @@ void hmp_info_status(Monitor *mon, const QDict *qdict);
+ void hmp_info_uuid(Monitor *mon, const QDict *qdict);
+ void hmp_info_chardev(Monitor *mon, const QDict *qdict);
+ void hmp_info_mice(Monitor *mon, const QDict *qdict);
++void hmp_info_savevm(Monitor *mon, const QDict *qdict);
+ 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);
+@@ -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);
++void hmp_savevm_start(Monitor *mon, const QDict *qdict);
++void hmp_snapshot_drive(Monitor *mon, const QDict *qdict);
++void hmp_delete_drive_snapshot(Monitor *mon, const QDict *qdict);
++void hmp_savevm_end(Monitor *mon, const QDict *qdict);
+ void hmp_sendkey(Monitor *mon, const QDict *qdict);
+ void hmp_screendump(Monitor *mon, const QDict *qdict);
+ void hmp_nbd_server_start(Monitor *mon, const QDict *qdict);
+diff --git a/include/block/block.h b/include/block/block.h
+index 11c162d..6822b91 100644
+--- a/include/block/block.h
++++ b/include/block/block.h
+@@ -256,6 +256,7 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
+ int bdrv_get_backing_file_depth(BlockDriverState *bs);
+ void bdrv_refresh_filename(BlockDriverState *bs);
+ int bdrv_truncate(BlockDriverState *bs, int64_t offset);
++void bdrv_delete(BlockDriverState *bs);
+ int64_t bdrv_nb_sectors(BlockDriverState *bs);
+ int64_t bdrv_getlength(BlockDriverState *bs);
+ int64_t bdrv_get_allocated_file_size(BlockDriverState *bs);
+diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
+index ee7c760..4875441 100644
+--- a/include/sysemu/sysemu.h
++++ b/include/sysemu/sysemu.h
+@@ -79,6 +79,7 @@ void qemu_remove_machine_init_done_notifier(Notifier *notify);
+ void hmp_savevm(Monitor *mon, const QDict *qdict);
+ int load_vmstate(const char *name);
++int load_state_from_blockdev(const char *filename);
+ void hmp_delvm(Monitor *mon, const QDict *qdict);
+ void hmp_info_snapshots(Monitor *mon, const QDict *qdict);
+@@ -106,13 +107,13 @@ enum qemu_vm_cmd {
+ #define MAX_VM_CMD_PACKAGED_SIZE (1ul << 24)
+ bool qemu_savevm_state_blocked(Error **errp);
+-void qemu_savevm_state_begin(QEMUFile *f,
++int qemu_savevm_state_begin(QEMUFile *f,
+                              const MigrationParams *params);
+ void qemu_savevm_state_header(QEMUFile *f);
+ int qemu_savevm_state_iterate(QEMUFile *f, bool postcopy);
+ void qemu_savevm_state_cleanup(void);
+ void qemu_savevm_state_complete_postcopy(QEMUFile *f);
+-void qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only);
++int qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only);
+ void qemu_savevm_state_pending(QEMUFile *f, uint64_t max_size,
+                                uint64_t *res_non_postcopiable,
+                                uint64_t *res_postcopiable);
+diff --git a/migration/savevm.c b/migration/savevm.c
+index 33a2911..b1bdfb6 100644
+--- a/migration/savevm.c
++++ b/migration/savevm.c
+@@ -879,11 +879,11 @@ void qemu_savevm_state_header(QEMUFile *f)
+ }
+-void qemu_savevm_state_begin(QEMUFile *f,
++int qemu_savevm_state_begin(QEMUFile *f,
+                              const MigrationParams *params)
+ {
+     SaveStateEntry *se;
+-    int ret;
++    int ret = 0;
+     trace_savevm_state_begin();
+     QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
+@@ -911,6 +911,7 @@ void qemu_savevm_state_begin(QEMUFile *f,
+             break;
+         }
+     }
++    return ret;
+ }
+ /*
+@@ -1014,7 +1015,7 @@ void qemu_savevm_state_complete_postcopy(QEMUFile *f)
+     qemu_fflush(f);
+ }
+-void qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only)
++int qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only)
+ {
+     QJSON *vmdesc;
+     int vmdesc_len;
+@@ -1048,12 +1049,12 @@ void qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only)
+         save_section_footer(f, se);
+         if (ret < 0) {
+             qemu_file_set_error(f, ret);
+-            return;
++            return ret;
+         }
+     }
+     if (iterable_only) {
+-        return;
++        return ret;
+     }
+     vmdesc = qjson_new();
+@@ -1100,6 +1101,7 @@ void qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only)
+     qjson_destroy(vmdesc);
+     qemu_fflush(f);
++    return qemu_file_get_error(f);
+ }
+ /* Give an estimate of the amount left to be transferred,
+diff --git a/qapi-schema.json b/qapi-schema.json
+index 147137d..0c0faf7 100644
+--- a/qapi-schema.json
++++ b/qapi-schema.json
+@@ -594,6 +594,42 @@
+            '*cpu-throttle-percentage': 'int',
+            '*error-desc': 'str'} }
++
++# @SaveVMInfo
++#
++# Information about current migration process.
++#
++# @status: #optional string describing the current savevm status.
++#          This can be 'active', 'completed', 'failed'.
++#          If this field is not returned, no savevm process
++#          has been initiated
++#
++# @error: #optional string containing error message is status is failed.
++#
++# @total-time: #optional total amount of milliseconds since savevm started.
++#        If savevm has ended, it returns the total save time
++#
++# @bytes: #optional total amount of data transfered
++#
++# Since: 1.3
++##
++{ 'struct': 'SaveVMInfo',
++  'data': {'*status': 'str', '*error': 'str',
++           '*total-time': 'int', '*bytes': 'int'} }
++
++##
++# @query-savevm
++#
++# Returns information about current savevm process.
++#
++# Returns: @SaveVMInfo
++#
++# Since: 1.3
++##
++{ 'command': 'query-savevm', 'returns': 'SaveVMInfo' }
++
++##
++
+ ##
+ # @query-migrate
+ #
+@@ -3286,8 +3322,18 @@
+ #
+ # Since: 1.2.0
+ ##
++
+ { 'command': 'query-target', 'returns': 'TargetInfo' }
++{ 'command': 'savevm-start', 'data': { '*statefile': 'str' } }
++
++{ 'command': 'snapshot-drive', 'data': { 'device': 'str', 'name': 'str' } }
++
++{ 'command': 'delete-drive-snapshot', 'data': { 'device': 'str', 'name': 'str' } }
++
++{ 'command': 'savevm-end' }
++
++
+ ##
+ # @QKeyCode:
+ #
+diff --git a/qemu-options.hx b/qemu-options.hx
+index a71aaf8..37fad3b 100644
+--- a/qemu-options.hx
++++ b/qemu-options.hx
+@@ -3302,6 +3302,19 @@ STEXI
+ Start right away with a saved state (@code{loadvm} in monitor)
+ ETEXI
++DEF("loadstate", HAS_ARG, QEMU_OPTION_loadstate, \
++    "-loadstate file\n" \
++    "                start right away with a saved state\n",
++    QEMU_ARCH_ALL)
++STEXI
++@item -loadstate @var{file}
++@findex -loadstate
++Start right away with a saved state. This option does not rollback
++disk state like @code{loadvm}, so user must make sure that disk
++have correct state. @var{file} can be any valid device URL. See the section
++for "Device URL Syntax" for more information.
++ETEXI
++
+ #ifndef _WIN32
+ DEF("daemonize", 0, QEMU_OPTION_daemonize, \
+     "-daemonize      daemonize QEMU after initializing\n", QEMU_ARCH_ALL)
+diff --git a/qmp-commands.hx b/qmp-commands.hx
+index a8e8522..6342cd2 100644
+--- a/qmp-commands.hx
++++ b/qmp-commands.hx
+@@ -4904,6 +4904,36 @@ Example:
+ EQMP
+     {
++        .name       = "savevm-start",
++        .args_type  = "statefile:s?",
++        .mhandler.cmd_new = qmp_marshal_savevm_start,
++    },
++
++    {
++        .name       = "snapshot-drive",
++        .args_type  = "device:s,name:s",
++        .mhandler.cmd_new = qmp_marshal_snapshot_drive,
++    },
++
++    {
++        .name       = "delete-drive-snapshot",
++        .args_type  = "device:s,name:s",
++        .mhandler.cmd_new = qmp_marshal_delete_drive_snapshot,
++    },
++
++    {
++        .name       = "savevm-end",
++        .args_type  = "",
++        .mhandler.cmd_new = qmp_marshal_savevm_end,
++    },
++
++    {
++        .name       = "query-savevm",
++        .args_type  = "",
++        .mhandler.cmd_new = qmp_marshal_query_savevm,
++    },
++
++    {
+         .name       = "query-rocker",
+         .args_type  = "name:s",
+         .mhandler.cmd_new = qmp_marshal_query_rocker,
+diff --git a/savevm-async.c b/savevm-async.c
+new file mode 100644
+index 0000000..ae7ea84
+--- /dev/null
++++ b/savevm-async.c
+@@ -0,0 +1,526 @@
++#include "qemu/osdep.h"
++#include "qemu-common.h"
++#include "qapi/qmp/qerror.h"
++#include "qemu/error-report.h"
++#include "sysemu/sysemu.h"
++#include "qmp-commands.h"
++#include "qemu-options.h"
++#include "migration/qemu-file.h"
++#include "qom/qom-qobject.h"
++#include "migration/migration.h"
++#include "block/snapshot.h"
++#include "block/qapi.h"
++#include "block/block.h"
++#include "qemu/timer.h"
++#include "sysemu/block-backend.h"
++#include "qapi/qmp/qstring.h"
++#include "qemu/rcu.h"
++#include "qemu/thread.h"
++#include "qemu/cutils.h"
++
++/* #define DEBUG_SAVEVM_STATE */
++
++#ifdef DEBUG_SAVEVM_STATE
++#define DPRINTF(fmt, ...) \
++    do { printf("savevm-async: " fmt, ## __VA_ARGS__); } while (0)
++#else
++#define DPRINTF(fmt, ...) \
++    do { } while (0)
++#endif
++
++enum {
++    SAVE_STATE_DONE,
++    SAVE_STATE_ERROR,
++    SAVE_STATE_ACTIVE,
++    SAVE_STATE_COMPLETED,
++    SAVE_STATE_CANCELLED
++};
++
++
++static struct SnapshotState {
++    BlockDriverState *bs;
++    size_t bs_pos;
++    int state;
++    Error *error;
++    Error *blocker;
++    int saved_vm_running;
++    QEMUFile *file;
++    int64_t total_time;
++} snap_state;
++
++SaveVMInfo *qmp_query_savevm(Error **errp)
++{
++    SaveVMInfo *info = g_malloc0(sizeof(*info));
++    struct SnapshotState *s = &snap_state;
++
++    if (s->state != SAVE_STATE_DONE) {
++        info->has_bytes = true;
++        info->bytes = s->bs_pos;
++        switch (s->state) {
++        case SAVE_STATE_ERROR:
++            info->has_status = true;
++            info->status = g_strdup("failed");
++            info->has_total_time = true;
++            info->total_time = s->total_time;
++            if (s->error) {
++                info->has_error = true;
++                info->error = g_strdup(error_get_pretty(s->error));
++            }
++            break;
++        case SAVE_STATE_ACTIVE:
++            info->has_status = true;
++            info->status = g_strdup("active");
++            info->has_total_time = true;
++            info->total_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME)
++                - s->total_time;
++            break;
++        case SAVE_STATE_COMPLETED:
++            info->has_status = true;
++            info->status = g_strdup("completed");
++            info->has_total_time = true;
++            info->total_time = s->total_time;
++            break;
++        }
++    }
++
++    return info;
++}
++
++static int save_snapshot_cleanup(void)
++{
++    int ret = 0;
++
++    DPRINTF("save_snapshot_cleanup\n");
++
++    snap_state.total_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) -
++        snap_state.total_time;
++
++    if (snap_state.file) {
++        ret = qemu_fclose(snap_state.file);
++    }
++
++    if (snap_state.bs) {
++        /* 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);
++        error_free(snap_state.blocker);
++        snap_state.blocker = NULL;
++        bdrv_unref(snap_state.bs);
++        snap_state.bs = NULL;
++    }
++
++    return ret;
++}
++
++static void save_snapshot_error(const char *fmt, ...)
++{
++    va_list ap;
++    char *msg;
++
++    va_start(ap, fmt);
++    msg = g_strdup_vprintf(fmt, ap);
++    va_end(ap);
++
++    DPRINTF("save_snapshot_error: %s\n", msg);
++
++    if (!snap_state.error) {
++        error_set(&snap_state.error, ERROR_CLASS_GENERIC_ERROR, "%s", msg);
++    }
++
++    g_free (msg);
++
++    snap_state.state = SAVE_STATE_ERROR;
++
++    save_snapshot_cleanup();
++}
++
++static void save_snapshot_completed(void)
++{
++    DPRINTF("save_snapshot_completed\n");
++
++    if (save_snapshot_cleanup() < 0) {
++        snap_state.state = SAVE_STATE_ERROR;
++    } else {
++        snap_state.state = SAVE_STATE_COMPLETED;
++    }
++}
++
++static int block_state_close(void *opaque)
++{
++    snap_state.file = NULL;
++    return bdrv_flush(snap_state.bs);
++}
++
++static int block_state_put_buffer(void *opaque, const uint8_t *buf,
++                                  int64_t pos, int size)
++{
++    int ret;
++
++    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;
++    }
++
++    return ret;
++}
++
++static int store_and_stop(void) {
++    if (global_state_store()) {
++        save_snapshot_error("Error saving global state");
++        return 1;
++    }
++    if (runstate_is_running()) {
++        vm_stop(RUN_STATE_SAVE_VM);
++    }
++    return 0;
++}
++
++static void process_savevm_co(void *opaque)
++{
++    int ret;
++    int64_t maxlen;
++    MigrationParams params = {
++        .blk = 0,
++        .shared = 0
++    };
++
++    snap_state.state = SAVE_STATE_ACTIVE;
++
++    qemu_mutex_unlock_iothread();
++    qemu_savevm_state_header(snap_state.file);
++    ret = qemu_savevm_state_begin(snap_state.file, &params);
++    qemu_mutex_lock_iothread();
++
++    if (ret < 0) {
++        save_snapshot_error("qemu_savevm_state_begin failed");
++        return;
++    }
++
++    while (snap_state.state == SAVE_STATE_ACTIVE) {
++        uint64_t pending_size;
++
++        pending_size = qemu_savevm_state_pending(snap_state.file, 0);
++
++        if (pending_size) {
++                ret = qemu_savevm_state_iterate(snap_state.file);
++                if (ret < 0) {
++                    save_snapshot_error("qemu_savevm_state_iterate error %d", ret);
++                    break;
++                }
++                DPRINTF("savevm inerate pending size %lu ret %d\n", pending_size, ret);
++        } else {
++            DPRINTF("done iterating\n");
++            if (store_and_stop())
++                break;
++            DPRINTF("savevm inerate finished\n");
++            qemu_savevm_state_complete_precopy(snap_state.file);
++            DPRINTF("save complete\n");
++            save_snapshot_completed();
++            break;
++        }
++
++        /* 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;
++        if ((pending_size < 100000) ||
++            ((snap_state.bs_pos + pending_size) >= maxlen)) {
++            if (store_and_stop())
++                break;
++        }
++    }
++
++    if(snap_state.state == SAVE_STATE_CANCELLED) {
++        save_snapshot_completed();
++        Error *errp = NULL;
++        qmp_savevm_end(&errp);
++    }
++
++}
++
++static const QEMUFileOps block_file_ops = {
++    .put_buffer =     block_state_put_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;
++    int ret;
++
++    if (snap_state.state != SAVE_STATE_DONE) {
++        error_set(errp, ERROR_CLASS_GENERIC_ERROR,
++                  "VM snapshot already started\n");
++        return;
++    }
++
++    /* initialize snapshot info */
++    snap_state.saved_vm_running = runstate_is_running();
++    snap_state.bs_pos = 0;
++    snap_state.total_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
++    snap_state.blocker = NULL;
++
++    if (snap_state.error) {
++        error_free(snap_state.error);
++        snap_state.error = NULL;
++    }
++
++    if (!has_statefile) {
++        vm_stop(RUN_STATE_SAVE_VM);
++        snap_state.state = SAVE_STATE_COMPLETED;
++        return;
++    }
++
++    if (qemu_savevm_state_blocked(errp)) {
++        return;
++    }
++
++    /* 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) {
++        error_set(errp, ERROR_CLASS_GENERIC_ERROR, "failed to open '%s'", statefile);
++        goto restart;
++    }
++
++    snap_state.file = qemu_fopen_ops(&snap_state, &block_file_ops);
++
++    if (!snap_state.file) {
++        error_set(errp, ERROR_CLASS_GENERIC_ERROR, "failed to open '%s'", statefile);
++        goto restart;
++    }
++
++
++    error_setg(&snap_state.blocker, "block device is in use by savevm");
++    bdrv_op_block_all(snap_state.bs, snap_state.blocker);
++
++    Coroutine *co = qemu_coroutine_create(process_savevm_co);
++    qemu_coroutine_enter(co);
++
++    return;
++
++restart:
++
++    save_snapshot_error("setup failed");
++
++    if (snap_state.saved_vm_running) {
++        vm_start();
++    }
++}
++
++void qmp_savevm_end(Error **errp)
++{
++    if (snap_state.state == SAVE_STATE_DONE) {
++        error_set(errp, ERROR_CLASS_GENERIC_ERROR,
++                  "VM snapshot not started\n");
++        return;
++    }
++
++    if (snap_state.state == SAVE_STATE_ACTIVE) {
++        snap_state.state = SAVE_STATE_CANCELLED;
++        return;
++    }
++
++    if (snap_state.saved_vm_running) {
++        vm_start();
++    }
++
++    snap_state.state = SAVE_STATE_DONE;
++}
++
++void qmp_snapshot_drive(const char *device, const char *name, Error **errp)
++{
++    BlockBackend *blk;
++    BlockDriverState *bs;
++    QEMUSnapshotInfo sn1, *sn = &sn1;
++    int ret;
++#ifdef _WIN32
++    struct _timeb tb;
++#else
++    struct timeval tv;
++#endif
++
++    if (snap_state.state != SAVE_STATE_COMPLETED) {
++        error_set(errp, ERROR_CLASS_GENERIC_ERROR,
++                  "VM snapshot not ready/started\n");
++        return;
++    }
++
++    blk = blk_by_name(device);
++    if (!blk) {
++        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
++                  "Device '%s' not found", device);
++        return;
++    }
++
++    bs = blk_bs(blk);
++    if (!bdrv_is_inserted(bs)) {
++        error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
++        return;
++    }
++
++    if (bdrv_is_read_only(bs)) {
++        error_setg(errp, "Node '%s' is read only", device);
++        return;
++    }
++
++    if (!bdrv_can_snapshot(bs)) {
++        error_setg(errp, QERR_UNSUPPORTED);
++        return;
++    }
++
++    if (bdrv_snapshot_find(bs, sn, name) >= 0) {
++        error_set(errp, ERROR_CLASS_GENERIC_ERROR,
++                  "snapshot '%s' already exists", name);
++        return;
++    }
++
++    sn = &sn1;
++    memset(sn, 0, sizeof(*sn));
++
++#ifdef _WIN32
++    _ftime(&tb);
++    sn->date_sec = tb.time;
++    sn->date_nsec = tb.millitm * 1000000;
++#else
++    gettimeofday(&tv, NULL);
++    sn->date_sec = tv.tv_sec;
++    sn->date_nsec = tv.tv_usec * 1000;
++#endif
++    sn->vm_clock_nsec = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
++
++    pstrcpy(sn->name, sizeof(sn->name), name);
++
++    sn->vm_state_size = 0; /* do not save state */
++
++    ret = bdrv_snapshot_create(bs, sn);
++    if (ret < 0) {
++        error_set(errp, ERROR_CLASS_GENERIC_ERROR,
++                  "Error while creating snapshot on '%s'\n", device);
++        return;
++    }
++}
++
++void qmp_delete_drive_snapshot(const char *device, const char *name,
++                               Error **errp)
++{
++    BlockBackend *blk;
++    BlockDriverState *bs;
++    QEMUSnapshotInfo sn1, *sn = &sn1;
++    Error *local_err = NULL;
++
++    int ret;
++
++    blk = blk_by_name(device);
++    if (!blk) {
++        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
++                  "Device '%s' not found", device);
++        return;
++    }
++
++    bs = blk_bs(blk);
++    if (bdrv_is_read_only(bs)) {
++        error_setg(errp, "Node '%s' is read only", device);
++        return;
++    }
++
++    if (!bdrv_can_snapshot(bs)) {
++        error_setg(errp, QERR_UNSUPPORTED);
++        return;
++    }
++
++    if (bdrv_snapshot_find(bs, sn, name) < 0) {
++        /* return success if snapshot does not exists */
++        return;
++    }
++
++    ret = bdrv_snapshot_delete(bs, NULL, name, &local_err);
++    if (ret < 0) {
++        error_set(errp, ERROR_CLASS_GENERIC_ERROR,
++                  "Error while deleting snapshot on '%s'\n", device);
++        return;
++    }
++}
++
++static int loadstate_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
++                                int size)
++{
++    BlockDriverState *bs = (BlockDriverState *)opaque;
++    int64_t maxlen = bdrv_getlength(bs);
++    if (pos > maxlen) {
++        return -EIO;
++    }
++    if ((pos + size) > maxlen) {
++        size = maxlen - pos - 1;
++    }
++    if (size == 0) {
++        return 0;
++    }
++    return bdrv_pread(bs, pos, buf, size);
++}
++
++static const QEMUFileOps loadstate_file_ops = {
++    .get_buffer = loadstate_get_buffer,
++};
++
++int load_state_from_blockdev(const char *filename)
++{
++    BlockDriverState *bs = NULL;
++    BlockDriver *drv = NULL;
++    Error *local_err = NULL;
++    Error *blocker = NULL;
++
++    QEMUFile *f;
++    int ret;
++
++    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);
++
++    if (ret < 0) {
++        error_report("Could not open VM state file");
++        goto the_end;
++    }
++
++    /* restore the VM state */
++    f = qemu_fopen_ops(bs, &loadstate_file_ops);
++    if (!f) {
++        error_report("Could not open VM state file");
++        ret = -EINVAL;
++        goto the_end;
++    }
++
++    qemu_system_reset(VMRESET_SILENT);
++    migration_incoming_state_new(f);
++    ret = qemu_loadvm_state(f);
++
++    qemu_fclose(f);
++    migration_incoming_state_destroy();
++    if (ret < 0) {
++        error_report("Error %d while loading VM state", ret);
++        goto the_end;
++    }
++
++    ret = 0;
++
++ the_end:
++    if (bs) {
++        bdrv_op_unblock_all(bs, blocker);
++        error_free(blocker);
++        bdrv_unref(bs);
++    }
++    return ret;
++}
+diff --git a/vl.c b/vl.c
+index bdf4fdc..85033e3 100644
+--- a/vl.c
++++ b/vl.c
+@@ -2948,6 +2948,7 @@ int main(int argc, char **argv, char **envp)
+     int optind;
+     const char *optarg;
+     const char *loadvm = NULL;
++    const char *loadstate = NULL;
+     MachineClass *machine_class;
+     const char *cpu_model;
+     const char *vga_model = NULL;
+@@ -3589,6 +3590,9 @@ int main(int argc, char **argv, char **envp)
+             case QEMU_OPTION_loadvm:
+                 loadvm = optarg;
+                 break;
++            case QEMU_OPTION_loadstate:
++                loadstate = optarg;
++                break;
+             case QEMU_OPTION_full_screen:
+                 full_screen = 1;
+                 break;
+@@ -4583,6 +4587,10 @@ int main(int argc, char **argv, char **envp)
+         if (load_vmstate(loadvm) < 0) {
+             autostart = 0;
+         }
++    } else if (loadstate) {
++        if (load_state_from_blockdev(loadstate) < 0) {
++            autostart = 0;
++        }
+     }
+     qdev_prop_check_globals();
+-- 
+2.1.4
+
diff --git a/debian/patches/pve/0023-backup-vma-allow-empty-backups.patch b/debian/patches/pve/0023-backup-vma-allow-empty-backups.patch
new file mode 100644 (file)
index 0000000..79df37a
--- /dev/null
@@ -0,0 +1,256 @@
+From 4e3757e9cb0235a3ff0093f982dc3a2b4f4bdfe4 Mon Sep 17 00:00:00 2001
+From: Wolfgang Bumiller <w.bumiller@proxmox.com>
+Date: Wed, 9 Dec 2015 16:31:51 +0100
+Subject: [PATCH 23/41] 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 2aafb26..78f1de9 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 79b7fd4..0d26fc6 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 c88a4358..08e4725 100644
+--- a/vma.c
++++ b/vma.c
+@@ -27,7 +27,7 @@ static void help(void)
+         "\n"
+         "vma list <filename>\n"
+         "vma config <filename> [-c config]\n"
+-        "vma create <filename> [-c config] <archive> pathname ...\n"
++        "vma create <filename> [-c config] pathname ...\n"
+         "vma extract <filename> [-r <fifo>] <targetdir>\n"
+         "vma verify <filename> [-v]\n"
+         ;
+@@ -395,6 +395,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;
+@@ -468,8 +480,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();
+     }
+@@ -504,11 +516,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;
+@@ -539,37 +551,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 98377e4..365ceb2 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.1.4
+
diff --git a/debian/patches/pve/0023-internal-snapshot-async.patch b/debian/patches/pve/0023-internal-snapshot-async.patch
deleted file mode 100644 (file)
index 0a51416..0000000
+++ /dev/null
@@ -1,996 +0,0 @@
-From a53c35c25e703bc08198ec6ee02a86c79dae8aaa Mon Sep 17 00:00:00 2001
-From: Wolfgang Bumiller <w.bumiller@proxmox.com>
-Date: Wed, 9 Dec 2015 16:04:32 +0100
-Subject: [PATCH 23/55] internal snapshot async
-
----
- Makefile.objs           |   1 +
- block.c                 |   2 +-
- hmp-commands-info.hx    |  13 ++
- hmp-commands.hx         |  32 +++
- hmp.c                   |  57 ++++++
- hmp.h                   |   5 +
- include/block/block.h   |   1 +
- include/sysemu/sysemu.h |   5 +-
- migration/savevm.c      |  12 +-
- qapi-schema.json        |  46 +++++
- qemu-options.hx         |  13 ++
- qmp-commands.hx         |  30 +++
- savevm-async.c          | 522 ++++++++++++++++++++++++++++++++++++++++++++++++
- vl.c                    |   8 +
- 14 files changed, 739 insertions(+), 8 deletions(-)
- create mode 100644 savevm-async.c
-
-diff --git a/Makefile.objs b/Makefile.objs
-index 5fd0bc4..c3367dd 100644
---- a/Makefile.objs
-+++ b/Makefile.objs
-@@ -54,6 +54,7 @@ common-obj-y += migration/
- common-obj-y += qemu-char.o #aio.o
- common-obj-y += page_cache.o
- common-obj-y += qjson.o
-+common-obj-y += savevm-async.o
- common-obj-$(CONFIG_SPICE) += spice-qemu-char.o
-diff --git a/block.c b/block.c
-index d4939b4..bee5a8d 100644
---- a/block.c
-+++ b/block.c
-@@ -2332,7 +2332,7 @@ void bdrv_replace_in_backing_chain(BlockDriverState *old, BlockDriverState *new)
-     bdrv_unref(old);
- }
--static void bdrv_delete(BlockDriverState *bs)
-+void bdrv_delete(BlockDriverState *bs)
- {
-     assert(!bs->job);
-     assert(bdrv_op_blocker_is_empty(bs));
-diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
-index f872262..c213ef7 100644
---- a/hmp-commands-info.hx
-+++ b/hmp-commands-info.hx
-@@ -588,6 +588,19 @@ Show current migration xbzrle cache size.
- ETEXI
-     {
-+        .name       = "savevm",
-+        .args_type  = "",
-+        .params     = "",
-+        .help       = "show savevm status",
-+        .mhandler.cmd = hmp_info_savevm,
-+    },
-+
-+STEXI
-+@item info savevm
-+show savevm status
-+ETEXI
-+
-+    {
-         .name       = "balloon",
-         .args_type  = "",
-         .params     = "",
-diff --git a/hmp-commands.hx b/hmp-commands.hx
-index 8a94e36..2c0009a 100644
---- a/hmp-commands.hx
-+++ b/hmp-commands.hx
-@@ -1790,3 +1790,35 @@ ETEXI
- STEXI
- @end table
- ETEXI
-+
-+    {
-+        .name       = "savevm-start",
-+        .args_type  = "statefile:s?",
-+        .params     = "[statefile]",
-+        .help       = "Prepare for snapshot and halt VM. Save VM state to statefile.",
-+        .mhandler.cmd = hmp_savevm_start,
-+    },
-+
-+    {
-+        .name       = "snapshot-drive",
-+        .args_type  = "device:s,name:s",
-+        .params     = "device name",
-+        .help       = "Create internal snapshot.",
-+        .mhandler.cmd = hmp_snapshot_drive,
-+    },
-+
-+    {
-+        .name       = "delete-drive-snapshot",
-+        .args_type  = "device:s,name:s",
-+        .params     = "device name",
-+        .help       = "Delete internal snapshot.",
-+        .mhandler.cmd = hmp_delete_drive_snapshot,
-+    },
-+
-+    {
-+        .name       = "savevm-end",
-+        .args_type  = "",
-+        .params     = "",
-+        .help       = "Resume VM after snaphot.",
-+        .mhandler.cmd = hmp_savevm_end,
-+    },
-diff --git a/hmp.c b/hmp.c
-index 040909e..78644a7 100644
---- a/hmp.c
-+++ b/hmp.c
-@@ -2093,6 +2093,63 @@ void hmp_info_memory_devices(Monitor *mon, const QDict *qdict)
-     qapi_free_MemoryDeviceInfoList(info_list);
- }
-+void hmp_savevm_start(Monitor *mon, const QDict *qdict)
-+{
-+    Error *errp = NULL;
-+    const char *statefile = qdict_get_try_str(qdict, "statefile");
-+
-+    qmp_savevm_start(statefile != NULL, statefile, &errp);
-+    hmp_handle_error(mon, &errp);
-+}
-+
-+void hmp_snapshot_drive(Monitor *mon, const QDict *qdict)
-+{
-+    Error *errp = NULL;
-+    const char *name = qdict_get_str(qdict, "name");
-+    const char *device = qdict_get_str(qdict, "device");
-+
-+    qmp_snapshot_drive(device, name, &errp);
-+    hmp_handle_error(mon, &errp);
-+}
-+
-+void hmp_delete_drive_snapshot(Monitor *mon, const QDict *qdict)
-+{
-+    Error *errp = NULL;
-+    const char *name = qdict_get_str(qdict, "name");
-+    const char *device = qdict_get_str(qdict, "device");
-+
-+    qmp_delete_drive_snapshot(device, name, &errp);
-+    hmp_handle_error(mon, &errp);
-+}
-+
-+void hmp_savevm_end(Monitor *mon, const QDict *qdict)
-+{
-+    Error *errp = NULL;
-+
-+    qmp_savevm_end(&errp);
-+    hmp_handle_error(mon, &errp);
-+}
-+
-+void hmp_info_savevm(Monitor *mon, const QDict *qdict)
-+{
-+    SaveVMInfo *info;
-+    info = qmp_query_savevm(NULL);
-+
-+    if (info->has_status) {
-+        monitor_printf(mon, "savevm status: %s\n", info->status);
-+        monitor_printf(mon, "total time: %" PRIu64 " milliseconds\n",
-+                       info->total_time);
-+    } else {
-+        monitor_printf(mon, "savevm status: not running\n");
-+    }
-+    if (info->has_bytes) {
-+        monitor_printf(mon, "Bytes saved: %"PRIu64"\n", info->bytes);
-+    }
-+    if (info->has_error) {
-+        monitor_printf(mon, "Error: %s\n", info->error);
-+    }
-+}
-+
- void hmp_info_iothreads(Monitor *mon, const QDict *qdict)
- {
-     IOThreadInfoList *info_list = qmp_query_iothreads(NULL);
-diff --git a/hmp.h b/hmp.h
-index c708b3f..99bc949 100644
---- a/hmp.h
-+++ b/hmp.h
-@@ -26,6 +26,7 @@ void hmp_info_status(Monitor *mon, const QDict *qdict);
- void hmp_info_uuid(Monitor *mon, const QDict *qdict);
- void hmp_info_chardev(Monitor *mon, const QDict *qdict);
- void hmp_info_mice(Monitor *mon, const QDict *qdict);
-+void hmp_info_savevm(Monitor *mon, const QDict *qdict);
- 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);
-@@ -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);
-+void hmp_savevm_start(Monitor *mon, const QDict *qdict);
-+void hmp_snapshot_drive(Monitor *mon, const QDict *qdict);
-+void hmp_delete_drive_snapshot(Monitor *mon, const QDict *qdict);
-+void hmp_savevm_end(Monitor *mon, const QDict *qdict);
- void hmp_sendkey(Monitor *mon, const QDict *qdict);
- void hmp_screendump(Monitor *mon, const QDict *qdict);
- void hmp_nbd_server_start(Monitor *mon, const QDict *qdict);
-diff --git a/include/block/block.h b/include/block/block.h
-index 3a73137..fcc9cac 100644
---- a/include/block/block.h
-+++ b/include/block/block.h
-@@ -266,6 +266,7 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
- int bdrv_get_backing_file_depth(BlockDriverState *bs);
- void bdrv_refresh_filename(BlockDriverState *bs);
- int bdrv_truncate(BlockDriverState *bs, int64_t offset);
-+void bdrv_delete(BlockDriverState *bs);
- int64_t bdrv_nb_sectors(BlockDriverState *bs);
- int64_t bdrv_getlength(BlockDriverState *bs);
- int64_t bdrv_get_allocated_file_size(BlockDriverState *bs);
-diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
-index 38fb3ca..d4790a6 100644
---- a/include/sysemu/sysemu.h
-+++ b/include/sysemu/sysemu.h
-@@ -78,6 +78,7 @@ void qemu_add_machine_init_done_notifier(Notifier *notify);
- void hmp_savevm(Monitor *mon, const QDict *qdict);
- int load_vmstate(const char *name);
-+int load_state_from_blockdev(const char *filename);
- void hmp_delvm(Monitor *mon, const QDict *qdict);
- void hmp_info_snapshots(Monitor *mon, const QDict *qdict);
-@@ -105,13 +106,13 @@ enum qemu_vm_cmd {
- #define MAX_VM_CMD_PACKAGED_SIZE (1ul << 24)
- bool qemu_savevm_state_blocked(Error **errp);
--void qemu_savevm_state_begin(QEMUFile *f,
-+int qemu_savevm_state_begin(QEMUFile *f,
-                              const MigrationParams *params);
- void qemu_savevm_state_header(QEMUFile *f);
- int qemu_savevm_state_iterate(QEMUFile *f, bool postcopy);
- void qemu_savevm_state_cleanup(void);
- void qemu_savevm_state_complete_postcopy(QEMUFile *f);
--void qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only);
-+int qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only);
- void qemu_savevm_state_pending(QEMUFile *f, uint64_t max_size,
-                                uint64_t *res_non_postcopiable,
-                                uint64_t *res_postcopiable);
-diff --git a/migration/savevm.c b/migration/savevm.c
-index 8346649..d6560f5 100644
---- a/migration/savevm.c
-+++ b/migration/savevm.c
-@@ -896,11 +896,11 @@ void qemu_savevm_state_header(QEMUFile *f)
- }
--void qemu_savevm_state_begin(QEMUFile *f,
-+int qemu_savevm_state_begin(QEMUFile *f,
-                              const MigrationParams *params)
- {
-     SaveStateEntry *se;
--    int ret;
-+    int ret = 0;
-     trace_savevm_state_begin();
-     QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
-@@ -928,6 +928,7 @@ void qemu_savevm_state_begin(QEMUFile *f,
-             break;
-         }
-     }
-+    return ret;
- }
- /*
-@@ -1031,7 +1032,7 @@ void qemu_savevm_state_complete_postcopy(QEMUFile *f)
-     qemu_fflush(f);
- }
--void qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only)
-+int qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only)
- {
-     QJSON *vmdesc;
-     int vmdesc_len;
-@@ -1065,12 +1066,12 @@ void qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only)
-         save_section_footer(f, se);
-         if (ret < 0) {
-             qemu_file_set_error(f, ret);
--            return;
-+            return ret;
-         }
-     }
-     if (iterable_only) {
--        return;
-+        return ret;
-     }
-     vmdesc = qjson_new();
-@@ -1117,6 +1118,7 @@ void qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only)
-     object_unref(OBJECT(vmdesc));
-     qemu_fflush(f);
-+    return qemu_file_get_error(f);
- }
- /* Give an estimate of the amount left to be transferred,
-diff --git a/qapi-schema.json b/qapi-schema.json
-index 3427d50..2392139 100644
---- a/qapi-schema.json
-+++ b/qapi-schema.json
-@@ -585,6 +585,42 @@
-            '*setup-time': 'int',
-            '*x-cpu-throttle-percentage': 'int'} }
-+
-+# @SaveVMInfo
-+#
-+# Information about current migration process.
-+#
-+# @status: #optional string describing the current savevm status.
-+#          This can be 'active', 'completed', 'failed'.
-+#          If this field is not returned, no savevm process
-+#          has been initiated
-+#
-+# @error: #optional string containing error message is status is failed.
-+#
-+# @total-time: #optional total amount of milliseconds since savevm started.
-+#        If savevm has ended, it returns the total save time
-+#
-+# @bytes: #optional total amount of data transfered
-+#
-+# Since: 1.3
-+##
-+{ 'struct': 'SaveVMInfo',
-+  'data': {'*status': 'str', '*error': 'str',
-+           '*total-time': 'int', '*bytes': 'int'} }
-+
-+##
-+# @query-savevm
-+#
-+# Returns information about current savevm process.
-+#
-+# Returns: @SaveVMInfo
-+#
-+# Since: 1.3
-+##
-+{ 'command': 'query-savevm', 'returns': 'SaveVMInfo' }
-+
-+##
-+
- ##
- # @query-migrate
- #
-@@ -3197,8 +3233,18 @@
- #
- # Since: 1.2.0
- ##
-+
- { 'command': 'query-target', 'returns': 'TargetInfo' }
-+{ 'command': 'savevm-start', 'data': { '*statefile': 'str' } }
-+
-+{ 'command': 'snapshot-drive', 'data': { 'device': 'str', 'name': 'str' } }
-+
-+{ 'command': 'delete-drive-snapshot', 'data': { 'device': 'str', 'name': 'str' } }
-+
-+{ 'command': 'savevm-end' }
-+
-+
- ##
- # @QKeyCode:
- #
-diff --git a/qemu-options.hx b/qemu-options.hx
-index 6106520..20ab9ac 100644
---- a/qemu-options.hx
-+++ b/qemu-options.hx
-@@ -3270,6 +3270,19 @@ STEXI
- Start right away with a saved state (@code{loadvm} in monitor)
- ETEXI
-+DEF("loadstate", HAS_ARG, QEMU_OPTION_loadstate, \
-+    "-loadstate file\n" \
-+    "                start right away with a saved state\n",
-+    QEMU_ARCH_ALL)
-+STEXI
-+@item -loadstate @var{file}
-+@findex -loadstate
-+Start right away with a saved state. This option does not rollback
-+disk state like @code{loadvm}, so user must make sure that disk
-+have correct state. @var{file} can be any valid device URL. See the section
-+for "Device URL Syntax" for more information.
-+ETEXI
-+
- #ifndef _WIN32
- DEF("daemonize", 0, QEMU_OPTION_daemonize, \
-     "-daemonize      daemonize QEMU after initializing\n", QEMU_ARCH_ALL)
-diff --git a/qmp-commands.hx b/qmp-commands.hx
-index 3f03c0d..437ddd6 100644
---- a/qmp-commands.hx
-+++ b/qmp-commands.hx
-@@ -4783,6 +4783,36 @@ Example:
- EQMP
-     {
-+        .name       = "savevm-start",
-+        .args_type  = "statefile:s?",
-+        .mhandler.cmd_new = qmp_marshal_input_savevm_start,
-+    },
-+
-+    {
-+        .name       = "snapshot-drive",
-+        .args_type  = "device:s,name:s",
-+        .mhandler.cmd_new = qmp_marshal_input_snapshot_drive,
-+    },
-+
-+    {
-+        .name       = "delete-drive-snapshot",
-+        .args_type  = "device:s,name:s",
-+        .mhandler.cmd_new = qmp_marshal_input_delete_drive_snapshot,
-+    },
-+
-+    {
-+        .name       = "savevm-end",
-+        .args_type  = "",
-+        .mhandler.cmd_new = qmp_marshal_input_savevm_end,
-+    },
-+
-+    {
-+        .name       = "query-savevm",
-+        .args_type  = "",
-+        .mhandler.cmd_new = qmp_marshal_input_query_savevm,
-+    },
-+
-+    {
-         .name       = "query-rocker",
-         .args_type  = "name:s",
-         .mhandler.cmd_new = qmp_marshal_query_rocker,
-diff --git a/savevm-async.c b/savevm-async.c
-new file mode 100644
-index 0000000..8117443
---- /dev/null
-+++ b/savevm-async.c
-@@ -0,0 +1,522 @@
-+#include "qemu-common.h"
-+#include "qapi/qmp/qerror.h"
-+#include "qemu/error-report.h"
-+#include "sysemu/sysemu.h"
-+#include "qmp-commands.h"
-+#include "qemu-options.h"
-+#include "migration/qemu-file.h"
-+#include "qom/qom-qobject.h"
-+#include "migration/migration.h"
-+#include "block/snapshot.h"
-+#include "block/qapi.h"
-+#include "block/block.h"
-+#include "qemu/timer.h"
-+#include "sysemu/block-backend.h"
-+#include "qapi/qmp/qstring.h"
-+
-+/* #define DEBUG_SAVEVM_STATE */
-+
-+#ifdef DEBUG_SAVEVM_STATE
-+#define DPRINTF(fmt, ...) \
-+    do { printf("savevm-async: " fmt, ## __VA_ARGS__); } while (0)
-+#else
-+#define DPRINTF(fmt, ...) \
-+    do { } while (0)
-+#endif
-+
-+enum {
-+    SAVE_STATE_DONE,
-+    SAVE_STATE_ERROR,
-+    SAVE_STATE_ACTIVE,
-+    SAVE_STATE_COMPLETED,
-+    SAVE_STATE_CANCELLED
-+};
-+
-+
-+static struct SnapshotState {
-+    BlockDriverState *bs;
-+    size_t bs_pos;
-+    int state;
-+    Error *error;
-+    Error *blocker;
-+    int saved_vm_running;
-+    QEMUFile *file;
-+    int64_t total_time;
-+} snap_state;
-+
-+SaveVMInfo *qmp_query_savevm(Error **errp)
-+{
-+    SaveVMInfo *info = g_malloc0(sizeof(*info));
-+    struct SnapshotState *s = &snap_state;
-+
-+    if (s->state != SAVE_STATE_DONE) {
-+        info->has_bytes = true;
-+        info->bytes = s->bs_pos;
-+        switch (s->state) {
-+        case SAVE_STATE_ERROR:
-+            info->has_status = true;
-+            info->status = g_strdup("failed");
-+            info->has_total_time = true;
-+            info->total_time = s->total_time;
-+            if (s->error) {
-+                info->has_error = true;
-+                info->error = g_strdup(error_get_pretty(s->error));
-+            }
-+            break;
-+        case SAVE_STATE_ACTIVE:
-+            info->has_status = true;
-+            info->status = g_strdup("active");
-+            info->has_total_time = true;
-+            info->total_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME)
-+                - s->total_time;
-+            break;
-+        case SAVE_STATE_COMPLETED:
-+            info->has_status = true;
-+            info->status = g_strdup("completed");
-+            info->has_total_time = true;
-+            info->total_time = s->total_time;
-+            break;
-+        }
-+    }
-+
-+    return info;
-+}
-+
-+static int save_snapshot_cleanup(void)
-+{
-+    int ret = 0;
-+
-+    DPRINTF("save_snapshot_cleanup\n");
-+
-+    snap_state.total_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) -
-+        snap_state.total_time;
-+
-+    if (snap_state.file) {
-+        ret = qemu_fclose(snap_state.file);
-+    }
-+
-+    if (snap_state.bs) {
-+        /* 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);
-+        error_free(snap_state.blocker);
-+        snap_state.blocker = NULL;
-+        bdrv_unref(snap_state.bs);
-+        snap_state.bs = NULL;
-+    }
-+
-+    return ret;
-+}
-+
-+static void save_snapshot_error(const char *fmt, ...)
-+{
-+    va_list ap;
-+    char *msg;
-+
-+    va_start(ap, fmt);
-+    msg = g_strdup_vprintf(fmt, ap);
-+    va_end(ap);
-+
-+    DPRINTF("save_snapshot_error: %s\n", msg);
-+
-+    if (!snap_state.error) {
-+        error_set(&snap_state.error, ERROR_CLASS_GENERIC_ERROR, "%s", msg);
-+    }
-+
-+    g_free (msg);
-+
-+    snap_state.state = SAVE_STATE_ERROR;
-+
-+    save_snapshot_cleanup();
-+}
-+
-+static void save_snapshot_completed(void)
-+{
-+    DPRINTF("save_snapshot_completed\n");
-+
-+    if (save_snapshot_cleanup() < 0) {
-+        snap_state.state = SAVE_STATE_ERROR;
-+    } else {
-+        snap_state.state = SAVE_STATE_COMPLETED;
-+    }
-+}
-+
-+static int block_state_close(void *opaque)
-+{
-+    snap_state.file = NULL;
-+    return bdrv_flush(snap_state.bs);
-+}
-+
-+static int block_state_put_buffer(void *opaque, const uint8_t *buf,
-+                                  int64_t pos, int size)
-+{
-+    int ret;
-+
-+    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;
-+    }
-+
-+    return ret;
-+}
-+
-+static int store_and_stop(void) {
-+    if (global_state_store()) {
-+        save_snapshot_error("Error saving global state");
-+        return 1;
-+    }
-+    if (runstate_is_running()) {
-+        vm_stop(RUN_STATE_SAVE_VM);
-+    }
-+    return 0;
-+}
-+
-+static void process_savevm_co(void *opaque)
-+{
-+    int ret;
-+    int64_t maxlen;
-+    MigrationParams params = {
-+        .blk = 0,
-+        .shared = 0
-+    };
-+
-+    snap_state.state = SAVE_STATE_ACTIVE;
-+
-+    qemu_mutex_unlock_iothread();
-+    qemu_savevm_state_header(snap_state.file);
-+    ret = qemu_savevm_state_begin(snap_state.file, &params);
-+    qemu_mutex_lock_iothread();
-+
-+    if (ret < 0) {
-+        save_snapshot_error("qemu_savevm_state_begin failed");
-+        return;
-+    }
-+
-+    while (snap_state.state == SAVE_STATE_ACTIVE) {
-+        uint64_t pending_size;
-+
-+        pending_size = qemu_savevm_state_pending(snap_state.file, 0);
-+
-+        if (pending_size) {
-+                ret = qemu_savevm_state_iterate(snap_state.file);
-+                if (ret < 0) {
-+                    save_snapshot_error("qemu_savevm_state_iterate error %d", ret);
-+                    break;
-+                }
-+                DPRINTF("savevm inerate pending size %lu ret %d\n", pending_size, ret);
-+        } else {
-+            DPRINTF("done iterating\n");
-+            if (store_and_stop())
-+                break;
-+            DPRINTF("savevm inerate finished\n");
-+            qemu_savevm_state_complete_precopy(snap_state.file);
-+            DPRINTF("save complete\n");
-+            save_snapshot_completed();
-+            break;
-+        }
-+
-+        /* 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;
-+        if ((pending_size < 100000) ||
-+            ((snap_state.bs_pos + pending_size) >= maxlen)) {
-+            if (store_and_stop())
-+                break;
-+        }
-+    }
-+
-+    if(snap_state.state == SAVE_STATE_CANCELLED) {
-+        save_snapshot_completed();
-+        Error *errp = NULL;
-+        qmp_savevm_end(&errp);
-+    }
-+
-+}
-+
-+static const QEMUFileOps block_file_ops = {
-+    .put_buffer =     block_state_put_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_CACHE_WB | BDRV_O_RDWR;
-+    int ret;
-+
-+    if (snap_state.state != SAVE_STATE_DONE) {
-+        error_set(errp, ERROR_CLASS_GENERIC_ERROR,
-+                  "VM snapshot already started\n");
-+        return;
-+    }
-+
-+    /* initialize snapshot info */
-+    snap_state.saved_vm_running = runstate_is_running();
-+    snap_state.bs_pos = 0;
-+    snap_state.total_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
-+    snap_state.blocker = NULL;
-+
-+    if (snap_state.error) {
-+        error_free(snap_state.error);
-+        snap_state.error = NULL;
-+    }
-+
-+    if (!has_statefile) {
-+        vm_stop(RUN_STATE_SAVE_VM);
-+        snap_state.state = SAVE_STATE_COMPLETED;
-+        return;
-+    }
-+
-+    if (qemu_savevm_state_blocked(errp)) {
-+        return;
-+    }
-+
-+    /* 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) {
-+        error_set(errp, ERROR_CLASS_GENERIC_ERROR, "failed to open '%s'", statefile);
-+        goto restart;
-+    }
-+
-+    snap_state.file = qemu_fopen_ops(&snap_state, &block_file_ops);
-+
-+    if (!snap_state.file) {
-+        error_set(errp, ERROR_CLASS_GENERIC_ERROR, "failed to open '%s'", statefile);
-+        goto restart;
-+    }
-+
-+
-+    error_setg(&snap_state.blocker, "block device is in use by savevm");
-+    bdrv_op_block_all(snap_state.bs, snap_state.blocker);
-+
-+    Coroutine *co = qemu_coroutine_create(process_savevm_co);
-+    qemu_coroutine_enter(co, NULL);
-+
-+    return;
-+
-+restart:
-+
-+    save_snapshot_error("setup failed");
-+
-+    if (snap_state.saved_vm_running) {
-+        vm_start();
-+    }
-+}
-+
-+void qmp_savevm_end(Error **errp)
-+{
-+    if (snap_state.state == SAVE_STATE_DONE) {
-+        error_set(errp, ERROR_CLASS_GENERIC_ERROR,
-+                  "VM snapshot not started\n");
-+        return;
-+    }
-+
-+    if (snap_state.state == SAVE_STATE_ACTIVE) {
-+        snap_state.state = SAVE_STATE_CANCELLED;
-+        return;
-+    }
-+
-+    if (snap_state.saved_vm_running) {
-+        vm_start();
-+    }
-+
-+    snap_state.state = SAVE_STATE_DONE;
-+}
-+
-+void qmp_snapshot_drive(const char *device, const char *name, Error **errp)
-+{
-+    BlockBackend *blk;
-+    BlockDriverState *bs;
-+    QEMUSnapshotInfo sn1, *sn = &sn1;
-+    int ret;
-+#ifdef _WIN32
-+    struct _timeb tb;
-+#else
-+    struct timeval tv;
-+#endif
-+
-+    if (snap_state.state != SAVE_STATE_COMPLETED) {
-+        error_set(errp, ERROR_CLASS_GENERIC_ERROR,
-+                  "VM snapshot not ready/started\n");
-+        return;
-+    }
-+
-+    blk = blk_by_name(device);
-+    if (!blk) {
-+        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
-+                  "Device '%s' not found", device);
-+        return;
-+    }
-+
-+    bs = blk_bs(blk);
-+    if (!bdrv_is_inserted(bs)) {
-+        error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
-+        return;
-+    }
-+
-+    if (bdrv_is_read_only(bs)) {
-+        error_setg(errp, "Node '%s' is read only", device);
-+        return;
-+    }
-+
-+    if (!bdrv_can_snapshot(bs)) {
-+        error_setg(errp, QERR_UNSUPPORTED);
-+        return;
-+    }
-+
-+    if (bdrv_snapshot_find(bs, sn, name) >= 0) {
-+        error_set(errp, ERROR_CLASS_GENERIC_ERROR,
-+                  "snapshot '%s' already exists", name);
-+        return;
-+    }
-+
-+    sn = &sn1;
-+    memset(sn, 0, sizeof(*sn));
-+
-+#ifdef _WIN32
-+    _ftime(&tb);
-+    sn->date_sec = tb.time;
-+    sn->date_nsec = tb.millitm * 1000000;
-+#else
-+    gettimeofday(&tv, NULL);
-+    sn->date_sec = tv.tv_sec;
-+    sn->date_nsec = tv.tv_usec * 1000;
-+#endif
-+    sn->vm_clock_nsec = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-+
-+    pstrcpy(sn->name, sizeof(sn->name), name);
-+
-+    sn->vm_state_size = 0; /* do not save state */
-+
-+    ret = bdrv_snapshot_create(bs, sn);
-+    if (ret < 0) {
-+        error_set(errp, ERROR_CLASS_GENERIC_ERROR,
-+                  "Error while creating snapshot on '%s'\n", device);
-+        return;
-+    }
-+}
-+
-+void qmp_delete_drive_snapshot(const char *device, const char *name,
-+                               Error **errp)
-+{
-+    BlockBackend *blk;
-+    BlockDriverState *bs;
-+    QEMUSnapshotInfo sn1, *sn = &sn1;
-+    Error *local_err = NULL;
-+
-+    int ret;
-+
-+    blk = blk_by_name(device);
-+    if (!blk) {
-+        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
-+                  "Device '%s' not found", device);
-+        return;
-+    }
-+
-+    bs = blk_bs(blk);
-+    if (bdrv_is_read_only(bs)) {
-+        error_setg(errp, "Node '%s' is read only", device);
-+        return;
-+    }
-+
-+    if (!bdrv_can_snapshot(bs)) {
-+        error_setg(errp, QERR_UNSUPPORTED);
-+        return;
-+    }
-+
-+    if (bdrv_snapshot_find(bs, sn, name) < 0) {
-+        /* return success if snapshot does not exists */
-+        return;
-+    }
-+
-+    ret = bdrv_snapshot_delete(bs, NULL, name, &local_err);
-+    if (ret < 0) {
-+        error_set(errp, ERROR_CLASS_GENERIC_ERROR,
-+                  "Error while deleting snapshot on '%s'\n", device);
-+        return;
-+    }
-+}
-+
-+static int loadstate_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
-+                                int size)
-+{
-+    BlockDriverState *bs = (BlockDriverState *)opaque;
-+    int64_t maxlen = bdrv_getlength(bs);
-+    if (pos > maxlen) {
-+        return -EIO;
-+    }
-+    if ((pos + size) > maxlen) {
-+        size = maxlen - pos - 1;
-+    }
-+    if (size == 0) {
-+        return 0;
-+    }
-+    return bdrv_pread(bs, pos, buf, size);
-+}
-+
-+static const QEMUFileOps loadstate_file_ops = {
-+    .get_buffer = loadstate_get_buffer,
-+};
-+
-+int load_state_from_blockdev(const char *filename)
-+{
-+    BlockDriverState *bs = NULL;
-+    BlockDriver *drv = NULL;
-+    Error *local_err = NULL;
-+    Error *blocker = NULL;
-+
-+    QEMUFile *f;
-+    int ret;
-+
-+    bs = bdrv_new();
-+    ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_CACHE_WB, drv, &local_err);
-+    error_setg(&blocker, "block device is in use by load state");
-+    bdrv_op_block_all(bs, blocker);
-+
-+    if (ret < 0) {
-+        error_report("Could not open VM state file");
-+        goto the_end;
-+    }
-+
-+    /* restore the VM state */
-+    f = qemu_fopen_ops(bs, &loadstate_file_ops);
-+    if (!f) {
-+        error_report("Could not open VM state file");
-+        ret = -EINVAL;
-+        goto the_end;
-+    }
-+
-+    qemu_system_reset(VMRESET_SILENT);
-+    migration_incoming_state_new(f);
-+    ret = qemu_loadvm_state(f);
-+
-+    qemu_fclose(f);
-+    migration_incoming_state_destroy();
-+    if (ret < 0) {
-+        error_report("Error %d while loading VM state", ret);
-+        goto the_end;
-+    }
-+
-+    ret = 0;
-+
-+ the_end:
-+    if (bs) {
-+        bdrv_op_unblock_all(bs, blocker);
-+        error_free(blocker);
-+        bdrv_unref(bs);
-+    }
-+    return ret;
-+}
-diff --git a/vl.c b/vl.c
-index feeb2c4..ba29593 100644
---- a/vl.c
-+++ b/vl.c
-@@ -2979,6 +2979,7 @@ int main(int argc, char **argv, char **envp)
-     int optind;
-     const char *optarg;
-     const char *loadvm = NULL;
-+    const char *loadstate = NULL;
-     MachineClass *machine_class;
-     const char *cpu_model;
-     const char *vga_model = NULL;
-@@ -3612,6 +3613,9 @@ int main(int argc, char **argv, char **envp)
-             case QEMU_OPTION_loadvm:
-                 loadvm = optarg;
-                 break;
-+            case QEMU_OPTION_loadstate:
-+                loadstate = optarg;
-+                break;
-             case QEMU_OPTION_full_screen:
-                 full_screen = 1;
-                 break;
-@@ -4640,6 +4644,10 @@ int main(int argc, char **argv, char **envp)
-         if (load_vmstate(loadvm) < 0) {
-             autostart = 0;
-         }
-+    } else if (loadstate) {
-+        if (load_state_from_blockdev(loadstate) < 0) {
-+            autostart = 0;
-+        }
-     }
-     qdev_prop_check_globals();
--- 
-2.1.4
-
diff --git a/debian/patches/pve/0024-backup-vma-allow-empty-backups.patch b/debian/patches/pve/0024-backup-vma-allow-empty-backups.patch
deleted file mode 100644 (file)
index 25db720..0000000
+++ /dev/null
@@ -1,268 +0,0 @@
-From 7136f6d83dee1ee791c142ab0bb3d406589e9e13 Mon Sep 17 00:00:00 2001
-From: Wolfgang Bumiller <w.bumiller@proxmox.com>
-Date: Wed, 9 Dec 2015 16:31:51 +0100
-Subject: [PATCH 24/55] backup: vma: allow empty backups
-
----
- vma-reader.c | 29 ++++++++++-----------
- vma-writer.c | 30 ++++++++++++++--------
- vma.c        | 84 ++++++++++++++++++++++++++++++++++++++----------------------
- vma.h        |  1 +
- 4 files changed, 88 insertions(+), 56 deletions(-)
-
-diff --git a/vma-reader.c b/vma-reader.c
-index d9f43fe..5d0d3ea 100644
---- a/vma-reader.c
-+++ b/vma-reader.c
-@@ -334,11 +334,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]);
-@@ -830,16 +825,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 3c77e98..5cc4564 100644
---- a/vma-writer.c
-+++ b/vma-writer.c
-@@ -258,7 +258,7 @@ vma_queue_write(VmaWriter *vmaw, const void *buf, size_t bytes)
-     }
-     vmaw->co_writer = NULL;
--    
-+
-     return (done == bytes) ? bytes : -1;
- }
-@@ -382,10 +382,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]);
-@@ -502,6 +498,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)
-@@ -529,12 +542,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 6a33352..00f20b0 100644
---- a/vma.c
-+++ b/vma.c
-@@ -33,7 +33,7 @@ static void help(void)
-         "\n"
-         "vma list <filename>\n"
-         "vma config <filename> [-c config]\n"
--        "vma create <filename> [-c config] <archive> pathname ...\n"
-+        "vma create <filename> [-c config] pathname ...\n"
-         "vma extract <filename> [-r <fifo>] <targetdir>\n"
-         "vma verify <filename> [-v]\n"
-         ;
-@@ -401,6 +401,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;
-@@ -474,8 +486,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();
-     }
-@@ -510,11 +522,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++);
-         BlockDriver *drv = NULL;
-         Error *errp = NULL;
-@@ -546,37 +558,49 @@ 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 (verbose) {
--
--            uint64_t total = 0;
--            uint64_t transferred = 0;
--            uint64_t zero_bytes = 0;
-+    if (devcount) {
-+        while (1) {
-+            main_loop_wait(false);
-+            vma_writer_get_status(vmaw, &vmastat);
-+
-+            if (verbose) {
-+
-+                uint64_t total = 0;
-+                uint64_t transferred = 0;
-+                uint64_t zero_bytes = 0;
-+
-+                int i;
-+                for (i = 0; i < 256; i++) {
-+                    if (vmastat.stream_info[i].size) {
-+                        total += vmastat.stream_info[i].size;
-+                        transferred += vmastat.stream_info[i].transferred;
-+                        zero_bytes += vmastat.stream_info[i].zero_bytes;
-+                    }
-+                }
-+                percent = (transferred*100)/total;
-+                if (percent != last_percent) {
-+                    fprintf(stderr, "progress %d%% %zd/%zd %zd\n", percent,
-+                            transferred, total, zero_bytes);
-+                    fflush(stderr);
--            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);
-+        qemu_coroutine_enter(co, vmaw);
-+      while (1) {
-+          main_loop_wait(false);
-+          vma_writer_get_status(vmaw, &vmastat);
-+          if (vmastat.closed) {
-+                  break;
-+            }
-+      }
-     }
-     bdrv_drain_all();
-diff --git a/vma.h b/vma.h
-index 98377e4..365ceb2 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.1.4
-
diff --git a/debian/patches/pve/0024-qmp-add-get_link_status.patch b/debian/patches/pve/0024-qmp-add-get_link_status.patch
new file mode 100644 (file)
index 0000000..fa88704
--- /dev/null
@@ -0,0 +1,126 @@
+From 7e58a86c836514745590e4f4d280841c4808a022 Mon Sep 17 00:00:00 2001
+From: Wolfgang Bumiller <w.bumiller@proxmox.com>
+Date: Wed, 9 Dec 2015 16:34:41 +0100
+Subject: [PATCH 24/41] qmp: add get_link_status
+
+---
+ net/net.c        | 27 +++++++++++++++++++++++++++
+ qapi-schema.json | 15 +++++++++++++++
+ qmp-commands.hx  | 23 +++++++++++++++++++++++
+ scripts/qapi.py  |  2 ++
+ 4 files changed, 67 insertions(+)
+
+diff --git a/net/net.c b/net/net.c
+index d51cb29..c94d93d 100644
+--- a/net/net.c
++++ b/net/net.c
+@@ -1362,6 +1362,33 @@ void hmp_info_network(Monitor *mon, const QDict *qdict)
+     }
+ }
++int64_t qmp_get_link_status(const char *name, Error **errp)
++{
++    NetClientState *ncs[MAX_QUEUE_NUM];
++    NetClientState *nc;
++    int queues;
++    bool ret;
++
++    queues = qemu_find_net_clients_except(name, ncs,
++                                          NET_CLIENT_DRIVER__MAX,
++                                          MAX_QUEUE_NUM);
++
++    if (queues == 0) {
++        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
++                  "Device '%s' not found", name);
++        return (int64_t) -1;
++    }
++
++    nc = ncs[0];
++    ret = ncs[0]->link_down;
++
++    if (nc->peer->info->type == NET_CLIENT_DRIVER_NIC) {
++      ret = ncs[0]->peer->link_down;
++    }
++
++    return (int64_t) ret ? 0 : 1;
++}
++
+ void qmp_set_link(const char *name, bool up, Error **errp)
+ {
+     NetClientState *ncs[MAX_QUEUE_NUM];
+diff --git a/qapi-schema.json b/qapi-schema.json
+index 0c0faf7..d75e932 100644
+--- a/qapi-schema.json
++++ b/qapi-schema.json
+@@ -1786,6 +1786,21 @@
+ { 'command': 'set_link', 'data': {'name': 'str', 'up': 'bool'} }
+ ##
++# @get_link_status
++#
++# Get the current link state of the nics or nic.
++#
++# @name: name of the nic you get the state of
++#
++# Return: If link is up 1
++#         If link is down 0
++#         If an error occure an empty string.
++#
++# Notes: this is an Proxmox VE extension and not offical part of Qemu.
++##
++{ 'command': 'get_link_status', 'data': {'name': 'str'}, 'returns': 'int'}
++
++##
+ # @balloon:
+ #
+ # Request the balloon driver to change its balloon size.
+diff --git a/qmp-commands.hx b/qmp-commands.hx
+index 6342cd2..a84932a 100644
+--- a/qmp-commands.hx
++++ b/qmp-commands.hx
+@@ -1883,6 +1883,29 @@ Example:
+ EQMP
+     {
++        .name       = "get_link_status",
++        .args_type  = "name:s",
++        .mhandler.cmd_new = qmp_marshal_get_link_status,
++    },
++
++SQMP
++get_link_status
++--------
++
++Get the link status of a network adapter.
++
++Arguments:
++
++- "name": network device name (json-string)
++
++Example:
++
++-> { "execute": "get_link_status", "arguments": { "name": "e1000.0" } }
++<- { "return": {1} }
++
++EQMP
++
++    {
+         .name       = "getfd",
+         .args_type  = "fdname:s",
+         .params     = "getfd name",
+diff --git a/scripts/qapi.py b/scripts/qapi.py
+index 21bc32f..f900659 100644
+--- a/scripts/qapi.py
++++ b/scripts/qapi.py
+@@ -39,6 +39,8 @@ builtin_types = {
+ # Whitelist of commands allowed to return a non-dictionary
+ returns_whitelist = [
++    'get_link_status',
++
+     # From QMP:
+     'human-monitor-command',
+     'qom-get',
+-- 
+2.1.4
+
diff --git a/debian/patches/pve/0025-backup-vma-add-BlockDriver-to-bdrv_open-in-extract_c.patch b/debian/patches/pve/0025-backup-vma-add-BlockDriver-to-bdrv_open-in-extract_c.patch
deleted file mode 100644 (file)
index 71f9f1d..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-From a88a0bf330a1ede68e867d7ae932b3ffd4d4911a Mon Sep 17 00:00:00 2001
-From: Wolfgang Bumiller <w.bumiller@proxmox.com>
-Date: Wed, 9 Dec 2015 16:32:39 +0100
-Subject: [PATCH 25/55] backup: vma: add BlockDriver to bdrv_open in
- extract_content
-
----
- vma.c | 8 +++++++-
- 1 file changed, 7 insertions(+), 1 deletion(-)
-
-diff --git a/vma.c b/vma.c
-index 00f20b0..543e7d8 100644
---- a/vma.c
-+++ b/vma.c
-@@ -299,7 +299,13 @@ static int extract_content(int argc, char **argv)
-             }
-             BlockDriverState *bs = bdrv_new();
--            if (errp || bdrv_open(&bs, devfn, NULL, NULL, flags, NULL, &errp)) {
-+
-+          const char *tmp = g_strrstr(devfn, ".");
-+          const char *format = (tmp == NULL) ? "raw" : ++tmp;
-+
-+          BlockDriver *drv = bdrv_find_format(format);
-+
-+          if (errp || bdrv_open(&bs, devfn, NULL, NULL, flags, drv, &errp)) {
-                 g_error("can't open file %s - %s", devfn,
-                         error_get_pretty(errp));
-             }
--- 
-2.1.4
-
diff --git a/debian/patches/pve/0025-smm_available-false.patch b/debian/patches/pve/0025-smm_available-false.patch
new file mode 100644 (file)
index 0000000..14b5a62
--- /dev/null
@@ -0,0 +1,26 @@
+From 38b2b042f9943786c9d3728d9c24cb110170df88 Mon Sep 17 00:00:00 2001
+From: Alexandre Derumier <aderumier@odiso.com>
+Date: Tue, 29 Sep 2015 15:37:44 +0200
+Subject: [PATCH 25/41] smm_available = false
+
+Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
+---
+ hw/i386/pc.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/hw/i386/pc.c b/hw/i386/pc.c
+index ba8a5a1..9c206fc 100644
+--- a/hw/i386/pc.c
++++ b/hw/i386/pc.c
+@@ -2084,7 +2084,7 @@ bool pc_machine_is_smm_enabled(PCMachineState *pcms)
+     if (tcg_enabled() || qtest_enabled()) {
+         smm_available = true;
+     } else if (kvm_enabled()) {
+-        smm_available = kvm_has_smm();
++        smm_available = false;
+     }
+     if (smm_available) {
+-- 
+2.1.4
+
diff --git a/debian/patches/pve/0026-glusterfs-daemonize.patch b/debian/patches/pve/0026-glusterfs-daemonize.patch
deleted file mode 100644 (file)
index 61abcc2..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-From 577243992461100d840e90b6018df958ee165a34 Mon Sep 17 00:00:00 2001
-From: Wolfgang Bumiller <w.bumiller@proxmox.com>
-Date: Wed, 9 Dec 2015 16:33:10 +0100
-Subject: [PATCH 26/55] glusterfs: daemonize
-
----
- block/gluster.c | 8 +++++---
- 1 file changed, 5 insertions(+), 3 deletions(-)
-
-diff --git a/block/gluster.c b/block/gluster.c
-index a8aaacf..9cf33e9 100644
---- a/block/gluster.c
-+++ b/block/gluster.c
-@@ -198,9 +198,11 @@ static struct glfs *qemu_gluster_init(GlusterConf *gconf, const char *filename,
-      * TODO: Use GF_LOG_ERROR instead of hard code value of 4 here when
-      * GlusterFS makes GF_LOG_* macros available to libgfapi users.
-      */
--    ret = glfs_set_logging(glfs, "-", 4);
--    if (ret < 0) {
--        goto out;
-+    if (!is_daemonized()) {
-+        ret = glfs_set_logging(glfs, "-", 4);
-+        if (ret < 0) {
-+            goto out;
-+        }
-     }
-     ret = glfs_init(glfs);
--- 
-2.1.4
-
diff --git a/debian/patches/pve/0026-use-whitespace-between-VERSION-and-PKGVERSION.patch b/debian/patches/pve/0026-use-whitespace-between-VERSION-and-PKGVERSION.patch
new file mode 100644 (file)
index 0000000..5e74929
--- /dev/null
@@ -0,0 +1,27 @@
+From 6c2e8cae485cb72873084b36d4b701606cd28f3a Mon Sep 17 00:00:00 2001
+From: Wolfgang Bumiller <w.bumiller@proxmox.com>
+Date: Wed, 9 Dec 2015 16:50:05 +0100
+Subject: [PATCH 26/41] 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()
+---
+ vl.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/vl.c b/vl.c
+index 85033e3..fefc0bd 100644
+--- a/vl.c
++++ b/vl.c
+@@ -1919,7 +1919,7 @@ static void main_loop(void)
+ static void version(void)
+ {
+-    printf("QEMU emulator version " QEMU_VERSION QEMU_PKGVERSION ", "
++    printf("QEMU emulator version " QEMU_VERSION " " QEMU_PKGVERSION ", "
+            QEMU_COPYRIGHT "\n");
+ }
+-- 
+2.1.4
+
diff --git a/debian/patches/pve/0027-gluster-possiblity-to-specify-a-secondary-server.patch b/debian/patches/pve/0027-gluster-possiblity-to-specify-a-secondary-server.patch
deleted file mode 100644 (file)
index dd3babd..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-From 15c3d8e19c9d7534441226229dd509e3a61ce82a Mon Sep 17 00:00:00 2001
-From: Wolfgang Bumiller <w.bumiller@proxmox.com>
-Date: Wed, 9 Dec 2015 16:33:25 +0100
-Subject: [PATCH 27/55] gluster: possiblity to specify a secondary server
-
----
- block/gluster.c | 40 +++++++++++++++++++++++++++++++---------
- 1 file changed, 31 insertions(+), 9 deletions(-)
-
-diff --git a/block/gluster.c b/block/gluster.c
-index 9cf33e9..0377725 100644
---- a/block/gluster.c
-+++ b/block/gluster.c
-@@ -28,6 +28,7 @@ typedef struct BDRVGlusterState {
- typedef struct GlusterConf {
-     char *server;
-+    char *backupserver;
-     int port;
-     char *volname;
-     char *image;
-@@ -38,6 +39,7 @@ static void qemu_gluster_gconf_free(GlusterConf *gconf)
- {
-     if (gconf) {
-         g_free(gconf->server);
-+        g_free(gconf->backupserver);
-         g_free(gconf->volname);
-         g_free(gconf->image);
-         g_free(gconf->transport);
-@@ -71,7 +73,7 @@ static int parse_volume_options(GlusterConf *gconf, char *path)
- }
- /*
-- * file=gluster[+transport]://[server[:port]]/volname/image[?socket=...]
-+ * file=gluster[+transport]://[server[:port]]/volname/image[?socket=...|?s2=...]
-  *
-  * 'gluster' is the protocol.
-  *
-@@ -87,6 +89,8 @@ static int parse_volume_options(GlusterConf *gconf, char *path)
-  * The 'socket' field needs to be populated with the path to unix domain
-  * socket.
-  *
-+ * 's2' can be used to specifies a second volfile server.
-+ *
-  * 'port' is the port number on which glusterd is listening. This is optional
-  * and if not specified, QEMU will send 0 which will make gluster to use the
-  * default port. If the transport type is unix, then 'port' should not be
-@@ -99,6 +103,7 @@ static int parse_volume_options(GlusterConf *gconf, char *path)
-  * Examples:
-  *
-  * file=gluster://1.2.3.4/testvol/a.img
-+ * file=gluster://1.2.3.4/testvol/a.img?s2=1.2.3.5
-  * file=gluster+tcp://1.2.3.4/testvol/a.img
-  * file=gluster+tcp://1.2.3.4:24007/testvol/dir/a.img
-  * file=gluster+tcp://[1:2:3:4:5:6:7:8]/testvol/dir/a.img
-@@ -113,6 +118,8 @@ static int qemu_gluster_parseuri(GlusterConf *gconf, const char *filename)
-     QueryParams *qp = NULL;
-     bool is_unix = false;
-     int ret = 0;
-+    int i;
-+    char *socket = NULL;
-     uri = uri_parse(filename);
-     if (!uri) {
-@@ -140,21 +147,28 @@ static int qemu_gluster_parseuri(GlusterConf *gconf, const char *filename)
-     }
-     qp = query_params_parse(uri->query);
--    if (qp->n > 1 || (is_unix && !qp->n) || (!is_unix && qp->n)) {
-+    for (i = 0; i < qp->n; i++) {
-+        if (!is_unix && strcmp(qp->p[i].name, "s2") == 0) {
-+            gconf->backupserver = g_strdup(qp->p[i].value);
-+        } else if (is_unix && strcmp(qp->p[i].name, "socket") == 0) {
-+            socket = qp->p[i].value;
-+        } else {
-+            ret = -EINVAL;
-+            goto out;
-+        }
-+    }
-+
-+    if (is_unix && !socket) {
-         ret = -EINVAL;
-         goto out;
-     }
-     if (is_unix) {
--        if (uri->server || uri->port) {
-+        if (!socket || uri->server || uri->port) {
-             ret = -EINVAL;
-             goto out;
-         }
--        if (strcmp(qp->p[0].name, "socket")) {
--            ret = -EINVAL;
--            goto out;
--        }
--        gconf->server = g_strdup(qp->p[0].value);
-+        gconf->server = g_strdup(socket);
-     } else {
-         gconf->server = g_strdup(uri->server ? uri->server : "localhost");
-         gconf->port = uri->port;
-@@ -178,7 +192,7 @@ static struct glfs *qemu_gluster_init(GlusterConf *gconf, const char *filename,
-     ret = qemu_gluster_parseuri(gconf, filename);
-     if (ret < 0) {
-         error_setg(errp, "Usage: file=gluster[+transport]://[server[:port]]/"
--                   "volname/image[?socket=...]");
-+                   "volname/image[?socket=...|?s2=...]");
-         errno = -ret;
-         goto out;
-     }
-@@ -194,6 +208,14 @@ static struct glfs *qemu_gluster_init(GlusterConf *gconf, const char *filename,
-         goto out;
-     }
-+    if (gconf->backupserver) {
-+        ret = glfs_set_volfile_server(glfs, gconf->transport, gconf->backupserver,
-+                                      gconf->port);
-+        if (ret < 0) {
-+            goto out;
-+        }
-+    }
-+
-     /*
-      * TODO: Use GF_LOG_ERROR instead of hard code value of 4 here when
-      * GlusterFS makes GF_LOG_* macros available to libgfapi users.
--- 
-2.1.4
-
diff --git a/debian/patches/pve/0027-vma-add-firewall.patch b/debian/patches/pve/0027-vma-add-firewall.patch
new file mode 100644 (file)
index 0000000..9406982
--- /dev/null
@@ -0,0 +1,158 @@
+From eeedbc0558580dcb28d4e82b567ea980b24c9cd3 Mon Sep 17 00:00:00 2001
+From: Wolfgang Bumiller <w.bumiller@proxmox.com>
+Date: Wed, 9 Dec 2015 16:51:23 +0100
+Subject: [PATCH 27/41] vma: add firewall
+
+---
+ blockdev.c       | 78 ++++++++++++++++++++++++++++++++++----------------------
+ hmp.c            |  2 +-
+ qapi-schema.json |  1 +
+ qmp-commands.hx  |  2 +-
+ 4 files changed, 51 insertions(+), 32 deletions(-)
+
+diff --git a/blockdev.c b/blockdev.c
+index 2371cf3..bbb1502 100644
+--- a/blockdev.c
++++ b/blockdev.c
+@@ -3157,6 +3157,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)
+ {
+@@ -3184,6 +3222,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)
+ {
+@@ -3335,38 +3374,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 7bd319f..6c6a0ac 100644
+--- a/hmp.c
++++ b/hmp.c
+@@ -1549,7 +1549,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 d75e932..7bb0ee0 100644
+--- a/qapi-schema.json
++++ b/qapi-schema.json
+@@ -420,6 +420,7 @@
+ { 'command': 'backup', 'data': { 'backup-file': 'str',
+                                     '*format': 'BackupFormat',
+                                     '*config-file': 'str',
++                                    '*firewall-file': 'str',
+                                     '*devlist': 'str', '*speed': 'int' },
+   'returns': 'UuidInfo' }
+diff --git a/qmp-commands.hx b/qmp-commands.hx
+index a84932a..94cfac2 100644
+--- a/qmp-commands.hx
++++ b/qmp-commands.hx
+@@ -1315,7 +1315,7 @@ EQMP
+     {
+         .name       = "backup",
+-        .args_type  = "backup-file:s,format:s?,config-file:F?,speed:o?,devlist:s?",
++        .args_type  = "backup-file:s,format:s?,config-file:F?,firewall-file:F?,speed:o?,devlist:s?",
+         .mhandler.cmd_new = qmp_marshal_backup,
+     },
+-- 
+2.1.4
+
diff --git a/debian/patches/pve/0028-qmp-add-get_link_status.patch b/debian/patches/pve/0028-qmp-add-get_link_status.patch
deleted file mode 100644 (file)
index d8c6803..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-From 9170833ae6e593326b1a37892282d4177ab7414e Mon Sep 17 00:00:00 2001
-From: Wolfgang Bumiller <w.bumiller@proxmox.com>
-Date: Wed, 9 Dec 2015 16:34:41 +0100
-Subject: [PATCH 28/55] qmp: add get_link_status
-
----
- net/net.c        | 27 +++++++++++++++++++++++++++
- qapi-schema.json | 15 +++++++++++++++
- qmp-commands.hx  | 23 +++++++++++++++++++++++
- scripts/qapi.py  |  2 ++
- 4 files changed, 67 insertions(+)
-
-diff --git a/net/net.c b/net/net.c
-index 6b0b375..0e3f231 100644
---- a/net/net.c
-+++ b/net/net.c
-@@ -1325,6 +1325,33 @@ void hmp_info_network(Monitor *mon, const QDict *qdict)
-     }
- }
-+int64_t qmp_get_link_status(const char *name, Error **errp)
-+{
-+    NetClientState *ncs[MAX_QUEUE_NUM];
-+    NetClientState *nc;
-+    int queues;
-+    bool ret;
-+
-+    queues = qemu_find_net_clients_except(name, ncs,
-+                                          NET_CLIENT_OPTIONS_KIND_MAX,
-+                                          MAX_QUEUE_NUM);
-+
-+    if (queues == 0) {
-+        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
-+                  "Device '%s' not found", name);
-+        return (int64_t) -1;
-+    }
-+
-+    nc = ncs[0];
-+    ret = ncs[0]->link_down;
-+
-+    if (nc->peer->info->type == NET_CLIENT_OPTIONS_KIND_NIC) {
-+      ret = ncs[0]->peer->link_down;
-+    }
-+
-+    return (int64_t) ret ? 0 : 1;
-+}
-+
- void qmp_set_link(const char *name, bool up, Error **errp)
- {
-     NetClientState *ncs[MAX_QUEUE_NUM];
-diff --git a/qapi-schema.json b/qapi-schema.json
-index 2392139..d1985d2 100644
---- a/qapi-schema.json
-+++ b/qapi-schema.json
-@@ -1725,6 +1725,21 @@
- { 'command': 'set_link', 'data': {'name': 'str', 'up': 'bool'} }
- ##
-+# @get_link_status
-+#
-+# Get the current link state of the nics or nic.
-+#
-+# @name: name of the nic you get the state of
-+#
-+# Return: If link is up 1
-+#         If link is down 0
-+#         If an error occure an empty string.
-+#
-+# Notes: this is an Proxmox VE extension and not offical part of Qemu.
-+##
-+{ 'command': 'get_link_status', 'data': {'name': 'str'}, 'returns': 'int'}
-+
-+##
- # @balloon:
- #
- # Request the balloon driver to change its balloon size.
-diff --git a/qmp-commands.hx b/qmp-commands.hx
-index 437ddd6..71c5d53 100644
---- a/qmp-commands.hx
-+++ b/qmp-commands.hx
-@@ -1844,6 +1844,29 @@ Example:
- EQMP
-     {
-+        .name       = "get_link_status",
-+        .args_type  = "name:s",
-+        .mhandler.cmd_new = qmp_marshal_input_get_link_status,
-+    },
-+
-+SQMP
-+get_link_status
-+--------
-+
-+Get the link status of a network adapter.
-+
-+Arguments:
-+
-+- "name": network device name (json-string)
-+
-+Example:
-+
-+-> { "execute": "get_link_status", "arguments": { "name": "e1000.0" } }
-+<- { "return": {1} }
-+
-+EQMP
-+
-+    {
-         .name       = "getfd",
-         .args_type  = "fdname:s",
-         .params     = "getfd name",
-diff --git a/scripts/qapi.py b/scripts/qapi.py
-index b13ae47..088478a 100644
---- a/scripts/qapi.py
-+++ b/scripts/qapi.py
-@@ -39,6 +39,8 @@ builtin_types = {
- # Whitelist of commands allowed to return a non-dictionary
- returns_whitelist = [
-+    'get_link_status',
-+
-     # From QMP:
-     'human-monitor-command',
-     'qom-get',
--- 
-2.1.4
-
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
new file mode 100644 (file)
index 0000000..a51eae1
--- /dev/null
@@ -0,0 +1,101 @@
+From f4494a796f451cbb9bb680798b73f62cac943e54 Mon Sep 17 00:00:00 2001
+From: Wolfgang Bumiller <w.bumiller@proxmox.com>
+Date: Thu, 10 Dec 2015 15:14:00 +0100
+Subject: [PATCH 28/41] 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 ae7ea84..7979435 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;
+@@ -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.1.4
+
diff --git a/debian/patches/pve/0029-smm_available-false.patch b/debian/patches/pve/0029-smm_available-false.patch
deleted file mode 100644 (file)
index a0a1593..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-From 3aebb3903e61b8ceb7f0d302f8dfddfe7195c10e Mon Sep 17 00:00:00 2001
-From: Alexandre Derumier <aderumier@odiso.com>
-Date: Tue, 29 Sep 2015 15:37:44 +0200
-Subject: [PATCH 29/55] smm_available = false
-
-Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
----
- hw/i386/pc.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/hw/i386/pc.c b/hw/i386/pc.c
-index 1225a99..ceae96c 100644
---- a/hw/i386/pc.c
-+++ b/hw/i386/pc.c
-@@ -1839,7 +1839,7 @@ bool pc_machine_is_smm_enabled(PCMachineState *pcms)
-     if (tcg_enabled() || qtest_enabled()) {
-         smm_available = true;
-     } else if (kvm_enabled()) {
--        smm_available = kvm_has_smm();
-+        smm_available = false;
-     }
-     if (smm_available) {
--- 
-2.1.4
-
diff --git a/debian/patches/pve/0029-vnc-make-x509-imply-tls-again.patch b/debian/patches/pve/0029-vnc-make-x509-imply-tls-again.patch
new file mode 100644 (file)
index 0000000..cb9802a
--- /dev/null
@@ -0,0 +1,28 @@
+From a826a6ead084ea0d86680c6e9901f4f51ee5beb0 Mon Sep 17 00:00:00 2001
+From: Wolfgang Bumiller <w.bumiller@proxmox.com>
+Date: Tue, 12 Jan 2016 09:09:49 +0100
+Subject: [PATCH 29/41] vnc: make x509 imply tls again
+
+---
+ ui/vnc.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/ui/vnc.c b/ui/vnc.c
+index 8d7d435..a7f5f1e 100644
+--- a/ui/vnc.c
++++ b/ui/vnc.c
+@@ -3725,9 +3725,8 @@ void vnc_display_open(const char *id, Error **errp)
+         const char *path;
+         bool tls = false, x509 = false, x509verify = false;
+         tls  = qemu_opt_get_bool(opts, "tls", false);
+-        if (tls) {
+-            path = qemu_opt_get(opts, "x509");
+-
++        path = qemu_opt_get(opts, "x509");
++        if (tls || path) {
+             if (path) {
+                 x509 = true;
+             } else {
+-- 
+2.1.4
+
diff --git a/debian/patches/pve/0030-PVE-VNC-authentication.patch b/debian/patches/pve/0030-PVE-VNC-authentication.patch
new file mode 100644 (file)
index 0000000..c372151
--- /dev/null
@@ -0,0 +1,683 @@
+From 09e462b87b17f37fa98a2745dcf2d14c981b7e95 Mon Sep 17 00:00:00 2001
+From: Wolfgang Bumiller <w.bumiller@proxmox.com>
+Date: Mon, 11 Jan 2016 10:40:31 +0100
+Subject: [PATCH 30/41] PVE VNC authentication
+
+---
+ crypto/tlscreds.c         |  47 +++++++++++
+ crypto/tlscredspriv.h     |   2 +
+ crypto/tlscredsx509.c     |  13 ++--
+ crypto/tlssession.c       |   1 +
+ include/crypto/tlscreds.h |   1 +
+ include/ui/console.h      |   1 +
+ qemu-options.hx           |   3 +
+ ui/vnc-auth-vencrypt.c    | 194 ++++++++++++++++++++++++++++++++++++++--------
+ ui/vnc.c                  | 140 ++++++++++++++++++++++++++++++++-
+ ui/vnc.h                  |   4 +
+ vl.c                      |   9 +++
+ 11 files changed, 375 insertions(+), 40 deletions(-)
+
+diff --git a/crypto/tlscreds.c b/crypto/tlscreds.c
+index a896553..e9ae13c 100644
+--- a/crypto/tlscreds.c
++++ b/crypto/tlscreds.c
+@@ -158,6 +158,33 @@ qcrypto_tls_creds_prop_get_verify(Object *obj,
+ static void
++qcrypto_tls_creds_prop_set_pve(Object *obj,
++                                 bool value,
++                                 Error **errp G_GNUC_UNUSED)
++{
++    QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
++
++    creds->pve = value;
++}
++
++
++static bool
++qcrypto_tls_creds_prop_get_pve(Object *obj,
++                                  Error **errp G_GNUC_UNUSED)
++{
++    QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
++
++    return creds->pve;
++}
++
++bool qcrypto_tls_creds_is_pve(QCryptoTLSCreds *creds)
++{
++    Error *errp = NULL;
++    return qcrypto_tls_creds_prop_get_pve((Object*)creds, &errp);
++}
++
++
++static void
+ qcrypto_tls_creds_prop_set_dir(Object *obj,
+                                const char *value,
+                                Error **errp G_GNUC_UNUSED)
+@@ -250,6 +277,26 @@ qcrypto_tls_creds_init(Object *obj)
+     QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
+     creds->verifyPeer = true;
++    creds->pve = false;
++
++    object_property_add_bool(obj, "verify-peer",
++                             qcrypto_tls_creds_prop_get_verify,
++                             qcrypto_tls_creds_prop_set_verify,
++                             NULL);
++    object_property_add_bool(obj, "pve",
++                             qcrypto_tls_creds_prop_get_pve,
++                             qcrypto_tls_creds_prop_set_pve,
++                             NULL);
++    object_property_add_str(obj, "dir",
++                            qcrypto_tls_creds_prop_get_dir,
++                            qcrypto_tls_creds_prop_set_dir,
++                            NULL);
++    object_property_add_enum(obj, "endpoint",
++                             "QCryptoTLSCredsEndpoint",
++                             QCryptoTLSCredsEndpoint_lookup,
++                             qcrypto_tls_creds_prop_get_endpoint,
++                             qcrypto_tls_creds_prop_set_endpoint,
++                             NULL);
+ }
+diff --git a/crypto/tlscredspriv.h b/crypto/tlscredspriv.h
+index 13e9b6c..0356acc 100644
+--- a/crypto/tlscredspriv.h
++++ b/crypto/tlscredspriv.h
+@@ -36,6 +36,8 @@ int qcrypto_tls_creds_get_dh_params_file(QCryptoTLSCreds *creds,
+                                          gnutls_dh_params_t *dh_params,
+                                          Error **errp);
++bool qcrypto_tls_creds_is_pve(QCryptoTLSCreds *creds);
++
+ #endif
+ #endif /* QCRYPTO_TLSCREDSPRIV_H */
+diff --git a/crypto/tlscredsx509.c b/crypto/tlscredsx509.c
+index 520d34d..1ba971c 100644
+--- a/crypto/tlscredsx509.c
++++ b/crypto/tlscredsx509.c
+@@ -555,22 +555,23 @@ qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds,
+         *key = NULL, *dhparams = NULL;
+     int ret;
+     int rv = -1;
++    bool pve = qcrypto_tls_creds_is_pve(&creds->parent_obj);
+     trace_qcrypto_tls_creds_x509_load(creds,
+             creds->parent_obj.dir ? creds->parent_obj.dir : "<nodir>");
+     if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
+         if (qcrypto_tls_creds_get_path(&creds->parent_obj,
+-                                       QCRYPTO_TLS_CREDS_X509_CA_CERT,
++                                       pve ? "pve-root-ca.pem" : QCRYPTO_TLS_CREDS_X509_CA_CERT,
+                                        true, &cacert, errp) < 0 ||
+             qcrypto_tls_creds_get_path(&creds->parent_obj,
+                                        QCRYPTO_TLS_CREDS_X509_CA_CRL,
+                                        false, &cacrl, errp) < 0 ||
+             qcrypto_tls_creds_get_path(&creds->parent_obj,
+-                                       QCRYPTO_TLS_CREDS_X509_SERVER_CERT,
++                                       pve ? "local/pve-ssl.pem" : QCRYPTO_TLS_CREDS_X509_SERVER_CERT,
+                                        true, &cert, errp) < 0 ||
+             qcrypto_tls_creds_get_path(&creds->parent_obj,
+-                                       QCRYPTO_TLS_CREDS_X509_SERVER_KEY,
++                                       pve ? "local/pve-ssl.key" : QCRYPTO_TLS_CREDS_X509_SERVER_KEY,
+                                        true, &key, errp) < 0 ||
+             qcrypto_tls_creds_get_path(&creds->parent_obj,
+                                        QCRYPTO_TLS_CREDS_DH_PARAMS,
+@@ -579,13 +580,13 @@ qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds,
+         }
+     } else {
+         if (qcrypto_tls_creds_get_path(&creds->parent_obj,
+-                                       QCRYPTO_TLS_CREDS_X509_CA_CERT,
++                                       pve ? "pve-root-ca.pem" : QCRYPTO_TLS_CREDS_X509_CA_CERT,
+                                        true, &cacert, errp) < 0 ||
+             qcrypto_tls_creds_get_path(&creds->parent_obj,
+-                                       QCRYPTO_TLS_CREDS_X509_CLIENT_CERT,
++                                       pve ? "local/pve-ssl.pem" : QCRYPTO_TLS_CREDS_X509_CLIENT_CERT,
+                                        false, &cert, errp) < 0 ||
+             qcrypto_tls_creds_get_path(&creds->parent_obj,
+-                                       QCRYPTO_TLS_CREDS_X509_CLIENT_KEY,
++                                       pve ? "local/pve-ssl.key" : QCRYPTO_TLS_CREDS_X509_CLIENT_KEY,
+                                        false, &key, errp) < 0) {
+             goto cleanup;
+         }
+diff --git a/crypto/tlssession.c b/crypto/tlssession.c
+index 2de42c6..768466a 100644
+--- a/crypto/tlssession.c
++++ b/crypto/tlssession.c
+@@ -23,6 +23,7 @@
+ #include "crypto/tlscredsanon.h"
+ #include "crypto/tlscredsx509.h"
+ #include "qapi/error.h"
++#include "crypto/tlscredspriv.h"
+ #include "qemu/acl.h"
+ #include "trace.h"
+diff --git a/include/crypto/tlscreds.h b/include/crypto/tlscreds.h
+index ad47d88..f86d379 100644
+--- a/include/crypto/tlscreds.h
++++ b/include/crypto/tlscreds.h
+@@ -55,6 +55,7 @@ struct QCryptoTLSCreds {
+ #endif
+     bool verifyPeer;
+     char *priority;
++    bool pve;
+ };
+diff --git a/include/ui/console.h b/include/ui/console.h
+index 2703a3a..db6dd22 100644
+--- a/include/ui/console.h
++++ b/include/ui/console.h
+@@ -456,6 +456,7 @@ static inline void cocoa_display_init(DisplayState *ds, int full_screen)
+ #endif
+ /* vnc.c */
++void pve_auth_setup(int vmid);
+ void vnc_display_init(const char *id);
+ void vnc_display_open(const char *id, Error **errp);
+ void vnc_display_add_client(const char *id, int csock, bool skipauth);
+diff --git a/qemu-options.hx b/qemu-options.hx
+index 37fad3b..f943ae6 100644
+--- a/qemu-options.hx
++++ b/qemu-options.hx
+@@ -473,6 +473,9 @@ STEXI
+ @table @option
+ ETEXI
++DEF("id", HAS_ARG, QEMU_OPTION_id,
++    "-id n         set the VMID\n", QEMU_ARCH_ALL)
++
+ DEF("fda", HAS_ARG, QEMU_OPTION_fda,
+     "-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 11c8c9a..d11f1df 100644
+--- a/ui/vnc-auth-vencrypt.c
++++ b/ui/vnc-auth-vencrypt.c
+@@ -28,6 +28,107 @@
+ #include "vnc.h"
+ #include "qapi/error.h"
+ #include "qemu/main-loop.h"
++#include "qemu/sockets.h"
++
++static int protocol_client_auth_plain(VncState *vs, uint8_t *data, size_t len)
++{
++      const char *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));
++      }
++
++      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";
++              goto err;
++      }
++
++      strncpy(username, (char *)data, vs->username_len);
++      username[vs->username_len] = 0;
++      strncpy(passwd, (char *)data + vs->username_len, vs->password_len);
++      passwd[vs->password_len] = 0;
++
++      VNC_DEBUG("AUTH PLAIN username: %s pw: %s\n", username, passwd);
++
++      if (pve_auth_verify(clientip, username, passwd) == 0) {
++              vnc_write_u32(vs, 0); /* Accept auth completion */
++              start_client_init(vs);
++              return 0;
++      }
++
++      err =  "Authentication failed";
++err:
++       if (err) {
++             VNC_DEBUG("AUTH PLAIN ERROR: %s\n", err);
++             vnc_write_u32(vs, 1); /* Reject auth */
++             if (vs->minor >= 8) {
++                     int elen = strlen(err);
++                     vnc_write_u32(vs, elen);
++                     vnc_write(vs, err, elen);
++             }
++       }
++       vnc_flush(vs);
++       vnc_client_error(vs);
++
++       return 0;
++
++}
++
++static int protocol_client_auth_plain_start(VncState *vs, uint8_t *data, size_t len)
++{
++      uint32_t ulen = read_u32(data, 0);
++      uint32_t pwlen = read_u32(data, 4);
++      const char *err = NULL;
++
++      VNC_DEBUG("AUTH PLAIN START %u %u\n", ulen, pwlen);
++
++       if (!ulen) {
++             err = "No User name.";
++             goto err;
++       }
++       if (ulen >= 255) {
++             err = "User name too long.";
++             goto err;
++       }
++       if (!pwlen) {
++             err = "Password too short";
++             goto err;
++       }
++       if (pwlen >= 511) {
++             err = "Password too long.";
++             goto err;
++       }
++
++       vs->username_len = ulen;
++       vs->password_len = pwlen;
++
++       vnc_read_when(vs, protocol_client_auth_plain, ulen + pwlen);
++
++       return 0;
++err:
++       if (err) {
++             VNC_DEBUG("AUTH PLAIN ERROR: %s\n", err);
++             vnc_write_u32(vs, 1); /* Reject auth */
++             if (vs->minor >= 8) {
++                     int elen = strlen(err);
++                     vnc_write_u32(vs, elen);
++                     vnc_write(vs, err, elen);
++             }
++       }
++       vnc_flush(vs);
++       vnc_client_error(vs);
++
++       return 0;
++}
+ static void start_auth_vencrypt_subauth(VncState *vs)
+ {
+@@ -39,6 +140,17 @@ static void start_auth_vencrypt_subauth(VncState *vs)
+        start_client_init(vs);
+        break;
++    case VNC_AUTH_VENCRYPT_TLSPLAIN:
++    case VNC_AUTH_VENCRYPT_X509PLAIN:
++       VNC_DEBUG("Start TLS auth PLAIN\n");
++       vnc_read_when(vs, protocol_client_auth_plain_start, 8);
++       break;
++
++    case VNC_AUTH_VENCRYPT_PLAIN:
++       VNC_DEBUG("Start auth PLAIN\n");
++       vnc_read_when(vs, protocol_client_auth_plain_start, 8);
++       break;
++
+     case VNC_AUTH_VENCRYPT_TLSVNC:
+     case VNC_AUTH_VENCRYPT_X509VNC:
+        VNC_DEBUG("Start TLS auth VNC\n");
+@@ -87,44 +199,63 @@ static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len
+ {
+     int auth = read_u32(data, 0);
+-    if (auth != vs->subauth) {
++    if (auth != vs->subauth && auth != VNC_AUTH_VENCRYPT_PLAIN) {
+         VNC_DEBUG("Rejecting auth %d\n", auth);
+         vnc_write_u8(vs, 0); /* Reject auth */
+         vnc_flush(vs);
+         vnc_client_error(vs);
+     } else {
+-        Error *err = NULL;
+-        QIOChannelTLS *tls;
+-        VNC_DEBUG("Accepting auth %d, setting up TLS for handshake\n", auth);
+-        vnc_write_u8(vs, 1); /* Accept auth */
+-        vnc_flush(vs);
+-
+-        if (vs->ioc_tag) {
+-            g_source_remove(vs->ioc_tag);
+-            vs->ioc_tag = 0;
++        if (auth == VNC_AUTH_VENCRYPT_PLAIN) {
++            vs->subauth = auth;
++            start_auth_vencrypt_subauth(vs);
+         }
++        else
++        {
++            Error *err = NULL;
++            QIOChannelTLS *tls;
++            VNC_DEBUG("Accepting auth %d, setting up TLS for handshake\n", auth);
++            vnc_write_u8(vs, 1); /* Accept auth */
++            vnc_flush(vs);
+-        tls = qio_channel_tls_new_server(
+-            vs->ioc,
+-            vs->vd->tlscreds,
+-            vs->vd->tlsaclname,
+-            &err);
+-        if (!tls) {
+-            VNC_DEBUG("Failed to setup TLS %s\n", error_get_pretty(err));
+-            error_free(err);
+-            vnc_client_error(vs);
+-            return 0;
+-        }
++            if (vs->ioc_tag) {
++                g_source_remove(vs->ioc_tag);
++                vs->ioc_tag = 0;
++            }
+-        VNC_DEBUG("Start TLS VeNCrypt handshake process\n");
+-        object_unref(OBJECT(vs->ioc));
+-        vs->ioc = QIO_CHANNEL(tls);
+-        vs->tls = qio_channel_tls_get_session(tls);
++            tls = qio_channel_tls_new_server(
++                vs->ioc,
++                vs->vd->tlscreds,
++                vs->vd->tlsaclname,
++                &err);
++            if (!tls) {
++                VNC_DEBUG("Failed to setup TLS %s\n", error_get_pretty(err));
++                error_free(err);
++                vnc_client_error(vs);
++                return 0;
++                vs->tls = qcrypto_tls_session_new(vs->vd->tlscreds,
++                                                  NULL,
++                                                  vs->vd->tlsaclname,
++                                                  QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
++                                                  &err);
++                if (!vs->tls) {
++                    VNC_DEBUG("Failed to setup TLS %s\n",
++                              error_get_pretty(err));
++                    error_free(err);
++                    vnc_client_error(vs);
++                    return 0;
++                }
++            }
+-        qio_channel_tls_handshake(tls,
+-                                  vnc_tls_handshake_done,
+-                                  vs,
+-                                  NULL);
++            VNC_DEBUG("Start TLS VeNCrypt handshake process\n");
++            object_unref(OBJECT(vs->ioc));
++            vs->ioc = QIO_CHANNEL(tls);
++            vs->tls = qio_channel_tls_get_session(tls);
++
++            qio_channel_tls_handshake(tls,
++                                      vnc_tls_handshake_done,
++                                      vs,
++                                      NULL);
++        }
+     }
+     return 0;
+ }
+@@ -138,10 +269,11 @@ static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len
+         vnc_flush(vs);
+         vnc_client_error(vs);
+     } else {
+-        VNC_DEBUG("Sending allowed auth %d\n", vs->subauth);
++        VNC_DEBUG("Sending allowed auths %d %d\n", vs->subauth, VNC_AUTH_VENCRYPT_PLAIN);
+         vnc_write_u8(vs, 0); /* Accept version */
+-        vnc_write_u8(vs, 1); /* Number of sub-auths */
++        vnc_write_u8(vs, 2); /* Number of sub-auths */
+         vnc_write_u32(vs, vs->subauth); /* The supported auth */
++        vnc_write_u32(vs, VNC_AUTH_VENCRYPT_PLAIN); /* Alternative supported auth */
+         vnc_flush(vs);
+         vnc_read_when(vs, protocol_client_vencrypt_auth, 4);
+     }
+diff --git a/ui/vnc.c b/ui/vnc.c
+index a7f5f1e..6b73667 100644
+--- a/ui/vnc.c
++++ b/ui/vnc.c
+@@ -55,6 +55,125 @@ static const struct timeval VNC_REFRESH_LOSSY = { 2, 0 };
+ #include "vnc_keysym.h"
+ #include "crypto/cipher.h"
++static int pve_vmid = 0;
++
++void pve_auth_setup(int vmid) {
++      pve_vmid = vmid;
++}
++
++static char *
++urlencode(char *buf, const char *value)
++{
++      static const char *hexchar = "0123456789abcdef";
++      char *p = buf;
++      int i;
++      int l = strlen(value);
++      for (i = 0; i < l; i++) {
++              char c = value[i];
++              if (('a' <= c && c <= 'z') ||
++                  ('A' <= c && c <= 'Z') ||
++                  ('0' <= c && c <= '9')) {
++                      *p++ = c;
++              } else if (c == 32) {
++                      *p++ = '+';
++              } else {
++                      *p++ = '%';
++                      *p++ = hexchar[c >> 4];
++                      *p++ = hexchar[c & 15];
++              }
++      }
++      *p = 0;
++
++      return p;
++}
++
++int
++pve_auth_verify(const char *clientip, const char *username, const char *passwd)
++{
++      struct sockaddr_in server;
++
++      int sfd = socket(AF_INET, SOCK_STREAM, 0);
++      if (sfd == -1) {
++              perror("pve_auth_verify: socket failed");
++              return -1;
++      }
++
++      struct hostent *he;
++      if ((he = gethostbyname("localhost")) == NULL) {
++              fprintf(stderr, "pve_auth_verify: error resolving hostname\n");
++              goto err;
++      }
++
++      memcpy(&server.sin_addr, he->h_addr_list[0], he->h_length);
++      server.sin_family = AF_INET;
++      server.sin_port = htons(85);
++
++      if (connect(sfd, (struct sockaddr *)&server, sizeof(server))) {
++              perror("pve_auth_verify: error connecting to server");
++              goto err;
++      }
++
++      char buf[8192];
++      char form[8192];
++
++      char *p = form;
++      p = urlencode(p, "username");
++      *p++ = '=';
++      p = urlencode(p, username);
++
++      *p++ = '&';
++      p = urlencode(p, "password");
++      *p++ = '=';
++      p = urlencode(p, passwd);
++
++      *p++ = '&';
++      p = urlencode(p, "path");
++      *p++ = '=';
++      char authpath[256];
++      sprintf(authpath, "/vms/%d", pve_vmid);
++      p = urlencode(p, authpath);
++
++      *p++ = '&';
++      p = urlencode(p, "privs");
++      *p++ = '=';
++      p = urlencode(p, "VM.Console");
++
++      sprintf(buf, "POST /api2/json/access/ticket HTTP/1.1\n"
++              "Host: localhost:85\n"
++              "Connection: close\n"
++              "PVEClientIP: %s\n"
++              "Content-Type: application/x-www-form-urlencoded\n"
++              "Content-Length: %zd\n\n%s\n", clientip, strlen(form), form);
++      ssize_t len = strlen(buf);
++      ssize_t sb = send(sfd, buf, len, 0);
++      if (sb < 0) {
++              perror("pve_auth_verify: send failed");
++              goto err;
++      }
++      if (sb != len) {
++              fprintf(stderr, "pve_auth_verify: partial send error\n");
++              goto err;
++      }
++
++      len = recv(sfd, buf, sizeof(buf) - 1, 0);
++      if (len < 0) {
++              perror("pve_auth_verify: recv failed");
++              goto err;
++      }
++
++      buf[len] = 0;
++
++      //printf("DATA:%s\n", buf);
++
++      shutdown(sfd, SHUT_RDWR);
++
++      return strncmp(buf, "HTTP/1.1 200 OK", 15);
++
++err:
++      shutdown(sfd, SHUT_RDWR);
++      return -1;
++}
++
+ static QTAILQ_HEAD(, VncDisplay) vnc_displays =
+     QTAILQ_HEAD_INITIALIZER(vnc_displays);
+@@ -3409,11 +3528,17 @@ vnc_display_setup_auth(VncDisplay *vs,
+             if (object_dynamic_cast(OBJECT(vs->tlscreds),
+                                     TYPE_QCRYPTO_TLS_CREDS_X509)) {
+                 VNC_DEBUG("Initializing VNC server with x509 password auth\n");
+-                vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
++                if (vs->tlscreds->pve)
++                    vs->subauth = VNC_AUTH_VENCRYPT_X509PLAIN;
++                else
++                    vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
+             } else if (object_dynamic_cast(OBJECT(vs->tlscreds),
+                                            TYPE_QCRYPTO_TLS_CREDS_ANON)) {
+                 VNC_DEBUG("Initializing VNC server with TLS password auth\n");
+-                vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
++                if (vs->tlscreds->pve)
++                    vs->subauth = VNC_AUTH_VENCRYPT_TLSPLAIN;
++                else
++                    vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
+             } else {
+                 error_setg(errp,
+                            "Unsupported TLS cred type %s",
+@@ -3504,6 +3629,7 @@ vnc_display_create_creds(bool x509,
+                          bool x509verify,
+                          const char *dir,
+                          const char *id,
++                         bool pve,
+                          Error **errp)
+ {
+     gchar *credsid = g_strdup_printf("tlsvnc%s", id);
+@@ -3519,6 +3645,7 @@ vnc_display_create_creds(bool x509,
+                                       "endpoint", "server",
+                                       "dir", dir,
+                                       "verify-peer", x509verify ? "yes" : "no",
++                                      "pve", pve ? "yes" : "no",
+                                       NULL);
+     } else {
+         creds = object_new_with_props(TYPE_QCRYPTO_TLS_CREDS_ANON,
+@@ -3526,6 +3653,7 @@ vnc_display_create_creds(bool x509,
+                                       credsid,
+                                       &err,
+                                       "endpoint", "server",
++                                      "pve", pve ? "yes" : "no",
+                                       NULL);
+     }
+@@ -3723,12 +3851,17 @@ void vnc_display_open(const char *id, Error **errp)
+         }
+     } else {
+         const char *path;
+-        bool tls = false, x509 = false, x509verify = false;
++        bool tls = false, x509 = false, x509verify = false, pve = false;
+         tls  = qemu_opt_get_bool(opts, "tls", false);
+         path = qemu_opt_get(opts, "x509");
+         if (tls || path) {
+             if (path) {
+                 x509 = true;
++                if (!strcmp(path, "on")) {
++                    /* magic to default to /etc/pve */
++                    path = "/etc/pve";
++                    pve = true;
++                }
+             } else {
+                 path = qemu_opt_get(opts, "x509verify");
+                 if (path) {
+@@ -3740,6 +3873,7 @@ void vnc_display_open(const char *id, Error **errp)
+                                                     x509verify,
+                                                     path,
+                                                     vs->id,
++                                                    pve,
+                                                     errp);
+             if (!vs->tlscreds) {
+                 goto fail;
+diff --git a/ui/vnc.h b/ui/vnc.h
+index ab5f244..2fde9d3 100644
+--- a/ui/vnc.h
++++ b/ui/vnc.h
+@@ -282,6 +282,8 @@ struct VncState
+     int auth;
+     int subauth; /* Used by VeNCrypt */
+     char challenge[VNC_AUTH_CHALLENGE_SIZE];
++    int username_len;
++    int password_len;
+     QCryptoTLSSession *tls; /* Borrowed pointer from channel, don't free */
+ #ifdef CONFIG_VNC_SASL
+     VncStateSASL sasl;
+@@ -577,4 +579,6 @@ int vnc_zrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
+ int vnc_zywrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
+ void vnc_zrle_clear(VncState *vs);
++int pve_auth_verify(const char *clientip, const char *username, const char *passwd);
++
+ #endif /* QEMU_VNC_H */
+diff --git a/vl.c b/vl.c
+index fefc0bd..7813b78 100644
+--- a/vl.c
++++ b/vl.c
+@@ -2936,6 +2936,7 @@ static int global_init_func(void *opaque, QemuOpts *opts, Error **errp)
+ int main(int argc, char **argv, char **envp)
+ {
+     int i;
++    long int vm_id_long = 0;
+     int snapshot, linux_boot;
+     const char *initrd_filename;
+     const char *kernel_filename, *kernel_cmdline;
+@@ -3708,6 +3709,14 @@ int main(int argc, char **argv, char **envp)
+                     exit(1);
+                 }
+                 break;
++            case QEMU_OPTION_id:
++                vm_id_long = strtol(optarg, (char **) &optarg, 10);
++                if (*optarg != 0 || vm_id_long < 100 || vm_id_long > INT_MAX) {
++                    fprintf(stderr, "Invalid ID\n");
++                    exit(1);
++                }
++                pve_auth_setup(vm_id_long);
++                break;
+             case QEMU_OPTION_vnc:
+                 vnc_parse(optarg, &error_fatal);
+                 break;
+-- 
+2.1.4
+
diff --git a/debian/patches/pve/0030-use-whitespace-between-VERSION-and-PKGVERSION.patch b/debian/patches/pve/0030-use-whitespace-between-VERSION-and-PKGVERSION.patch
deleted file mode 100644 (file)
index f28a147..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-From 011e629353ed4aeac6eeb7f1c9021b4906ae2946 Mon Sep 17 00:00:00 2001
-From: Wolfgang Bumiller <w.bumiller@proxmox.com>
-Date: Wed, 9 Dec 2015 16:50:05 +0100
-Subject: [PATCH 30/55] 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()
----
- vl.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/vl.c b/vl.c
-index ba29593..f393767 100644
---- a/vl.c
-+++ b/vl.c
-@@ -1949,7 +1949,7 @@ static void main_loop(void)
- static void version(void)
- {
--    printf("QEMU emulator version " QEMU_VERSION QEMU_PKGVERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n");
-+    printf("QEMU emulator version " QEMU_VERSION " " QEMU_PKGVERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n");
- }
- static void help(int exitcode)
--- 
-2.1.4
-
diff --git a/debian/patches/pve/0031-vma-add-firewall.patch b/debian/patches/pve/0031-vma-add-firewall.patch
deleted file mode 100644 (file)
index fa85138..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-From a89fc66658089da88eae095b3faa377c25db0198 Mon Sep 17 00:00:00 2001
-From: Wolfgang Bumiller <w.bumiller@proxmox.com>
-Date: Wed, 9 Dec 2015 16:51:23 +0100
-Subject: [PATCH 31/55] vma: add firewall
-
----
- blockdev.c       | 78 ++++++++++++++++++++++++++++++++++----------------------
- hmp.c            |  2 +-
- qapi-schema.json |  1 +
- qmp-commands.hx  |  2 +-
- 4 files changed, 51 insertions(+), 32 deletions(-)
-
-diff --git a/blockdev.c b/blockdev.c
-index 0131e92..dd4e4bd 100644
---- a/blockdev.c
-+++ b/blockdev.c
-@@ -3170,6 +3170,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;
-+}
-+
- static void pvebackup_run_next_job(void)
- {
-     GList *l = backup_state.di_list;
-@@ -3196,6 +3234,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)
- {
-@@ -3348,38 +3387,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 78644a7..f989f01 100644
---- a/hmp.c
-+++ b/hmp.c
-@@ -1533,7 +1533,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 d1985d2..2c31eb1 100644
---- a/qapi-schema.json
-+++ b/qapi-schema.json
-@@ -420,6 +420,7 @@
- { 'command': 'backup', 'data': { 'backup-file': 'str',
-                                     '*format': 'BackupFormat',
-                                     '*config-file': 'str',
-+                                    '*firewall-file': 'str',
-                                     '*devlist': 'str', '*speed': 'int' },
-   'returns': 'UuidInfo' }
-diff --git a/qmp-commands.hx b/qmp-commands.hx
-index 71c5d53..964563e 100644
---- a/qmp-commands.hx
-+++ b/qmp-commands.hx
-@@ -1280,7 +1280,7 @@ EQMP
-     {
-         .name       = "backup",
--        .args_type  = "backup-file:s,format:s?,config-file:F?,speed:o?,devlist:s?",
-+        .args_type  = "backup-file:s,format:s?,config-file:F?,firewall-file:F?,speed:o?,devlist:s?",
-         .mhandler.cmd_new = qmp_marshal_input_backup,
-     },
--- 
-2.1.4
-
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
new file mode 100644 (file)
index 0000000..27f28ea
--- /dev/null
@@ -0,0 +1,24 @@
+From 9625add5f8199243a7b3a4fa045adf25f99ed52d Mon Sep 17 00:00:00 2001
+From: Wolfgang Bumiller <w.bumiller@proxmox.com>
+Date: Mon, 8 Feb 2016 08:23:34 +0100
+Subject: [PATCH 31/41] 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 0d26fc6..a378762 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.1.4
+
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
new file mode 100644 (file)
index 0000000..f1699eb
--- /dev/null
@@ -0,0 +1,42 @@
+From 88f2fbcb13778b146482f034d88968ed3ea57a6b Mon Sep 17 00:00:00 2001
+From: Wolfgang Bumiller <w.bumiller@proxmox.com>
+Date: Tue, 23 Feb 2016 15:48:41 +0100
+Subject: [PATCH 32/41] 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 08e4725..8a27704 100644
+--- a/vma.c
++++ b/vma.c
+@@ -293,7 +293,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.1.4
+
diff --git a/debian/patches/pve/0032-vma-writer-aio_set_fd_handler-update.patch b/debian/patches/pve/0032-vma-writer-aio_set_fd_handler-update.patch
deleted file mode 100644 (file)
index ba47286..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-From 2d152da7999e912f6fc104f81a1616c3c6d96a89 Mon Sep 17 00:00:00 2001
-From: Wolfgang Bumiller <w.bumiller@proxmox.com>
-Date: Thu, 10 Dec 2015 14:25:01 +0100
-Subject: [PATCH 32/55] vma-writer: aio_set_fd_handler update
-
-passing 'false' as new is_external parameter to
-aio_set_fd_handler as per commit
-dca21e23ba: aio: Add "is_external" flag for event handlers
-
-For-patch: introduce new vma archive format
----
- vma-writer.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/vma-writer.c b/vma-writer.c
-index 5cc4564..f5a7abd 100644
---- a/vma-writer.c
-+++ b/vma-writer.c
-@@ -231,9 +231,9 @@ vma_queue_write(VmaWriter *vmaw, const void *buf, size_t bytes)
-     vmaw->co_writer = qemu_coroutine_self();
-     while (done < bytes) {
--        aio_set_fd_handler(qemu_get_aio_context(), vmaw->fd, NULL, vma_co_continue_write, vmaw);
-+        aio_set_fd_handler(qemu_get_aio_context(), vmaw->fd, false, NULL, vma_co_continue_write, vmaw);
-         qemu_coroutine_yield();
--        aio_set_fd_handler(qemu_get_aio_context(), vmaw->fd, NULL, NULL, NULL);
-+        aio_set_fd_handler(qemu_get_aio_context(), vmaw->fd, false, NULL, NULL, NULL);
-         if (vmaw->status < 0) {
-             DPRINTF("vma_queue_write detected canceled backup\n");
-             done = -1;
--- 
-2.1.4
-
diff --git a/debian/patches/pve/0033-block-add-the-zeroinit-block-driver-filter.patch b/debian/patches/pve/0033-block-add-the-zeroinit-block-driver-filter.patch
new file mode 100644 (file)
index 0000000..3eb9842
--- /dev/null
@@ -0,0 +1,252 @@
+From 01bb198e6aba040636af95939fcf933383e19835 Mon Sep 17 00:00:00 2001
+From: Wolfgang Bumiller <w.bumiller@proxmox.com>
+Date: Thu, 17 Mar 2016 11:33:37 +0100
+Subject: [PATCH 33/41] block: add the zeroinit block driver filter
+
+---
+ block/Makefile.objs |   1 +
+ 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
+index 2593a2f..930ca33 100644
+--- a/block/Makefile.objs
++++ b/block/Makefile.objs
+@@ -4,6 +4,7 @@ block-obj-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
+ block-obj-y += qed-check.o
+ block-obj-$(CONFIG_VHDX) += vhdx.o vhdx-endian.o vhdx-log.o
+ block-obj-y += quorum.o
++block-obj-y += zeroinit.o
+ block-obj-y += parallels.o blkdebug.o blkverify.o blkreplay.o
+ block-obj-y += block-backend.o snapshot.o qapi.o
+ block-obj-$(CONFIG_WIN32) += raw-win32.o win32-aio.o
+diff --git a/block/zeroinit.c b/block/zeroinit.c
+new file mode 100644
+index 0000000..c56a446
+--- /dev/null
++++ b/block/zeroinit.c
+@@ -0,0 +1,220 @@
++/*
++ * Filter to fake a zero-initialized block device.
++ *
++ * Copyright (c) 2016 Wolfgang Bumiller <w.bumiller@proxmox.com>
++ * Copyright (c) 2016 Proxmox Server Solutions GmbH
++ *
++ * This work is licensed under the terms of the GNU GPL, version 2 or later.
++ * See the COPYING file in the top-level directory.
++ */
++
++#include "qemu/osdep.h"
++#include "qapi/error.h"
++#include "block/block_int.h"
++#include "qapi/qmp/qdict.h"
++#include "qapi/qmp/qstring.h"
++#include "qemu/cutils.h"
++
++typedef struct {
++    bool has_zero_init;
++    int64_t extents;
++} BDRVZeroinitState;
++
++/* Valid blkverify filenames look like blkverify:path/to/raw_image:path/to/image */
++static void zeroinit_parse_filename(const char *filename, QDict *options,
++                                     Error **errp)
++{
++    QString *raw_path;
++
++    /* Parse the blkverify: prefix */
++    if (!strstart(filename, "zeroinit:", &filename)) {
++        /* There was no prefix; therefore, all options have to be already
++           present in the QDict (except for the filename) */
++        return;
++    }
++
++    raw_path = qstring_from_str(filename);
++    qdict_put(options, "x-next", raw_path);
++}
++
++static QemuOptsList runtime_opts = {
++    .name = "zeroinit",
++    .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
++    .desc = {
++        {
++            .name = "x-next",
++            .type = QEMU_OPT_STRING,
++            .help = "[internal use only, will be removed]",
++        },
++        {
++            .name = "x-zeroinit",
++            .type = QEMU_OPT_BOOL,
++            .help = "set has_initialized_zero flag",
++        },
++        { /* end of list */ }
++    },
++};
++
++static int zeroinit_open(BlockDriverState *bs, QDict *options, int flags,
++                          Error **errp)
++{
++    BDRVZeroinitState *s = bs->opaque;
++    QemuOpts *opts;
++    Error *local_err = NULL;
++    int ret;
++
++    s->extents = 0;
++
++    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 fail;
++    }
++
++    /* Open the raw file */
++    bs->file = bdrv_open_child(qemu_opt_get(opts, "x-next"), options, "next",
++                               bs, &child_file, false, &local_err);
++    if (local_err) {
++        ret = -EINVAL;
++        error_propagate(errp, local_err);
++        goto fail;
++    }
++
++    /* set the options */
++    s->has_zero_init = qemu_opt_get_bool(opts, "x-zeroinit", true);
++
++    ret = 0;
++fail:
++    if (ret < 0) {
++        bdrv_unref_child(bs, bs->file);
++    }
++    qemu_opts_del(opts);
++    return ret;
++}
++
++static void zeroinit_close(BlockDriverState *bs)
++{
++    BDRVZeroinitState *s = bs->opaque;
++    (void)s;
++}
++
++static int64_t zeroinit_getlength(BlockDriverState *bs)
++{
++    return bdrv_getlength(bs->file->bs);
++}
++
++static BlockAIOCB *zeroinit_aio_readv(BlockDriverState *bs,
++        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
++        BlockCompletionFunc *cb, void *opaque)
++{
++    return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors,
++                          cb, opaque);
++}
++
++static int coroutine_fn zeroinit_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
++                                                 int count, BdrvRequestFlags flags)
++{
++    BDRVZeroinitState *s = bs->opaque;
++    if (offset >= s->extents)
++        return 0;
++    return bdrv_pwrite_zeroes(bs->file, offset, count, flags);
++}
++
++static BlockAIOCB *zeroinit_aio_writev(BlockDriverState *bs,
++        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
++        BlockCompletionFunc *cb, void *opaque)
++{
++    BDRVZeroinitState *s = bs->opaque;
++    int64_t extents = (sector_num << BDRV_SECTOR_BITS) + ((nb_sectors + 1) << BDRV_SECTOR_BITS);
++    if (extents > s->extents)
++        s->extents = extents;
++    return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors,
++                           cb, opaque);
++}
++
++static BlockAIOCB *zeroinit_aio_flush(BlockDriverState *bs,
++                                       BlockCompletionFunc *cb,
++                                       void *opaque)
++{
++    return bdrv_aio_flush(bs->file->bs, cb, opaque);
++}
++
++static bool zeroinit_recurse_is_first_non_filter(BlockDriverState *bs,
++                                                  BlockDriverState *candidate)
++{
++    return bdrv_recurse_is_first_non_filter(bs->file->bs, candidate);
++}
++
++static coroutine_fn int zeroinit_co_flush(BlockDriverState *bs)
++{
++    return bdrv_co_flush(bs->file->bs);
++}
++
++static int zeroinit_has_zero_init(BlockDriverState *bs)
++{
++    BDRVZeroinitState *s = bs->opaque;
++    return s->has_zero_init;
++}
++
++static int64_t coroutine_fn zeroinit_co_get_block_status(BlockDriverState *bs,
++                                                         int64_t sector_num,
++                                                         int nb_sectors, int *pnum,
++                                                         BlockDriverState **file)
++{
++    return bdrv_get_block_status(bs->file->bs, sector_num, nb_sectors, pnum, file);
++}
++
++static coroutine_fn BlockAIOCB *zeroinit_aio_pdiscard(BlockDriverState *bs,
++                                                     int64_t offset, int count,
++                                                     BlockCompletionFunc *cb, void *opaque)
++{
++    return bdrv_aio_pdiscard(bs->file->bs, offset, count, cb, opaque);
++}
++
++static int zeroinit_truncate(BlockDriverState *bs, int64_t offset)
++{
++    return bdrv_truncate(bs->file->bs, offset);
++}
++
++static int zeroinit_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
++{
++    return bdrv_get_info(bs->file->bs, bdi);
++}
++
++static BlockDriver bdrv_zeroinit = {
++    .format_name                      = "zeroinit",
++    .protocol_name                    = "zeroinit",
++    .instance_size                    = sizeof(BDRVZeroinitState),
++
++    .bdrv_parse_filename              = zeroinit_parse_filename,
++    .bdrv_file_open                   = zeroinit_open,
++    .bdrv_close                       = zeroinit_close,
++    .bdrv_getlength                   = zeroinit_getlength,
++    .bdrv_co_flush_to_disk            = zeroinit_co_flush,
++
++    .bdrv_co_pwrite_zeroes            = zeroinit_co_pwrite_zeroes,
++    .bdrv_aio_writev                  = zeroinit_aio_writev,
++    .bdrv_aio_readv                   = zeroinit_aio_readv,
++    .bdrv_aio_flush                   = zeroinit_aio_flush,
++
++    .is_filter                        = true,
++    .bdrv_recurse_is_first_non_filter = zeroinit_recurse_is_first_non_filter,
++
++    .bdrv_has_zero_init = zeroinit_has_zero_init,
++
++    .bdrv_co_get_block_status = zeroinit_co_get_block_status,
++
++    .bdrv_aio_pdiscard = zeroinit_aio_pdiscard,
++
++    .bdrv_truncate = zeroinit_truncate,
++    .bdrv_get_info = zeroinit_get_info,
++};
++
++static void bdrv_zeroinit_init(void)
++{
++    bdrv_register(&bdrv_zeroinit);
++}
++
++block_init(bdrv_zeroinit_init);
+-- 
+2.1.4
+
diff --git a/debian/patches/pve/0033-vma-bdrv_open-dropped-the-drv-parameter.patch b/debian/patches/pve/0033-vma-bdrv_open-dropped-the-drv-parameter.patch
deleted file mode 100644 (file)
index 98e6cb0..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-From c0ca2a0437b4d648df1b54513c9f22a7519a328a Mon Sep 17 00:00:00 2001
-From: Wolfgang Bumiller <w.bumiller@proxmox.com>
-Date: Thu, 10 Dec 2015 14:43:07 +0100
-Subject: [PATCH 33/55] vma: bdrv_open dropped the drv parameter
-
-we now pass the 'drive' option via a qdict.
-As per commit:
-6ebf9aa2ef: block: Drop drv parameter from bdrv_open()
-
-For-patch: introduce new vma archive format
----
- vma.c | 10 +++++-----
- 1 file changed, 5 insertions(+), 5 deletions(-)
-
-diff --git a/vma.c b/vma.c
-index 543e7d8..cc48013 100644
---- a/vma.c
-+++ b/vma.c
-@@ -25,6 +25,7 @@
- #include "qemu-common.h"
- #include "qemu/error-report.h"
- #include "qemu/main-loop.h"
-+#include "sysemu/char.h" /* qstring_from_str */
- static void help(void)
- {
-@@ -302,10 +303,10 @@ static int extract_content(int argc, char **argv)
-           const char *tmp = g_strrstr(devfn, ".");
-           const char *format = (tmp == NULL) ? "raw" : ++tmp;
-+          QDict *options = qdict_new();
-+          qdict_put(options, "driver", qstring_from_str(format));
--          BlockDriver *drv = bdrv_find_format(format);
--
--          if (errp || bdrv_open(&bs, devfn, NULL, NULL, flags, drv, &errp)) {
-+          if (errp || bdrv_open(&bs, devfn, NULL, options, flags, &errp)) {
-                 g_error("can't open file %s - %s", devfn,
-                         error_get_pretty(errp));
-             }
-@@ -534,11 +535,10 @@ static int create_archive(int argc, char **argv)
-         char *devname = NULL;
-         path = extract_devname(path, &devname, devcount++);
--        BlockDriver *drv = NULL;
-         Error *errp = NULL;
-         BlockDriverState *bs = bdrv_new();
--        res = bdrv_open(&bs, path, NULL, NULL, BDRV_O_CACHE_WB , drv, &errp);
-+        res = bdrv_open(&bs, path, NULL, NULL, BDRV_O_CACHE_WB, &errp);
-         if (res < 0) {
-             unlink(archivename);
-             g_error("bdrv_open '%s' failed - %s", path, error_get_pretty(errp));
--- 
-2.1.4
-
diff --git a/debian/patches/pve/0034-blockdev-bdrv_open-dropped-the-drv-parameter.patch b/debian/patches/pve/0034-blockdev-bdrv_open-dropped-the-drv-parameter.patch
deleted file mode 100644 (file)
index 30e6574..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-From 548b3b099d230b1221edf8062341900679d83f3e Mon Sep 17 00:00:00 2001
-From: Wolfgang Bumiller <w.bumiller@proxmox.com>
-Date: Thu, 10 Dec 2015 14:46:59 +0100
-Subject: [PATCH 34/55] blockdev: bdrv_open dropped the drv parameter
-
-As per commit:
-6ebf9aa2ef: block: Drop drv parameter from bdrv_open()
-
-For-patch: backup: vma: add dir format
----
- blockdev.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/blockdev.c b/blockdev.c
-index dd4e4bd..bf61a74 100644
---- a/blockdev.c
-+++ b/blockdev.c
-@@ -3374,7 +3374,7 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
-             }
-             di->target = bdrv_new();
--            if (bdrv_open(&di->target, di->targetfile, NULL, NULL, flags, NULL, &local_err) < 0) {
-+            if (bdrv_open(&di->target, di->targetfile, NULL, NULL, flags, &local_err) < 0) {
-                 bdrv_unref(di->target);
-                 error_propagate(errp, local_err);
-                 goto err;
--- 
-2.1.4
-
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
new file mode 100644 (file)
index 0000000..f48bb98
--- /dev/null
@@ -0,0 +1,108 @@
+From 20cd4944b9581a7197d5544077117e5d704d9f78 Mon Sep 17 00:00:00 2001
+From: Wolfgang Bumiller <w.bumiller@proxmox.com>
+Date: Tue, 12 Apr 2016 13:49:44 +0200
+Subject: [PATCH 34/41] 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 8a27704..c8ad6c0 100644
+--- a/vma.c
++++ b/vma.c
+@@ -130,6 +130,7 @@ static int list_content(int argc, char **argv)
+ typedef struct RestoreMap {
+     char *devname;
+     char *path;
++    char *format;
+     bool write_zero;
+ } RestoreMap;
+@@ -217,13 +218,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);
+@@ -239,6 +251,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);
+@@ -263,6 +276,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;
+@@ -273,6 +287,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",
+@@ -295,15 +310,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.1.4
+
diff --git a/debian/patches/pve/0035-blockdev-backup_start-now-takes-a-BlockJobTxn.patch b/debian/patches/pve/0035-blockdev-backup_start-now-takes-a-BlockJobTxn.patch
deleted file mode 100644 (file)
index 15e35d6..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-From eb1226235b886a2e472ed78d5df38608eb537618 Mon Sep 17 00:00:00 2001
-From: Wolfgang Bumiller <w.bumiller@proxmox.com>
-Date: Thu, 10 Dec 2015 14:50:05 +0100
-Subject: [PATCH 35/55] blockdev: backup_start now takes a BlockJobTxn
-
-As per commit 78f51fde88d1:
-block: Add BlockJobTxn support to backup_run
-
-For-patch: backup: add pve monitor commands
----
- blockdev.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/blockdev.c b/blockdev.c
-index bf61a74..96fc30b 100644
---- a/blockdev.c
-+++ b/blockdev.c
-@@ -3437,7 +3437,7 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
-         backup_start(di->bs, di->target, speed, MIRROR_SYNC_MODE_FULL, NULL,
-                      BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT,
-                      pvebackup_dump_cb, pvebackup_complete_cb, di,
--                     1, &local_err);
-+                     1, NULL, &local_err);
-         if (local_err != NULL) {
-             error_setg(&backup_state.error, "backup_job_create failed");
--- 
-2.1.4
-
diff --git a/debian/patches/pve/0035-fix-possible-unitialised-return-value.patch b/debian/patches/pve/0035-fix-possible-unitialised-return-value.patch
new file mode 100644 (file)
index 0000000..8c0a2aa
--- /dev/null
@@ -0,0 +1,25 @@
+From bac1501cc8927f21ba79f986cefe5d741825f33d Mon Sep 17 00:00:00 2001
+From: Thomas Lamprecht <t.lamprecht@proxmox.com>
+Date: Wed, 6 Apr 2016 16:45:15 +0200
+Subject: [PATCH 35/41] fix possible unitialised return value
+
+---
+ migration/savevm.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/migration/savevm.c b/migration/savevm.c
+index b1bdfb6..cebba77 100644
+--- a/migration/savevm.c
++++ b/migration/savevm.c
+@@ -1020,7 +1020,7 @@ int qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only)
+     QJSON *vmdesc;
+     int vmdesc_len;
+     SaveStateEntry *se;
+-    int ret;
++    int ret = -1;
+     bool in_postcopy = migration_in_postcopy(migrate_get_current());
+     trace_savevm_state_complete_precopy();
+-- 
+2.1.4
+
diff --git a/debian/patches/pve/0036-savevm-async-migration-and-bdrv_open-update.patch b/debian/patches/pve/0036-savevm-async-migration-and-bdrv_open-update.patch
deleted file mode 100644 (file)
index db2c4d8..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-From 6517453d33b72863940749b1b4ee1b36b7acf24c Mon Sep 17 00:00:00 2001
-From: Wolfgang Bumiller <w.bumiller@proxmox.com>
-Date: Thu, 10 Dec 2015 15:14:00 +0100
-Subject: [PATCH 36/55] 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 8117443..bb4372c 100644
---- a/savevm-async.c
-+++ b/savevm-async.c
-@@ -150,10 +150,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);
-@@ -197,12 +197,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;
-@@ -213,7 +214,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;
-@@ -246,7 +247,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_CACHE_WB | BDRV_O_RDWR;
-@@ -285,7 +285,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;
-@@ -450,8 +450,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);
-@@ -474,7 +474,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;
-@@ -482,7 +481,7 @@ int load_state_from_blockdev(const char *filename)
-     int ret;
-     bs = bdrv_new();
--    ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_CACHE_WB, drv, &local_err);
-+    ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_CACHE_WB, &local_err);
-     error_setg(&blocker, "block device is in use by load state");
-     bdrv_op_block_all(bs, blocker);
--- 
-2.1.4
-
diff --git a/debian/patches/pve/0036-vnc-refactor-to-QIOChannelSocket.patch b/debian/patches/pve/0036-vnc-refactor-to-QIOChannelSocket.patch
new file mode 100644 (file)
index 0000000..6c61b95
--- /dev/null
@@ -0,0 +1,87 @@
+From 2782de60b0da6b7c8a2961c366aec92164beaaaa Mon Sep 17 00:00:00 2001
+From: Thomas Lamprecht <t.lamprecht@proxmox.com>
+Date: Wed, 6 Apr 2016 16:47:54 +0200
+Subject: [PATCH 36/41] 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 d11f1df..a529520 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.1.4
+
diff --git a/debian/patches/pve/0037-qapi-qmp_marshal_-renames-for-pve-monitor-commands.patch b/debian/patches/pve/0037-qapi-qmp_marshal_-renames-for-pve-monitor-commands.patch
deleted file mode 100644 (file)
index d301246..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-From 48d52946667b9814ff390405e649d8a8705ee584 Mon Sep 17 00:00:00 2001
-From: Wolfgang Bumiller <w.bumiller@proxmox.com>
-Date: Thu, 10 Dec 2015 15:19:42 +0100
-Subject: [PATCH 37/55] qapi: qmp_marshal_* renames for pve monitor commands
-
-As per 7fad30f0:
-qapi: Rename qmp_marshal_input_FOO() to qmp_marshal_FOO()
-
-For-patch: backup: add pve monitor commands
----
- qmp-commands.hx | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
-
-diff --git a/qmp-commands.hx b/qmp-commands.hx
-index 964563e..0eebb75 100644
---- a/qmp-commands.hx
-+++ b/qmp-commands.hx
-@@ -1281,19 +1281,19 @@ EQMP
-     {
-         .name       = "backup",
-         .args_type  = "backup-file:s,format:s?,config-file:F?,firewall-file:F?,speed:o?,devlist:s?",
--        .mhandler.cmd_new = qmp_marshal_input_backup,
-+        .mhandler.cmd_new = qmp_marshal_backup,
-     },
-     {
-         .name       = "backup-cancel",
-         .args_type  = "",
--        .mhandler.cmd_new = qmp_marshal_input_backup_cancel,
-+        .mhandler.cmd_new = qmp_marshal_backup_cancel,
-     },
-     {
-         .name       = "query-backup",
-         .args_type  = "",
--        .mhandler.cmd_new = qmp_marshal_input_query_backup,
-+        .mhandler.cmd_new = qmp_marshal_query_backup,
-     },
-     {
--- 
-2.1.4
-
diff --git a/debian/patches/pve/0037-vma-use-BlockBackend-on-extract.patch b/debian/patches/pve/0037-vma-use-BlockBackend-on-extract.patch
new file mode 100644 (file)
index 0000000..f167bad
--- /dev/null
@@ -0,0 +1,75 @@
+From e743956b35723c39dba917ee92bb3cda7c634326 Mon Sep 17 00:00:00 2001
+From: Thomas Lamprecht <t.lamprecht@proxmox.com>
+Date: Fri, 1 Jul 2016 15:47:29 +0200
+Subject: [PATCH 37/41] 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 c8ad6c0..a2ddd32 100644
+--- a/vma.c
++++ b/vma.c
+@@ -19,6 +19,7 @@
+ #include "qemu/error-report.h"
+ #include "qemu/main-loop.h"
+ #include "sysemu/char.h" /* qstring_from_str */
++#include "sysemu/block-backend.h"
+ static void help(void)
+ {
+@@ -263,6 +264,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)) {
+@@ -307,8 +310,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) {
+@@ -326,10 +327,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));
+             }
+@@ -362,6 +367,8 @@ static int extract_content(int argc, char **argv)
+     vma_reader_destroy(vmar);
++    blk_unref(blk);
++
+     bdrv_close_all();
+     return ret;
+-- 
+2.1.4
+
diff --git a/debian/patches/pve/0038-qapi-qmp_mashal_-renames-for-async-snapshot.patch b/debian/patches/pve/0038-qapi-qmp_mashal_-renames-for-async-snapshot.patch
deleted file mode 100644 (file)
index c87aa75..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-From 6eeadc56b6dac81222e595fd4d95daac4cac3333 Mon Sep 17 00:00:00 2001
-From: Wolfgang Bumiller <w.bumiller@proxmox.com>
-Date: Thu, 10 Dec 2015 15:21:10 +0100
-Subject: [PATCH 38/55] qapi: qmp_mashal_* renames for async snapshot
-
-As per 7fad30f0:
-qapi: Rename qmp_marshal_input_FOO() to qmp_marshal_FOO()
-
-For-patch: internal snapshot async
----
- qmp-commands.hx | 10 +++++-----
- 1 file changed, 5 insertions(+), 5 deletions(-)
-
-diff --git a/qmp-commands.hx b/qmp-commands.hx
-index 0eebb75..6abe9df 100644
---- a/qmp-commands.hx
-+++ b/qmp-commands.hx
-@@ -4808,31 +4808,31 @@ EQMP
-     {
-         .name       = "savevm-start",
-         .args_type  = "statefile:s?",
--        .mhandler.cmd_new = qmp_marshal_input_savevm_start,
-+        .mhandler.cmd_new = qmp_marshal_savevm_start,
-     },
-     {
-         .name       = "snapshot-drive",
-         .args_type  = "device:s,name:s",
--        .mhandler.cmd_new = qmp_marshal_input_snapshot_drive,
-+        .mhandler.cmd_new = qmp_marshal_snapshot_drive,
-     },
-     {
-         .name       = "delete-drive-snapshot",
-         .args_type  = "device:s,name:s",
--        .mhandler.cmd_new = qmp_marshal_input_delete_drive_snapshot,
-+        .mhandler.cmd_new = qmp_marshal_delete_drive_snapshot,
-     },
-     {
-         .name       = "savevm-end",
-         .args_type  = "",
--        .mhandler.cmd_new = qmp_marshal_input_savevm_end,
-+        .mhandler.cmd_new = qmp_marshal_savevm_end,
-     },
-     {
-         .name       = "query-savevm",
-         .args_type  = "",
--        .mhandler.cmd_new = qmp_marshal_input_query_savevm,
-+        .mhandler.cmd_new = qmp_marshal_query_savevm,
-     },
-     {
--- 
-2.1.4
-
diff --git a/debian/patches/pve/0038-vma-byte-based-write-calls.patch b/debian/patches/pve/0038-vma-byte-based-write-calls.patch
new file mode 100644 (file)
index 0000000..7066b63
--- /dev/null
@@ -0,0 +1,237 @@
+From 80c3adfb9b7da34e8e63f4d3b404bfc93b35ab64 Mon Sep 17 00:00:00 2001
+From: Wolfgang Bumiller <w.bumiller@proxmox.com>
+Date: Fri, 9 Sep 2016 14:51:28 +0200
+Subject: [PATCH 38/41] 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 78f1de9..2000889 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 a2ddd32..ff974bd 100644
+--- a/vma.c
++++ b/vma.c
+@@ -333,9 +333,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));
+             }
+@@ -427,7 +425,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;
+@@ -456,7 +454,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,
+@@ -467,8 +465,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;
+@@ -563,14 +561,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);
+@@ -579,7 +577,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 365ceb2..fa6f4df 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.1.4
+
diff --git a/debian/patches/pve/0039-qapi-qmp_mashal_-renames-for-get_link_status.patch b/debian/patches/pve/0039-qapi-qmp_mashal_-renames-for-get_link_status.patch
deleted file mode 100644 (file)
index a59223c..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-From 0c87d830e293ad329e1ac175475cd149ce189177 Mon Sep 17 00:00:00 2001
-From: Wolfgang Bumiller <w.bumiller@proxmox.com>
-Date: Thu, 10 Dec 2015 15:21:59 +0100
-Subject: [PATCH 39/55] qapi: qmp_mashal_* renames for get_link_status
-
-As per 7fad30f0:
-qapi: Rename qmp_marshal_input_FOO() to qmp_marshal_FOO()
-
-For-patch: qmp: add get_link_status
----
- qmp-commands.hx | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/qmp-commands.hx b/qmp-commands.hx
-index 6abe9df..38ec312 100644
---- a/qmp-commands.hx
-+++ b/qmp-commands.hx
-@@ -1846,7 +1846,7 @@ EQMP
-     {
-         .name       = "get_link_status",
-         .args_type  = "name:s",
--        .mhandler.cmd_new = qmp_marshal_input_get_link_status,
-+        .mhandler.cmd_new = qmp_marshal_get_link_status,
-     },
- SQMP
--- 
-2.1.4
-
diff --git a/debian/patches/pve/0039-rbd-disable-rbd_cache_writethrough_until_flush-with-.patch b/debian/patches/pve/0039-rbd-disable-rbd_cache_writethrough_until_flush-with-.patch
new file mode 100644 (file)
index 0000000..ab05f0a
--- /dev/null
@@ -0,0 +1,29 @@
+From e588ad5b8eccaecfea37f4bdcedfd7cc11ba4276 Mon Sep 17 00:00:00 2001
+From: Alexandre Derumier <aderumier@odiso.com>
+Date: Tue, 26 Jul 2016 16:51:00 +0200
+Subject: [PATCH 39/41] rbd: disable rbd_cache_writethrough_until_flush with
+ cache=unsafe
+
+Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
+---
+ block/rbd.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/block/rbd.c b/block/rbd.c
+index 0106fea..66428af 100644
+--- a/block/rbd.c
++++ b/block/rbd.c
+@@ -552,6 +552,10 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
+         rados_conf_set(s->cluster, "rbd_cache", "true");
+     }
++    if (flags & BDRV_O_NO_FLUSH) {
++      rados_conf_set(s->cluster, "rbd_cache_writethrough_until_flush", "false");
++    }
++
+     r = rados_connect(s->cluster);
+     if (r < 0) {
+         error_setg_errno(errp, -r, "error connecting");
+-- 
+2.1.4
+
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
new file mode 100644 (file)
index 0000000..e51cb50
--- /dev/null
@@ -0,0 +1,43 @@
+From 65b2906879eed81749598de83ae8f4f362e9f992 Mon Sep 17 00:00:00 2001
+From: Wolfgang Bumiller <w.bumiller@proxmox.com>
+Date: Mon, 1 Aug 2016 10:52:46 +0200
+Subject: [PATCH 40/41] 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 <aderumier@odiso.com>
+---
+ 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 7979435..76cd8fa 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;
++    int bdrv_oflags = BDRV_O_RDWR | BDRV_O_NO_FLUSH;
+     int ret;
+     if (snap_state.state != SAVE_STATE_DONE) {
+diff --git a/vma.c b/vma.c
+index ff974bd..a8fa4ff 100644
+--- a/vma.c
++++ b/vma.c
+@@ -280,7 +280,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.1.4
+
diff --git a/debian/patches/pve/0040-vnc-make-x509-imply-tls-again.patch b/debian/patches/pve/0040-vnc-make-x509-imply-tls-again.patch
deleted file mode 100644 (file)
index e90ff5b..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-From 6a839e5bfcd7e41815b3ba407361c8effd36b5a8 Mon Sep 17 00:00:00 2001
-From: Wolfgang Bumiller <w.bumiller@proxmox.com>
-Date: Tue, 12 Jan 2016 09:09:49 +0100
-Subject: [PATCH 40/55] vnc: make x509 imply tls again
-
----
- ui/vnc.c | 5 ++---
- 1 file changed, 2 insertions(+), 3 deletions(-)
-
-diff --git a/ui/vnc.c b/ui/vnc.c
-index 88a5824..4610ce8 100644
---- a/ui/vnc.c
-+++ b/ui/vnc.c
-@@ -3671,9 +3671,8 @@ void vnc_display_open(const char *id, Error **errp)
-         const char *path;
-         bool tls = false, x509 = false, x509verify = false;
-         tls  = qemu_opt_get_bool(opts, "tls", false);
--        if (tls) {
--            path = qemu_opt_get(opts, "x509");
--
-+        path = qemu_opt_get(opts, "x509");
-+        if (tls || path) {
-             if (path) {
-                 x509 = true;
-             } else {
--- 
-2.1.4
-
diff --git a/debian/patches/pve/0041-PVE-VNC-authentication.patch b/debian/patches/pve/0041-PVE-VNC-authentication.patch
deleted file mode 100644 (file)
index 1de06a4..0000000
+++ /dev/null
@@ -1,683 +0,0 @@
-From 4f24f670a0bbbce29981d7ee54d31a960e00617c Mon Sep 17 00:00:00 2001
-From: Wolfgang Bumiller <w.bumiller@proxmox.com>
-Date: Mon, 11 Jan 2016 10:40:31 +0100
-Subject: [PATCH 41/55] PVE VNC authentication
-
----
- crypto/tlscreds.c         |  47 +++++++++++
- crypto/tlscredspriv.h     |   2 +
- crypto/tlscredsx509.c     |  13 ++--
- crypto/tlssession.c       |   1 +
- include/crypto/tlscreds.h |   1 +
- include/ui/console.h      |   1 +
- qemu-options.hx           |   3 +
- ui/vnc-auth-vencrypt.c    | 194 ++++++++++++++++++++++++++++++++++++++--------
- ui/vnc.c                  | 140 ++++++++++++++++++++++++++++++++-
- ui/vnc.h                  |   4 +
- vl.c                      |   9 +++
- 11 files changed, 375 insertions(+), 40 deletions(-)
-
-diff --git a/crypto/tlscreds.c b/crypto/tlscreds.c
-index 1620e12..affe020 100644
---- a/crypto/tlscreds.c
-+++ b/crypto/tlscreds.c
-@@ -158,6 +158,33 @@ qcrypto_tls_creds_prop_get_verify(Object *obj,
- static void
-+qcrypto_tls_creds_prop_set_pve(Object *obj,
-+                                 bool value,
-+                                 Error **errp G_GNUC_UNUSED)
-+{
-+    QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
-+
-+    creds->pve = value;
-+}
-+
-+
-+static bool
-+qcrypto_tls_creds_prop_get_pve(Object *obj,
-+                                  Error **errp G_GNUC_UNUSED)
-+{
-+    QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
-+
-+    return creds->pve;
-+}
-+
-+bool qcrypto_tls_creds_is_pve(QCryptoTLSCreds *creds)
-+{
-+    Error *errp = NULL;
-+    return qcrypto_tls_creds_prop_get_pve((Object*)creds, &errp);
-+}
-+
-+
-+static void
- qcrypto_tls_creds_prop_set_dir(Object *obj,
-                                const char *value,
-                                Error **errp G_GNUC_UNUSED)
-@@ -225,6 +252,26 @@ qcrypto_tls_creds_init(Object *obj)
-     QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
-     creds->verifyPeer = true;
-+    creds->pve = false;
-+
-+    object_property_add_bool(obj, "verify-peer",
-+                             qcrypto_tls_creds_prop_get_verify,
-+                             qcrypto_tls_creds_prop_set_verify,
-+                             NULL);
-+    object_property_add_bool(obj, "pve",
-+                             qcrypto_tls_creds_prop_get_pve,
-+                             qcrypto_tls_creds_prop_set_pve,
-+                             NULL);
-+    object_property_add_str(obj, "dir",
-+                            qcrypto_tls_creds_prop_get_dir,
-+                            qcrypto_tls_creds_prop_set_dir,
-+                            NULL);
-+    object_property_add_enum(obj, "endpoint",
-+                             "QCryptoTLSCredsEndpoint",
-+                             QCryptoTLSCredsEndpoint_lookup,
-+                             qcrypto_tls_creds_prop_get_endpoint,
-+                             qcrypto_tls_creds_prop_set_endpoint,
-+                             NULL);
- }
-diff --git a/crypto/tlscredspriv.h b/crypto/tlscredspriv.h
-index 9222be4..3a34279 100644
---- a/crypto/tlscredspriv.h
-+++ b/crypto/tlscredspriv.h
-@@ -36,6 +36,8 @@ int qcrypto_tls_creds_get_dh_params_file(QCryptoTLSCreds *creds,
-                                          gnutls_dh_params_t *dh_params,
-                                          Error **errp);
-+bool qcrypto_tls_creds_is_pve(QCryptoTLSCreds *creds);
-+
- #endif
- #endif /* QCRYPTO_TLSCRED_PRIV_H__ */
-diff --git a/crypto/tlscredsx509.c b/crypto/tlscredsx509.c
-index 6a0179c..d8f3bf1 100644
---- a/crypto/tlscredsx509.c
-+++ b/crypto/tlscredsx509.c
-@@ -550,22 +550,23 @@ qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds,
-         *key = NULL, *dhparams = NULL;
-     int ret;
-     int rv = -1;
-+    bool pve = qcrypto_tls_creds_is_pve(&creds->parent_obj);
-     trace_qcrypto_tls_creds_x509_load(creds,
-             creds->parent_obj.dir ? creds->parent_obj.dir : "<nodir>");
-     if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
-         if (qcrypto_tls_creds_get_path(&creds->parent_obj,
--                                       QCRYPTO_TLS_CREDS_X509_CA_CERT,
-+                                       pve ? "pve-root-ca.pem" : QCRYPTO_TLS_CREDS_X509_CA_CERT,
-                                        true, &cacert, errp) < 0 ||
-             qcrypto_tls_creds_get_path(&creds->parent_obj,
-                                        QCRYPTO_TLS_CREDS_X509_CA_CRL,
-                                        false, &cacrl, errp) < 0 ||
-             qcrypto_tls_creds_get_path(&creds->parent_obj,
--                                       QCRYPTO_TLS_CREDS_X509_SERVER_CERT,
-+                                       pve ? "local/pve-ssl.pem" : QCRYPTO_TLS_CREDS_X509_SERVER_CERT,
-                                        true, &cert, errp) < 0 ||
-             qcrypto_tls_creds_get_path(&creds->parent_obj,
--                                       QCRYPTO_TLS_CREDS_X509_SERVER_KEY,
-+                                       pve ? "local/pve-ssl.key" : QCRYPTO_TLS_CREDS_X509_SERVER_KEY,
-                                        true, &key, errp) < 0 ||
-             qcrypto_tls_creds_get_path(&creds->parent_obj,
-                                        QCRYPTO_TLS_CREDS_DH_PARAMS,
-@@ -574,13 +575,13 @@ qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds,
-         }
-     } else {
-         if (qcrypto_tls_creds_get_path(&creds->parent_obj,
--                                       QCRYPTO_TLS_CREDS_X509_CA_CERT,
-+                                       pve ? "pve-root-ca.pem" : QCRYPTO_TLS_CREDS_X509_CA_CERT,
-                                        true, &cacert, errp) < 0 ||
-             qcrypto_tls_creds_get_path(&creds->parent_obj,
--                                       QCRYPTO_TLS_CREDS_X509_CLIENT_CERT,
-+                                       pve ? "local/pve-ssl.pem" : QCRYPTO_TLS_CREDS_X509_CLIENT_CERT,
-                                        false, &cert, errp) < 0 ||
-             qcrypto_tls_creds_get_path(&creds->parent_obj,
--                                       QCRYPTO_TLS_CREDS_X509_CLIENT_KEY,
-+                                       pve ? "local/pve-ssl.key" : QCRYPTO_TLS_CREDS_X509_CLIENT_KEY,
-                                        false, &key, errp) < 0) {
-             goto cleanup;
-         }
-diff --git a/crypto/tlssession.c b/crypto/tlssession.c
-index a543e5a..564ad5d 100644
---- a/crypto/tlssession.c
-+++ b/crypto/tlssession.c
-@@ -23,6 +23,7 @@
- #include "crypto/tlscredsanon.h"
- #include "crypto/tlscredsx509.h"
- #include "qapi/error.h"
-+#include "crypto/tlscredspriv.h"
- #include "qemu/acl.h"
- #include "trace.h"
-diff --git a/include/crypto/tlscreds.h b/include/crypto/tlscreds.h
-index 8e2babd..8969e66 100644
---- a/include/crypto/tlscreds.h
-+++ b/include/crypto/tlscreds.h
-@@ -54,6 +54,7 @@ struct QCryptoTLSCreds {
-     gnutls_dh_params_t dh_params;
- #endif
-     bool verifyPeer;
-+    bool pve;
- };
-diff --git a/include/ui/console.h b/include/ui/console.h
-index d5a88d9..c17bee0 100644
---- a/include/ui/console.h
-+++ b/include/ui/console.h
-@@ -427,6 +427,7 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame);
- void cocoa_display_init(DisplayState *ds, int full_screen);
- /* vnc.c */
-+void pve_auth_setup(int vmid);
- void vnc_display_init(const char *id);
- void vnc_display_open(const char *id, Error **errp);
- void vnc_display_add_client(const char *id, int csock, bool skipauth);
-diff --git a/qemu-options.hx b/qemu-options.hx
-index 20ab9ac..30b90f5 100644
---- a/qemu-options.hx
-+++ b/qemu-options.hx
-@@ -476,6 +476,9 @@ STEXI
- @table @option
- ETEXI
-+DEF("id", HAS_ARG, QEMU_OPTION_id,
-+    "-id n         set the VMID\n", QEMU_ARCH_ALL)
-+
- DEF("fda", HAS_ARG, QEMU_OPTION_fda,
-     "-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 11c8c9a..d11f1df 100644
---- a/ui/vnc-auth-vencrypt.c
-+++ b/ui/vnc-auth-vencrypt.c
-@@ -28,6 +28,107 @@
- #include "vnc.h"
- #include "qapi/error.h"
- #include "qemu/main-loop.h"
-+#include "qemu/sockets.h"
-+
-+static int protocol_client_auth_plain(VncState *vs, uint8_t *data, size_t len)
-+{
-+      const char *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));
-+      }
-+
-+      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";
-+              goto err;
-+      }
-+
-+      strncpy(username, (char *)data, vs->username_len);
-+      username[vs->username_len] = 0;
-+      strncpy(passwd, (char *)data + vs->username_len, vs->password_len);
-+      passwd[vs->password_len] = 0;
-+
-+      VNC_DEBUG("AUTH PLAIN username: %s pw: %s\n", username, passwd);
-+
-+      if (pve_auth_verify(clientip, username, passwd) == 0) {
-+              vnc_write_u32(vs, 0); /* Accept auth completion */
-+              start_client_init(vs);
-+              return 0;
-+      }
-+
-+      err =  "Authentication failed";
-+err:
-+       if (err) {
-+             VNC_DEBUG("AUTH PLAIN ERROR: %s\n", err);
-+             vnc_write_u32(vs, 1); /* Reject auth */
-+             if (vs->minor >= 8) {
-+                     int elen = strlen(err);
-+                     vnc_write_u32(vs, elen);
-+                     vnc_write(vs, err, elen);
-+             }
-+       }
-+       vnc_flush(vs);
-+       vnc_client_error(vs);
-+
-+       return 0;
-+
-+}
-+
-+static int protocol_client_auth_plain_start(VncState *vs, uint8_t *data, size_t len)
-+{
-+      uint32_t ulen = read_u32(data, 0);
-+      uint32_t pwlen = read_u32(data, 4);
-+      const char *err = NULL;
-+
-+      VNC_DEBUG("AUTH PLAIN START %u %u\n", ulen, pwlen);
-+
-+       if (!ulen) {
-+             err = "No User name.";
-+             goto err;
-+       }
-+       if (ulen >= 255) {
-+             err = "User name too long.";
-+             goto err;
-+       }
-+       if (!pwlen) {
-+             err = "Password too short";
-+             goto err;
-+       }
-+       if (pwlen >= 511) {
-+             err = "Password too long.";
-+             goto err;
-+       }
-+
-+       vs->username_len = ulen;
-+       vs->password_len = pwlen;
-+
-+       vnc_read_when(vs, protocol_client_auth_plain, ulen + pwlen);
-+
-+       return 0;
-+err:
-+       if (err) {
-+             VNC_DEBUG("AUTH PLAIN ERROR: %s\n", err);
-+             vnc_write_u32(vs, 1); /* Reject auth */
-+             if (vs->minor >= 8) {
-+                     int elen = strlen(err);
-+                     vnc_write_u32(vs, elen);
-+                     vnc_write(vs, err, elen);
-+             }
-+       }
-+       vnc_flush(vs);
-+       vnc_client_error(vs);
-+
-+       return 0;
-+}
- static void start_auth_vencrypt_subauth(VncState *vs)
- {
-@@ -39,6 +140,17 @@ static void start_auth_vencrypt_subauth(VncState *vs)
-        start_client_init(vs);
-        break;
-+    case VNC_AUTH_VENCRYPT_TLSPLAIN:
-+    case VNC_AUTH_VENCRYPT_X509PLAIN:
-+       VNC_DEBUG("Start TLS auth PLAIN\n");
-+       vnc_read_when(vs, protocol_client_auth_plain_start, 8);
-+       break;
-+
-+    case VNC_AUTH_VENCRYPT_PLAIN:
-+       VNC_DEBUG("Start auth PLAIN\n");
-+       vnc_read_when(vs, protocol_client_auth_plain_start, 8);
-+       break;
-+
-     case VNC_AUTH_VENCRYPT_TLSVNC:
-     case VNC_AUTH_VENCRYPT_X509VNC:
-        VNC_DEBUG("Start TLS auth VNC\n");
-@@ -87,44 +199,63 @@ static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len
- {
-     int auth = read_u32(data, 0);
--    if (auth != vs->subauth) {
-+    if (auth != vs->subauth && auth != VNC_AUTH_VENCRYPT_PLAIN) {
-         VNC_DEBUG("Rejecting auth %d\n", auth);
-         vnc_write_u8(vs, 0); /* Reject auth */
-         vnc_flush(vs);
-         vnc_client_error(vs);
-     } else {
--        Error *err = NULL;
--        QIOChannelTLS *tls;
--        VNC_DEBUG("Accepting auth %d, setting up TLS for handshake\n", auth);
--        vnc_write_u8(vs, 1); /* Accept auth */
--        vnc_flush(vs);
--
--        if (vs->ioc_tag) {
--            g_source_remove(vs->ioc_tag);
--            vs->ioc_tag = 0;
-+        if (auth == VNC_AUTH_VENCRYPT_PLAIN) {
-+            vs->subauth = auth;
-+            start_auth_vencrypt_subauth(vs);
-         }
-+        else
-+        {
-+            Error *err = NULL;
-+            QIOChannelTLS *tls;
-+            VNC_DEBUG("Accepting auth %d, setting up TLS for handshake\n", auth);
-+            vnc_write_u8(vs, 1); /* Accept auth */
-+            vnc_flush(vs);
--        tls = qio_channel_tls_new_server(
--            vs->ioc,
--            vs->vd->tlscreds,
--            vs->vd->tlsaclname,
--            &err);
--        if (!tls) {
--            VNC_DEBUG("Failed to setup TLS %s\n", error_get_pretty(err));
--            error_free(err);
--            vnc_client_error(vs);
--            return 0;
--        }
-+            if (vs->ioc_tag) {
-+                g_source_remove(vs->ioc_tag);
-+                vs->ioc_tag = 0;
-+            }
--        VNC_DEBUG("Start TLS VeNCrypt handshake process\n");
--        object_unref(OBJECT(vs->ioc));
--        vs->ioc = QIO_CHANNEL(tls);
--        vs->tls = qio_channel_tls_get_session(tls);
-+            tls = qio_channel_tls_new_server(
-+                vs->ioc,
-+                vs->vd->tlscreds,
-+                vs->vd->tlsaclname,
-+                &err);
-+            if (!tls) {
-+                VNC_DEBUG("Failed to setup TLS %s\n", error_get_pretty(err));
-+                error_free(err);
-+                vnc_client_error(vs);
-+                return 0;
-+                vs->tls = qcrypto_tls_session_new(vs->vd->tlscreds,
-+                                                  NULL,
-+                                                  vs->vd->tlsaclname,
-+                                                  QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
-+                                                  &err);
-+                if (!vs->tls) {
-+                    VNC_DEBUG("Failed to setup TLS %s\n",
-+                              error_get_pretty(err));
-+                    error_free(err);
-+                    vnc_client_error(vs);
-+                    return 0;
-+                }
-+            }
--        qio_channel_tls_handshake(tls,
--                                  vnc_tls_handshake_done,
--                                  vs,
--                                  NULL);
-+            VNC_DEBUG("Start TLS VeNCrypt handshake process\n");
-+            object_unref(OBJECT(vs->ioc));
-+            vs->ioc = QIO_CHANNEL(tls);
-+            vs->tls = qio_channel_tls_get_session(tls);
-+
-+            qio_channel_tls_handshake(tls,
-+                                      vnc_tls_handshake_done,
-+                                      vs,
-+                                      NULL);
-+        }
-     }
-     return 0;
- }
-@@ -138,10 +269,11 @@ static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len
-         vnc_flush(vs);
-         vnc_client_error(vs);
-     } else {
--        VNC_DEBUG("Sending allowed auth %d\n", vs->subauth);
-+        VNC_DEBUG("Sending allowed auths %d %d\n", vs->subauth, VNC_AUTH_VENCRYPT_PLAIN);
-         vnc_write_u8(vs, 0); /* Accept version */
--        vnc_write_u8(vs, 1); /* Number of sub-auths */
-+        vnc_write_u8(vs, 2); /* Number of sub-auths */
-         vnc_write_u32(vs, vs->subauth); /* The supported auth */
-+        vnc_write_u32(vs, VNC_AUTH_VENCRYPT_PLAIN); /* Alternative supported auth */
-         vnc_flush(vs);
-         vnc_read_when(vs, protocol_client_vencrypt_auth, 4);
-     }
-diff --git a/ui/vnc.c b/ui/vnc.c
-index 4610ce8..66e2163 100644
---- a/ui/vnc.c
-+++ b/ui/vnc.c
-@@ -55,6 +55,125 @@ static const struct timeval VNC_REFRESH_LOSSY = { 2, 0 };
- #include "vnc_keysym.h"
- #include "crypto/cipher.h"
-+static int pve_vmid = 0;
-+
-+void pve_auth_setup(int vmid) {
-+      pve_vmid = vmid;
-+}
-+
-+static char *
-+urlencode(char *buf, const char *value)
-+{
-+      static const char *hexchar = "0123456789abcdef";
-+      char *p = buf;
-+      int i;
-+      int l = strlen(value);
-+      for (i = 0; i < l; i++) {
-+              char c = value[i];
-+              if (('a' <= c && c <= 'z') ||
-+                  ('A' <= c && c <= 'Z') ||
-+                  ('0' <= c && c <= '9')) {
-+                      *p++ = c;
-+              } else if (c == 32) {
-+                      *p++ = '+';
-+              } else {
-+                      *p++ = '%';
-+                      *p++ = hexchar[c >> 4];
-+                      *p++ = hexchar[c & 15];
-+              }
-+      }
-+      *p = 0;
-+
-+      return p;
-+}
-+
-+int
-+pve_auth_verify(const char *clientip, const char *username, const char *passwd)
-+{
-+      struct sockaddr_in server;
-+
-+      int sfd = socket(AF_INET, SOCK_STREAM, 0);
-+      if (sfd == -1) {
-+              perror("pve_auth_verify: socket failed");
-+              return -1;
-+      }
-+
-+      struct hostent *he;
-+      if ((he = gethostbyname("localhost")) == NULL) {
-+              fprintf(stderr, "pve_auth_verify: error resolving hostname\n");
-+              goto err;
-+      }
-+
-+      memcpy(&server.sin_addr, he->h_addr_list[0], he->h_length);
-+      server.sin_family = AF_INET;
-+      server.sin_port = htons(85);
-+
-+      if (connect(sfd, (struct sockaddr *)&server, sizeof(server))) {
-+              perror("pve_auth_verify: error connecting to server");
-+              goto err;
-+      }
-+
-+      char buf[8192];
-+      char form[8192];
-+
-+      char *p = form;
-+      p = urlencode(p, "username");
-+      *p++ = '=';
-+      p = urlencode(p, username);
-+
-+      *p++ = '&';
-+      p = urlencode(p, "password");
-+      *p++ = '=';
-+      p = urlencode(p, passwd);
-+
-+      *p++ = '&';
-+      p = urlencode(p, "path");
-+      *p++ = '=';
-+      char authpath[256];
-+      sprintf(authpath, "/vms/%d", pve_vmid);
-+      p = urlencode(p, authpath);
-+
-+      *p++ = '&';
-+      p = urlencode(p, "privs");
-+      *p++ = '=';
-+      p = urlencode(p, "VM.Console");
-+
-+      sprintf(buf, "POST /api2/json/access/ticket HTTP/1.1\n"
-+              "Host: localhost:85\n"
-+              "Connection: close\n"
-+              "PVEClientIP: %s\n"
-+              "Content-Type: application/x-www-form-urlencoded\n"
-+              "Content-Length: %zd\n\n%s\n", clientip, strlen(form), form);
-+      ssize_t len = strlen(buf);
-+      ssize_t sb = send(sfd, buf, len, 0);
-+      if (sb < 0) {
-+              perror("pve_auth_verify: send failed");
-+              goto err;
-+      }
-+      if (sb != len) {
-+              fprintf(stderr, "pve_auth_verify: partial send error\n");
-+              goto err;
-+      }
-+
-+      len = recv(sfd, buf, sizeof(buf) - 1, 0);
-+      if (len < 0) {
-+              perror("pve_auth_verify: recv failed");
-+              goto err;
-+      }
-+
-+      buf[len] = 0;
-+
-+      //printf("DATA:%s\n", buf);
-+
-+      shutdown(sfd, SHUT_RDWR);
-+
-+      return strncmp(buf, "HTTP/1.1 200 OK", 15);
-+
-+err:
-+      shutdown(sfd, SHUT_RDWR);
-+      return -1;
-+}
-+
- static QTAILQ_HEAD(, VncDisplay) vnc_displays =
-     QTAILQ_HEAD_INITIALIZER(vnc_displays);
-@@ -3359,11 +3478,17 @@ vnc_display_setup_auth(VncDisplay *vs,
-             if (object_dynamic_cast(OBJECT(vs->tlscreds),
-                                     TYPE_QCRYPTO_TLS_CREDS_X509)) {
-                 VNC_DEBUG("Initializing VNC server with x509 password auth\n");
--                vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
-+                if (vs->tlscreds->pve)
-+                    vs->subauth = VNC_AUTH_VENCRYPT_X509PLAIN;
-+                else
-+                    vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
-             } else if (object_dynamic_cast(OBJECT(vs->tlscreds),
-                                            TYPE_QCRYPTO_TLS_CREDS_ANON)) {
-                 VNC_DEBUG("Initializing VNC server with TLS password auth\n");
--                vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
-+                if (vs->tlscreds->pve)
-+                    vs->subauth = VNC_AUTH_VENCRYPT_TLSPLAIN;
-+                else
-+                    vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
-             } else {
-                 error_setg(errp,
-                            "Unsupported TLS cred type %s",
-@@ -3454,6 +3579,7 @@ vnc_display_create_creds(bool x509,
-                          bool x509verify,
-                          const char *dir,
-                          const char *id,
-+                         bool pve,
-                          Error **errp)
- {
-     gchar *credsid = g_strdup_printf("tlsvnc%s", id);
-@@ -3469,6 +3595,7 @@ vnc_display_create_creds(bool x509,
-                                       "endpoint", "server",
-                                       "dir", dir,
-                                       "verify-peer", x509verify ? "yes" : "no",
-+                                      "pve", pve ? "yes" : "no",
-                                       NULL);
-     } else {
-         creds = object_new_with_props(TYPE_QCRYPTO_TLS_CREDS_ANON,
-@@ -3476,6 +3603,7 @@ vnc_display_create_creds(bool x509,
-                                       credsid,
-                                       &err,
-                                       "endpoint", "server",
-+                                      "pve", pve ? "yes" : "no",
-                                       NULL);
-     }
-@@ -3669,12 +3797,17 @@ void vnc_display_open(const char *id, Error **errp)
-         }
-     } else {
-         const char *path;
--        bool tls = false, x509 = false, x509verify = false;
-+        bool tls = false, x509 = false, x509verify = false, pve = false;
-         tls  = qemu_opt_get_bool(opts, "tls", false);
-         path = qemu_opt_get(opts, "x509");
-         if (tls || path) {
-             if (path) {
-                 x509 = true;
-+                if (!strcmp(path, "on")) {
-+                    /* magic to default to /etc/pve */
-+                    path = "/etc/pve";
-+                    pve = true;
-+                }
-             } else {
-                 path = qemu_opt_get(opts, "x509verify");
-                 if (path) {
-@@ -3686,6 +3819,7 @@ void vnc_display_open(const char *id, Error **errp)
-                                                     x509verify,
-                                                     path,
-                                                     vs->id,
-+                                                    pve,
-                                                     errp);
-             if (!vs->tlscreds) {
-                 goto fail;
-diff --git a/ui/vnc.h b/ui/vnc.h
-index 81a3261..40e2780 100644
---- a/ui/vnc.h
-+++ b/ui/vnc.h
-@@ -281,6 +281,8 @@ struct VncState
-     int auth;
-     int subauth; /* Used by VeNCrypt */
-     char challenge[VNC_AUTH_CHALLENGE_SIZE];
-+    int username_len;
-+    int password_len;
-     QCryptoTLSSession *tls; /* Borrowed pointer from channel, don't free */
- #ifdef CONFIG_VNC_SASL
-     VncStateSASL sasl;
-@@ -576,4 +578,6 @@ int vnc_zrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
- int vnc_zywrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
- void vnc_zrle_clear(VncState *vs);
-+int pve_auth_verify(const char *clientip, const char *username, const char *passwd);
-+
- #endif /* __QEMU_VNC_H */
-diff --git a/vl.c b/vl.c
-index f393767..f5fc86f 100644
---- a/vl.c
-+++ b/vl.c
-@@ -2967,6 +2967,7 @@ static void set_memory_options(uint64_t *ram_slots, ram_addr_t *maxram_size,
- int main(int argc, char **argv, char **envp)
- {
-     int i;
-+    long int vm_id_long = 0;
-     int snapshot, linux_boot;
-     const char *initrd_filename;
-     const char *kernel_filename, *kernel_cmdline;
-@@ -3737,6 +3738,14 @@ int main(int argc, char **argv, char **envp)
-                     exit(1);
-                 }
-                 break;
-+            case QEMU_OPTION_id:
-+                vm_id_long = strtol(optarg, (char **) &optarg, 10);
-+                if (*optarg != 0 || vm_id_long < 100 || vm_id_long > INT_MAX) {
-+                    fprintf(stderr, "Invalid ID\n");
-+                    exit(1);
-+                }
-+                pve_auth_setup(vm_id_long);
-+                break;
-             case QEMU_OPTION_vnc:
-             {
- #ifdef CONFIG_VNC
--- 
-2.1.4
-
diff --git a/debian/patches/pve/0041-savevm-async-updates.patch b/debian/patches/pve/0041-savevm-async-updates.patch
new file mode 100644 (file)
index 0000000..942073c
--- /dev/null
@@ -0,0 +1,236 @@
+From 8ba1bc13200b72a287554224b5aeb8cbf1bba156 Mon Sep 17 00:00:00 2001
+From: Wolfgang Bumiller <w.bumiller@proxmox.com>
+Date: Fri, 9 Sep 2016 15:21:19 +0200
+Subject: [PATCH 41/41] savevm-async updates
+
+---
+ savevm-async.c | 99 +++++++++++++++++++++++++++++++++++++---------------------
+ 1 file changed, 63 insertions(+), 36 deletions(-)
+
+diff --git a/savevm-async.c b/savevm-async.c
+index 76cd8fa..fddb18c 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,49 @@ 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)
++typedef struct BlkRwCo {
++    int64_t offset;
++    QEMUIOVector *qiov;
++    int ret;
++} BlkRwCo;
++
++static void block_state_write_entry(void *opaque) {
++    BlkRwCo *rwco = opaque;
++    rwco->ret = blk_co_pwritev(snap_state.target, rwco->offset, rwco->qiov->size,
++                               rwco->qiov, 0);
++}
++
++static ssize_t block_state_writev_buffer(void *opaque, struct iovec *iov,
++                                         int iovcnt, int64_t pos)
+ {
+-    ssize_t ret;
++    AioContext *aio_context;
++    QEMUIOVector qiov;
++    Coroutine *co;
++    BlkRwCo rwco;
++
++    qemu_iovec_init_external(&qiov, iov, iovcnt);
++
++    rwco = (BlkRwCo) {
++        .offset = pos,
++        .qiov   = &qiov,
++        .ret    = NOT_DONE,
++    };
+-    assert(pos == snap_state.bs_pos);
++    co = qemu_coroutine_create(&block_state_write_entry, &rwco);
++    qemu_coroutine_enter(co);
+-    if ((ret = bdrv_pwrite(snap_state.bs, snap_state.bs_pos, buf, size)) > 0) {
+-        snap_state.bs_pos += ret;
++    aio_context = blk_get_aio_context(snap_state.target);
++    while (rwco.ret == NOT_DONE) {
++        aio_poll(aio_context, true);
+     }
+-    return ret;
++    if (rwco.ret < 0) {
++        return rwco.ret;
++    }
++    return qiov.size;
+ }
+ static int store_and_stop(void) {
+@@ -227,7 +257,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 +274,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 +284,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_NO_FLUSH;
+-    int ret;
+     if (snap_state.state != SAVE_STATE_DONE) {
+         error_set(errp, ERROR_CLASS_GENERIC_ERROR,
+@@ -284,13 +313,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 +331,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 +484,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 +495,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,25 +504,25 @@ 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;
+-    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;
+@@ -516,10 +543,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.1.4
+
diff --git a/debian/patches/pve/0042-qmp_snapshot_drive-add-aiocontext.patch b/debian/patches/pve/0042-qmp_snapshot_drive-add-aiocontext.patch
new file mode 100644 (file)
index 0000000..2d84418
--- /dev/null
@@ -0,0 +1,65 @@
+From fa4f5325137a86bbbdc3f477a2a171a43ea80a7a Mon Sep 17 00:00:00 2001
+From: Alexandre Derumier <aderumier@odiso.com>
+Date: Tue, 13 Sep 2016 01:57:56 +0200
+Subject: [PATCH 42/42] qmp_snapshot_drive: add aiocontext
+
+Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
+---
+ savevm-async.c | 15 +++++++++++----
+ 1 file changed, 11 insertions(+), 4 deletions(-)
+
+diff --git a/savevm-async.c b/savevm-async.c
+index fddb18c..a158249 100644
+--- a/savevm-async.c
++++ b/savevm-async.c
+@@ -372,6 +372,7 @@ void qmp_snapshot_drive(const char *device, const char *name, Error **errp)
+     BlockBackend *blk;
+     BlockDriverState *bs;
+     QEMUSnapshotInfo sn1, *sn = &sn1;
++    AioContext *aio_context;
+     int ret;
+ #ifdef _WIN32
+     struct _timeb tb;
+@@ -398,20 +399,23 @@ void qmp_snapshot_drive(const char *device, const char *name, Error **errp)
+         return;
+     }
++    aio_context = bdrv_get_aio_context(bs);
++    aio_context_acquire(aio_context);
++
+     if (bdrv_is_read_only(bs)) {
+         error_setg(errp, "Node '%s' is read only", device);
+-        return;
++        goto out;
+     }
+     if (!bdrv_can_snapshot(bs)) {
+         error_setg(errp, QERR_UNSUPPORTED);
+-        return;
++        goto out;
+     }
+     if (bdrv_snapshot_find(bs, sn, name) >= 0) {
+         error_set(errp, ERROR_CLASS_GENERIC_ERROR,
+                   "snapshot '%s' already exists", name);
+-        return;
++        goto out;
+     }
+     sn = &sn1;
+@@ -436,8 +440,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);
+-        return;
++        goto out;
+     }
++
++out:
++    aio_context_release(aio_context);
+ }
+ void qmp_delete_drive_snapshot(const char *device, const char *name,
+-- 
+2.1.4
+
diff --git a/debian/patches/pve/0042-vma-writer-don-t-bail-out-on-zero-length-files.patch b/debian/patches/pve/0042-vma-writer-don-t-bail-out-on-zero-length-files.patch
deleted file mode 100644 (file)
index 954d5b8..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-From f8d5f70f8dbe379e442b182c89df168e38ba999d Mon Sep 17 00:00:00 2001
-From: Wolfgang Bumiller <w.bumiller@proxmox.com>
-Date: Mon, 8 Feb 2016 08:23:34 +0100
-Subject: [PATCH 42/55] 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 f5a7abd..3cde204 100644
---- a/vma-writer.c
-+++ b/vma-writer.c
-@@ -136,7 +136,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.1.4
-
diff --git a/debian/patches/pve/0043-vma-better-driver-guessing-for-bdrv_open.patch b/debian/patches/pve/0043-vma-better-driver-guessing-for-bdrv_open.patch
deleted file mode 100644 (file)
index bdf4a28..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-From d0cbfa6899c33f2a93696666b03d9a343eb81d15 Mon Sep 17 00:00:00 2001
-From: Wolfgang Bumiller <w.bumiller@proxmox.com>
-Date: Tue, 23 Feb 2016 15:48:41 +0100
-Subject: [PATCH 43/55] 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, 11 insertions(+), 4 deletions(-)
-
-diff --git a/vma.c b/vma.c
-index cc48013..1c4103f 100644
---- a/vma.c
-+++ b/vma.c
-@@ -301,10 +301,17 @@ static int extract_content(int argc, char **argv)
-             BlockDriverState *bs = bdrv_new();
--          const char *tmp = g_strrstr(devfn, ".");
--          const char *format = (tmp == NULL) ? "raw" : ++tmp;
--          QDict *options = qdict_new();
--          qdict_put(options, "driver", qstring_from_str(format));
-+          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,
--- 
-2.1.4
-
diff --git a/debian/patches/pve/0044-block-add-the-zeroinit-block-driver-filter.patch b/debian/patches/pve/0044-block-add-the-zeroinit-block-driver-filter.patch
deleted file mode 100644 (file)
index ca588f7..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-From b3bf300710e38fd4692f0d761c75f4ba3a7edd7e Mon Sep 17 00:00:00 2001
-From: Wolfgang Bumiller <w.bumiller@proxmox.com>
-Date: Thu, 17 Mar 2016 11:33:37 +0100
-Subject: [PATCH 44/55] block: add the zeroinit block driver filter
-
----
- block/Makefile.objs |   1 +
- block/zeroinit.c    | 216 ++++++++++++++++++++++++++++++++++++++++++++++++++++
- 2 files changed, 217 insertions(+)
- create mode 100644 block/zeroinit.c
-
-diff --git a/block/Makefile.objs b/block/Makefile.objs
-index 44a5416..9e2cdbc 100644
---- a/block/Makefile.objs
-+++ b/block/Makefile.objs
-@@ -4,6 +4,7 @@ block-obj-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
- block-obj-y += qed-check.o
- block-obj-$(CONFIG_VHDX) += vhdx.o vhdx-endian.o vhdx-log.o
- block-obj-y += quorum.o
-+block-obj-y += zeroinit.o
- block-obj-y += parallels.o blkdebug.o blkverify.o blkreplay.o
- block-obj-y += block-backend.o snapshot.o qapi.o
- block-obj-$(CONFIG_WIN32) += raw-win32.o win32-aio.o
-diff --git a/block/zeroinit.c b/block/zeroinit.c
-new file mode 100644
-index 0000000..04a9bd0
---- /dev/null
-+++ b/block/zeroinit.c
-@@ -0,0 +1,216 @@
-+/*
-+ * Filter to fake a zero-initialized block device.
-+ *
-+ * Copyright (c) 2016 Wolfgang Bumiller <w.bumiller@proxmox.com>
-+ * Copyright (c) 2016 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 "block/block_int.h"
-+#include "qapi/qmp/qdict.h"
-+#include "qapi/qmp/qstring.h"
-+
-+typedef struct {
-+    bool has_zero_init;
-+    int64_t extents;
-+} BDRVZeroinitState;
-+
-+/* Valid blkverify filenames look like blkverify:path/to/raw_image:path/to/image */
-+static void zeroinit_parse_filename(const char *filename, QDict *options,
-+                                     Error **errp)
-+{
-+    QString *raw_path;
-+
-+    /* Parse the blkverify: prefix */
-+    if (!strstart(filename, "zeroinit:", &filename)) {
-+        /* There was no prefix; therefore, all options have to be already
-+           present in the QDict (except for the filename) */
-+        return;
-+    }
-+
-+    raw_path = qstring_from_str(filename);
-+    qdict_put(options, "x-next", raw_path);
-+}
-+
-+static QemuOptsList runtime_opts = {
-+    .name = "zeroinit",
-+    .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
-+    .desc = {
-+        {
-+            .name = "x-next",
-+            .type = QEMU_OPT_STRING,
-+            .help = "[internal use only, will be removed]",
-+        },
-+        {
-+            .name = "x-zeroinit",
-+            .type = QEMU_OPT_BOOL,
-+            .help = "set has_initialized_zero flag",
-+        },
-+        { /* end of list */ }
-+    },
-+};
-+
-+static int zeroinit_open(BlockDriverState *bs, QDict *options, int flags,
-+                          Error **errp)
-+{
-+    BDRVZeroinitState *s = bs->opaque;
-+    QemuOpts *opts;
-+    Error *local_err = NULL;
-+    int ret;
-+
-+    s->extents = 0;
-+
-+    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 fail;
-+    }
-+
-+    /* Open the raw file */
-+    bs->file = bdrv_open_child(qemu_opt_get(opts, "x-next"), options, "next",
-+                               bs, &child_file, false, &local_err);
-+    if (local_err) {
-+        ret = -EINVAL;
-+        error_propagate(errp, local_err);
-+        goto fail;
-+    }
-+
-+    /* set the options */
-+    s->has_zero_init = qemu_opt_get_bool(opts, "x-zeroinit", true);
-+
-+    ret = 0;
-+fail:
-+    if (ret < 0) {
-+        bdrv_unref_child(bs, bs->file);
-+    }
-+    qemu_opts_del(opts);
-+    return ret;
-+}
-+
-+static void zeroinit_close(BlockDriverState *bs)
-+{
-+    BDRVZeroinitState *s = bs->opaque;
-+    (void)s;
-+}
-+
-+static int64_t zeroinit_getlength(BlockDriverState *bs)
-+{
-+    return bdrv_getlength(bs->file->bs);
-+}
-+
-+static BlockAIOCB *zeroinit_aio_readv(BlockDriverState *bs,
-+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
-+        BlockCompletionFunc *cb, void *opaque)
-+{
-+    return bdrv_aio_readv(bs->file->bs, sector_num, qiov, nb_sectors,
-+                          cb, opaque);
-+}
-+
-+static int coroutine_fn zeroinit_co_write_zeroes(BlockDriverState *bs, int64_t sector_num,
-+                                                 int nb_sectors, BdrvRequestFlags flags)
-+{
-+    BDRVZeroinitState *s = bs->opaque;
-+    if (sector_num >= s->extents)
-+        return 0;
-+    return bdrv_write_zeroes(bs->file->bs, sector_num, nb_sectors, flags);
-+}
-+
-+static BlockAIOCB *zeroinit_aio_writev(BlockDriverState *bs,
-+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
-+        BlockCompletionFunc *cb, void *opaque)
-+{
-+    BDRVZeroinitState *s = bs->opaque;
-+    int64_t extents = sector_num + nb_sectors + 1;
-+    if (extents > s->extents)
-+        s->extents = extents;
-+    return bdrv_aio_writev(bs->file->bs, sector_num, qiov, nb_sectors,
-+                           cb, opaque);
-+}
-+
-+static BlockAIOCB *zeroinit_aio_flush(BlockDriverState *bs,
-+                                       BlockCompletionFunc *cb,
-+                                       void *opaque)
-+{
-+    return bdrv_aio_flush(bs->file->bs, cb, opaque);
-+}
-+
-+static bool zeroinit_recurse_is_first_non_filter(BlockDriverState *bs,
-+                                                  BlockDriverState *candidate)
-+{
-+    return bdrv_recurse_is_first_non_filter(bs->file->bs, candidate);
-+}
-+
-+static coroutine_fn int zeroinit_co_flush(BlockDriverState *bs)
-+{
-+    return bdrv_co_flush(bs->file->bs);
-+}
-+
-+static int zeroinit_has_zero_init(BlockDriverState *bs)
-+{
-+    BDRVZeroinitState *s = bs->opaque;
-+    return s->has_zero_init;
-+}
-+
-+static int64_t coroutine_fn zeroinit_co_get_block_status(BlockDriverState *bs,
-+                                                         int64_t sector_num,
-+                                                         int nb_sectors, int *pnum)
-+{
-+    return bdrv_get_block_status(bs->file->bs, sector_num, nb_sectors, pnum);
-+}
-+
-+static coroutine_fn BlockAIOCB *zeroinit_aio_discard(BlockDriverState *bs,
-+                                                     int64_t sector_num, int nb_sectors,
-+                                                     BlockCompletionFunc *cb, void *opaque)
-+{
-+    return bdrv_aio_discard(bs->file->bs, sector_num, nb_sectors, cb, opaque);
-+}
-+
-+static int zeroinit_truncate(BlockDriverState *bs, int64_t offset)
-+{
-+    return bdrv_truncate(bs->file->bs, offset);
-+}
-+
-+static int zeroinit_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
-+{
-+    return bdrv_get_info(bs->file->bs, bdi);
-+}
-+
-+static BlockDriver bdrv_zeroinit = {
-+    .format_name                      = "zeroinit",
-+    .protocol_name                    = "zeroinit",
-+    .instance_size                    = sizeof(BDRVZeroinitState),
-+
-+    .bdrv_parse_filename              = zeroinit_parse_filename,
-+    .bdrv_file_open                   = zeroinit_open,
-+    .bdrv_close                       = zeroinit_close,
-+    .bdrv_getlength                   = zeroinit_getlength,
-+    .bdrv_co_flush_to_disk            = zeroinit_co_flush,
-+
-+    .bdrv_co_write_zeroes             = zeroinit_co_write_zeroes,
-+    .bdrv_aio_writev                  = zeroinit_aio_writev,
-+    .bdrv_aio_readv                   = zeroinit_aio_readv,
-+    .bdrv_aio_flush                   = zeroinit_aio_flush,
-+
-+    .is_filter                        = true,
-+    .bdrv_recurse_is_first_non_filter = zeroinit_recurse_is_first_non_filter,
-+
-+    .bdrv_has_zero_init = zeroinit_has_zero_init,
-+
-+    .bdrv_co_get_block_status = zeroinit_co_get_block_status,
-+
-+    .bdrv_aio_discard = zeroinit_aio_discard,
-+
-+    .bdrv_truncate = zeroinit_truncate,
-+    .bdrv_get_info = zeroinit_get_info,
-+};
-+
-+static void bdrv_zeroinit_init(void)
-+{
-+    bdrv_register(&bdrv_zeroinit);
-+}
-+
-+block_init(bdrv_zeroinit_init);
--- 
-2.1.4
-
diff --git a/debian/patches/pve/0045-vma-add-format-option-to-device-mapping.patch b/debian/patches/pve/0045-vma-add-format-option-to-device-mapping.patch
deleted file mode 100644 (file)
index a87569d..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-From 52002e4bb7572662d937de2c20b2110309095f29 Mon Sep 17 00:00:00 2001
-From: Wolfgang Bumiller <w.bumiller@proxmox.com>
-Date: Tue, 12 Apr 2016 13:49:44 +0200
-Subject: [PATCH 45/55] 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 1c4103f..46ae14b 100644
---- a/vma.c
-+++ b/vma.c
-@@ -137,6 +137,7 @@ static int list_content(int argc, char **argv)
- typedef struct RestoreMap {
-     char *devname;
-     char *path;
-+    char *format;
-     bool write_zero;
- } RestoreMap;
-@@ -224,13 +225,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);
-@@ -246,6 +258,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);
-@@ -270,6 +283,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|BDRV_O_CACHE_WB;
-             bool write_zero = true;
-@@ -280,6 +294,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",
-@@ -302,15 +317,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.1.4
-
diff --git a/debian/patches/pve/0046-pve-cleanup-includes-all-over-the-place.patch b/debian/patches/pve/0046-pve-cleanup-includes-all-over-the-place.patch
deleted file mode 100644 (file)
index b209b2b..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-From 17751f15c2d15782ee24ddcfe991de940dbdc3b0 Mon Sep 17 00:00:00 2001
-From: Thomas Lamprecht <t.lamprecht@proxmox.com>
-Date: Wed, 6 Apr 2016 13:28:16 +0200
-Subject: [PATCH 46/55] pve: cleanup includes all over the place
-
-QEMU wants to get a cleaner include system, adapt to it.
----
- block/zeroinit.c |  3 +++
- savevm-async.c   |  4 ++++
- vma-reader.c     | 11 +----------
- vma-writer.c     | 12 +++---------
- vma.c            |  9 +--------
- 5 files changed, 12 insertions(+), 27 deletions(-)
-
-diff --git a/block/zeroinit.c b/block/zeroinit.c
-index 04a9bd0..eb77657 100644
---- a/block/zeroinit.c
-+++ b/block/zeroinit.c
-@@ -8,9 +8,12 @@
-  * See the COPYING file in the top-level directory.
-  */
-+#include "qemu/osdep.h"
-+#include "qapi/error.h"
- #include "block/block_int.h"
- #include "qapi/qmp/qdict.h"
- #include "qapi/qmp/qstring.h"
-+#include "qemu/cutils.h"
- typedef struct {
-     bool has_zero_init;
-diff --git a/savevm-async.c b/savevm-async.c
-index bb4372c..4d73e66 100644
---- a/savevm-async.c
-+++ b/savevm-async.c
-@@ -1,3 +1,4 @@
-+#include "qemu/osdep.h"
- #include "qemu-common.h"
- #include "qapi/qmp/qerror.h"
- #include "qemu/error-report.h"
-@@ -13,6 +14,9 @@
- #include "qemu/timer.h"
- #include "sysemu/block-backend.h"
- #include "qapi/qmp/qstring.h"
-+#include "qemu/rcu.h"
-+#include "qemu/thread.h"
-+#include "qemu/cutils.h"
- /* #define DEBUG_SAVEVM_STATE */
-diff --git a/vma-reader.c b/vma-reader.c
-index 5d0d3ea..cb58360 100644
---- a/vma-reader.c
-+++ b/vma-reader.c
-@@ -11,14 +11,7 @@
-  *
-  */
--#include <stdio.h>
--#include <errno.h>
--#include <unistd.h>
--#include <stdio.h>
--#include <string.h>
--#include <sys/types.h>
--#include <sys/stat.h>
--#include <fcntl.h>
-+#include "qemu/osdep.h"
- #include <glib.h>
- #include <uuid/uuid.h>
-@@ -28,8 +21,6 @@
- #include "vma.h"
- #include "block/block.h"
--#define BITS_PER_LONG  (sizeof(unsigned long) * CHAR_BIT)
--
- static unsigned char zero_vma_block[VMA_BLOCK_SIZE];
- typedef struct VmaRestoreState {
-diff --git a/vma-writer.c b/vma-writer.c
-index 3cde204..e96fb55 100644
---- a/vma-writer.c
-+++ b/vma-writer.c
-@@ -11,22 +11,16 @@
-  *
-  */
--#include <stdio.h>
--#include <errno.h>
--#include <unistd.h>
--#include <stdio.h>
--#include <string.h>
--#include <sys/types.h>
--#include <sys/stat.h>
--#include <fcntl.h>
-+#include "qemu/osdep.h"
- #include <glib.h>
- #include <uuid/uuid.h>
--#include "qemu-common.h"
- #include "vma.h"
- #include "block/block.h"
- #include "monitor/monitor.h"
- #include "qemu/main-loop.h"
-+#include "qemu/coroutine.h"
-+#include "qemu/cutils.h"
- #define DEBUG_VMA 0
-diff --git a/vma.c b/vma.c
-index 46ae14b..c3db633 100644
---- a/vma.c
-+++ b/vma.c
-@@ -11,14 +11,7 @@
-  *
-  */
--#include <stdio.h>
--#include <errno.h>
--#include <unistd.h>
--#include <stdio.h>
--#include <string.h>
--#include <sys/types.h>
--#include <sys/stat.h>
--#include <fcntl.h>
-+#include "qemu/osdep.h"
- #include <glib.h>
- #include "vma.h"
--- 
-2.1.4
-
diff --git a/debian/patches/pve/0047-zeroinit-bdrv_get_block_status-got-a-new-param.patch b/debian/patches/pve/0047-zeroinit-bdrv_get_block_status-got-a-new-param.patch
deleted file mode 100644 (file)
index bf0ba7a..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-From e698a23ad095fcaf0d72734a480d5bc0202a6f75 Mon Sep 17 00:00:00 2001
-From: Thomas Lamprecht <t.lamprecht@proxmox.com>
-Date: Wed, 6 Apr 2016 14:15:58 +0200
-Subject: [PATCH 47/55] zeroinit: bdrv_get_block_status got a new param
-
-see: 67a0fd2a9bca204d2b39f910a97c7137636a0715
----
- block/zeroinit.c | 5 +++--
- 1 file changed, 3 insertions(+), 2 deletions(-)
-
-diff --git a/block/zeroinit.c b/block/zeroinit.c
-index eb77657..ad52847 100644
---- a/block/zeroinit.c
-+++ b/block/zeroinit.c
-@@ -160,9 +160,10 @@ static int zeroinit_has_zero_init(BlockDriverState *bs)
- static int64_t coroutine_fn zeroinit_co_get_block_status(BlockDriverState *bs,
-                                                          int64_t sector_num,
--                                                         int nb_sectors, int *pnum)
-+                                                         int nb_sectors, int *pnum,
-+                                                         BlockDriverState **file)
- {
--    return bdrv_get_block_status(bs->file->bs, sector_num, nb_sectors, pnum);
-+    return bdrv_get_block_status(bs->file->bs, sector_num, nb_sectors, pnum, file);
- }
- static coroutine_fn BlockAIOCB *zeroinit_aio_discard(BlockDriverState *bs,
--- 
-2.1.4
-
diff --git a/debian/patches/pve/0048-BDRV_O_CACHE_WB-was-removed.patch b/debian/patches/pve/0048-BDRV_O_CACHE_WB-was-removed.patch
deleted file mode 100644 (file)
index ca9d4e8..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-From 9d30e60ad2a6a450c282c6f2df4432d8b9d84b05 Mon Sep 17 00:00:00 2001
-From: Thomas Lamprecht <t.lamprecht@proxmox.com>
-Date: Wed, 6 Apr 2016 14:24:28 +0200
-Subject: [PATCH 48/55] BDRV_O_CACHE_WB was removed
-
-see: 61de4c680846167e01d7ba42bf787f8d1d80bf5e
----
- blockdev.c     | 2 +-
- savevm-async.c | 4 ++--
- vma.c          | 4 ++--
- 3 files changed, 5 insertions(+), 5 deletions(-)
-
-diff --git a/blockdev.c b/blockdev.c
-index 96fc30b..9330836 100644
---- a/blockdev.c
-+++ b/blockdev.c
-@@ -3365,7 +3365,7 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
-             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_O_CACHE_WB;
-+            int flags = BDRV_O_RDWR;
-             bdrv_img_create(di->targetfile, "raw", NULL, NULL, NULL,
-                             di->size, flags, &local_err, false);
-             if (local_err) {
-diff --git a/savevm-async.c b/savevm-async.c
-index 4d73e66..2c41b17 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_CACHE_WB | BDRV_O_RDWR;
-+    int bdrv_oflags = BDRV_O_RDWR;
-     int ret;
-     if (snap_state.state != SAVE_STATE_DONE) {
-@@ -485,7 +485,7 @@ int load_state_from_blockdev(const char *filename)
-     int ret;
-     bs = bdrv_new();
--    ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_CACHE_WB, &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);
-diff --git a/vma.c b/vma.c
-index c3db633..c1407d3 100644
---- a/vma.c
-+++ b/vma.c
-@@ -277,7 +277,7 @@ static int extract_content(int argc, char **argv)
-         } else if (di) {
-             char *devfn = NULL;
-             const char *format = NULL;
--            int flags = BDRV_O_RDWR|BDRV_O_CACHE_WB;
-+            int flags = BDRV_O_RDWR;
-             bool write_zero = true;
-             if (readmap) {
-@@ -558,7 +558,7 @@ static int create_archive(int argc, char **argv)
-         Error *errp = NULL;
-         BlockDriverState *bs = bdrv_new();
--        res = bdrv_open(&bs, path, NULL, NULL, BDRV_O_CACHE_WB, &errp);
-+        res = bdrv_open(&bs, path, NULL, NULL, 0, &errp);
-         if (res < 0) {
-             unlink(archivename);
-             g_error("bdrv_open '%s' failed - %s", path, error_get_pretty(errp));
--- 
-2.1.4
-
diff --git a/debian/patches/pve/0049-backup-bdrv_set_enable_write_cache-is-no-more.patch b/debian/patches/pve/0049-backup-bdrv_set_enable_write_cache-is-no-more.patch
deleted file mode 100644 (file)
index 74771aa..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-From b194d9117c084d148a3e4fee5c2b113faf799968 Mon Sep 17 00:00:00 2001
-From: Thomas Lamprecht <t.lamprecht@proxmox.com>
-Date: Wed, 6 Apr 2016 16:43:38 +0200
-Subject: [PATCH 49/55] backup: bdrv_set_enable_write_cache is no more
-
-see: 09cf9db1bcd60d9889b774925ba7058286d35412
-
-this reverts a hunk of our commit: backup: modify job api
----
- block/backup.c | 9 +++------
- 1 file changed, 3 insertions(+), 6 deletions(-)
-
-diff --git a/block/backup.c b/block/backup.c
-index c38b520..f0e647d 100644
---- a/block/backup.c
-+++ b/block/backup.c
-@@ -414,12 +414,9 @@ static void coroutine_fn backup_run(void *opaque)
-     job->done_bitmap = bitmap_new(end);
--    if (target) {
--        bdrv_set_enable_write_cache(target, true);
--        if (target->blk) {
--            blk_set_on_error(target->blk, on_target_error, on_target_error);
--            blk_iostatus_enable(target->blk);
--        }
-+    if (target && target->blk) {
-+        blk_set_on_error(target->blk, on_target_error, on_target_error);
-+        blk_iostatus_enable(target->blk);
-     }
-     bdrv_add_before_write_notifier(bs, &before_write);
--- 
-2.1.4
-
diff --git a/debian/patches/pve/0050-fix-possible-unitialised-return-value.patch b/debian/patches/pve/0050-fix-possible-unitialised-return-value.patch
deleted file mode 100644 (file)
index 353b739..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-From 9be0512acac31822307c8ff8bc336fee659eeeb0 Mon Sep 17 00:00:00 2001
-From: Thomas Lamprecht <t.lamprecht@proxmox.com>
-Date: Wed, 6 Apr 2016 16:45:15 +0200
-Subject: [PATCH 50/55] fix possible unitialised return value
-
----
- migration/savevm.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/migration/savevm.c b/migration/savevm.c
-index d6560f5..7b2d654 100644
---- a/migration/savevm.c
-+++ b/migration/savevm.c
-@@ -1037,7 +1037,7 @@ int qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only)
-     QJSON *vmdesc;
-     int vmdesc_len;
-     SaveStateEntry *se;
--    int ret;
-+    int ret = -1;
-     bool in_postcopy = migration_in_postcopy(migrate_get_current());
-     trace_savevm_state_complete_precopy();
--- 
-2.1.4
-
diff --git a/debian/patches/pve/0051-net-NET_CLIENT_OPTIONS_KIND_MAX-changed.patch b/debian/patches/pve/0051-net-NET_CLIENT_OPTIONS_KIND_MAX-changed.patch
deleted file mode 100644 (file)
index 2553ee9..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-From 23a15e3819093d32fbf15709bbe1fe9e3869b171 Mon Sep 17 00:00:00 2001
-From: Thomas Lamprecht <t.lamprecht@proxmox.com>
-Date: Wed, 6 Apr 2016 16:46:11 +0200
-Subject: [PATCH 51/55] net: NET_CLIENT_OPTIONS_KIND_MAX changed
-
-s/NET_CLIENT_OPTIONS_KIND_MAX/NET_CLIENT_OPTIONS_KIND__MAX/
----
- net/net.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/net/net.c b/net/net.c
-index 0e3f231..2b9de86 100644
---- a/net/net.c
-+++ b/net/net.c
-@@ -1333,7 +1333,7 @@ int64_t qmp_get_link_status(const char *name, Error **errp)
-     bool ret;
-     queues = qemu_find_net_clients_except(name, ncs,
--                                          NET_CLIENT_OPTIONS_KIND_MAX,
-+                                          NET_CLIENT_OPTIONS_KIND__MAX,
-                                           MAX_QUEUE_NUM);
-     if (queues == 0) {
--- 
-2.1.4
-
diff --git a/debian/patches/pve/0052-vnc-refactor-to-QIOChannelSocket.patch b/debian/patches/pve/0052-vnc-refactor-to-QIOChannelSocket.patch
deleted file mode 100644 (file)
index f3f01d0..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-From 24023a5773869ccac7c4f6d5065c7937396e2df9 Mon Sep 17 00:00:00 2001
-From: Thomas Lamprecht <t.lamprecht@proxmox.com>
-Date: Wed, 6 Apr 2016 16:47:54 +0200
-Subject: [PATCH 52/55] 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 d11f1df..a529520 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.1.4
-
diff --git a/debian/patches/pve/0053-vma-use-BlockBackend-on-extract.patch b/debian/patches/pve/0053-vma-use-BlockBackend-on-extract.patch
deleted file mode 100644 (file)
index b0e0ff9..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-From 817ed44ab0ada0b1fcfcc27763b6e2db546687d6 Mon Sep 17 00:00:00 2001
-From: Thomas Lamprecht <t.lamprecht@proxmox.com>
-Date: Fri, 1 Jul 2016 15:47:29 +0200
-Subject: [PATCH 53/55] 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 c1407d3..0716a45 100644
---- a/vma.c
-+++ b/vma.c
-@@ -19,6 +19,7 @@
- #include "qemu/error-report.h"
- #include "qemu/main-loop.h"
- #include "sysemu/char.h" /* qstring_from_str */
-+#include "sysemu/block-backend.h"
- static void help(void)
- {
-@@ -263,6 +264,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)) {
-@@ -307,8 +310,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) {
-@@ -326,10 +327,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));
-             }
-@@ -362,6 +367,8 @@ static int extract_content(int argc, char **argv)
-     vma_reader_destroy(vmar);
-+    blk_unref(blk);
-+
-     bdrv_close_all();
-     return ret;
--- 
-2.1.4
-
diff --git a/debian/patches/pve/0054-rbd-disable-rbd_cache_writethrough_until_flush-with-.patch b/debian/patches/pve/0054-rbd-disable-rbd_cache_writethrough_until_flush-with-.patch
deleted file mode 100644 (file)
index 0122420..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-From 75eead3024d641e0ff2fa7a901a41781101cf87c Mon Sep 17 00:00:00 2001
-From: Alexandre Derumier <aderumier@odiso.com>
-Date: Tue, 26 Jul 2016 16:51:00 +0200
-Subject: [PATCH 54/55] rbd: disable rbd_cache_writethrough_until_flush with
- cache=unsafe
-
-Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
----
- block/rbd.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
-diff --git a/block/rbd.c b/block/rbd.c
-index 5bc5b32..5656028 100644
---- a/block/rbd.c
-+++ b/block/rbd.c
-@@ -544,6 +544,10 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
-         rados_conf_set(s->cluster, "rbd_cache", "true");
-     }
-+    if (flags & BDRV_O_NO_FLUSH) {
-+      rados_conf_set(s->cluster, "rbd_cache_writethrough_until_flush", "false");
-+    }
-+
-     r = rados_connect(s->cluster);
-     if (r < 0) {
-         error_setg(errp, "error connecting");
--- 
-2.1.4
-
diff --git a/debian/patches/pve/0055-enable-cache-unsafe-for-vma-extract_content-and-qmp_.patch b/debian/patches/pve/0055-enable-cache-unsafe-for-vma-extract_content-and-qmp_.patch
deleted file mode 100644 (file)
index 64da954..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-From 6775cc94517696abe12bbae601395b7a16e06ba0 Mon Sep 17 00:00:00 2001
-From: Wolfgang Bumiller <w.bumiller@proxmox.com>
-Date: Mon, 1 Aug 2016 10:52:46 +0200
-Subject: [PATCH 55/55] 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 <aderumier@odiso.com>
-For-patch: BDRV_O_CACHE_WB was removed
----
- 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 2c41b17..6a2266c 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;
-+    int bdrv_oflags = BDRV_O_RDWR | BDRV_O_NO_FLUSH;
-     int ret;
-     if (snap_state.state != SAVE_STATE_DONE) {
-diff --git a/vma.c b/vma.c
-index 0716a45..4d2d5ad 100644
---- a/vma.c
-+++ b/vma.c
-@@ -280,7 +280,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.1.4
-
diff --git a/debian/patches/pve/0056-qmp_snapshot_drive-add-aiocontext.patch b/debian/patches/pve/0056-qmp_snapshot_drive-add-aiocontext.patch
deleted file mode 100644 (file)
index 8c2d9c9..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-From 61164c3693415d6dce39a7b0cbde43b184081243 Mon Sep 17 00:00:00 2001
-From: Alexandre Derumier <aderumier@odiso.com>
-Date: Tue, 13 Sep 2016 01:57:56 +0200
-Subject: [PATCH] qmp_snapshot_drive:  add aiocontext
-
-Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
----
- savevm-async.c | 15 +++++++++++----
- 1 file changed, 11 insertions(+), 4 deletions(-)
-
-diff --git a/savevm-async.c b/savevm-async.c
-index 6a2266c..308ac61 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)
-     BlockBackend *blk;
-     BlockDriverState *bs;
-     QEMUSnapshotInfo sn1, *sn = &sn1;
-+    AioContext *aio_context;
-     int ret;
- #ifdef _WIN32
-     struct _timeb tb;
-@@ -371,20 +372,23 @@ void qmp_snapshot_drive(const char *device, const char *name, Error **errp)
-         return;
-     }
-+    aio_context = bdrv_get_aio_context(bs);
-+    aio_context_acquire(aio_context);
-+
-     if (bdrv_is_read_only(bs)) {
-         error_setg(errp, "Node '%s' is read only", device);
--        return;
-+        goto out;
-     }
-     if (!bdrv_can_snapshot(bs)) {
-         error_setg(errp, QERR_UNSUPPORTED);
--        return;
-+        goto out;
-     }
-     if (bdrv_snapshot_find(bs, sn, name) >= 0) {
-         error_set(errp, ERROR_CLASS_GENERIC_ERROR,
-                   "snapshot '%s' already exists", name);
--        return;
-+        goto out;
-     }
-     sn = &sn1;
-@@ -409,8 +413,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);
--        return;
-+        goto out;
-     }
-+
-+out:
-+    aio_context_release(aio_context);
- }
- void qmp_delete_drive_snapshot(const char *device, const char *name,
--- 
-2.1.4
-
index 7f414efbe2d9c126211f06acfe81eac775ae3f36..0283083f22f5df8af6e5ccac30fd7661e4343734 100644 (file)
@@ -11,62 +11,50 @@ 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-vma-restore-tolerate-a-size-difference-up-to-4M.patch
-pve/0015-backup-modify-job-api.patch
-pve/0016-backup-add-pve-monitor-commands.patch
-pve/0017-backup-vma-add-dir-format.patch
-pve/0018-backup-do-not-return-errors-in-dump-callback.patch
-pve/0019-backup-vma-correctly-propagate-error.patch
-pve/0020-backup-vma-remove-async-queue.patch
-pve/0021-backup-vma-run-flush-inside-coroutine.patch
-pve/0022-backup-do-not-use-bdrv_drain_all.patch
-pve/0023-internal-snapshot-async.patch
-pve/0024-backup-vma-allow-empty-backups.patch
-pve/0025-backup-vma-add-BlockDriver-to-bdrv_open-in-extract_c.patch
-pve/0026-glusterfs-daemonize.patch
-pve/0027-gluster-possiblity-to-specify-a-secondary-server.patch
-pve/0028-qmp-add-get_link_status.patch
-pve/0029-smm_available-false.patch
-pve/0030-use-whitespace-between-VERSION-and-PKGVERSION.patch
-pve/0031-vma-add-firewall.patch
-pve/0032-vma-writer-aio_set_fd_handler-update.patch
-pve/0033-vma-bdrv_open-dropped-the-drv-parameter.patch
-pve/0034-blockdev-bdrv_open-dropped-the-drv-parameter.patch
-pve/0035-blockdev-backup_start-now-takes-a-BlockJobTxn.patch
-pve/0036-savevm-async-migration-and-bdrv_open-update.patch
-pve/0037-qapi-qmp_marshal_-renames-for-pve-monitor-commands.patch
-pve/0038-qapi-qmp_mashal_-renames-for-async-snapshot.patch
-pve/0039-qapi-qmp_mashal_-renames-for-get_link_status.patch
-pve/0040-vnc-make-x509-imply-tls-again.patch
-pve/0041-PVE-VNC-authentication.patch
-pve/0042-vma-writer-don-t-bail-out-on-zero-length-files.patch
-pve/0043-vma-better-driver-guessing-for-bdrv_open.patch
-pve/0044-block-add-the-zeroinit-block-driver-filter.patch
-pve/0045-vma-add-format-option-to-device-mapping.patch
-pve/0046-pve-cleanup-includes-all-over-the-place.patch
-pve/0047-zeroinit-bdrv_get_block_status-got-a-new-param.patch
-pve/0048-BDRV_O_CACHE_WB-was-removed.patch
-pve/0049-backup-bdrv_set_enable_write_cache-is-no-more.patch
-pve/0050-fix-possible-unitialised-return-value.patch
-pve/0051-net-NET_CLIENT_OPTIONS_KIND_MAX-changed.patch
-pve/0052-vnc-refactor-to-QIOChannelSocket.patch
-pve/0053-vma-use-BlockBackend-on-extract.patch
-pve/0054-rbd-disable-rbd_cache_writethrough_until_flush-with-.patch
-pve/0055-enable-cache-unsafe-for-vma-extract_content-and-qmp_.patch
-pve/0056-qmp_snapshot_drive-add-aiocontext.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
 #see https://bugs.launchpad.net/qemu/+bug/1488363?comments=all
+extra/x86-lapic-Load-LAPIC-state-at-post_load.patch
 extra/0001-Revert-target-i386-disable-LINT0-after-reset.patch
-extra/0002-scsi-esp-fix-migration.patch
-extra/CVE-2016-6490-virtio-check-vring-descriptor-buffer-length.patch
-extra/0002-net-vmxnet3-check-for-device_active-before-write.patch
-extra/0005-net-vmxnet-initialise-local-tx-descriptor.patch
-extra/0009-net-limit-allocation-in-nc_sendv_compat.patch
+extra/0002-net-vmxnet-initialise-local-tx-descriptor.patch
+extra/0003-net-limit-allocation-in-nc_sendv_compat.patch
+extra/CVE-2016-7155-scsi-check-page-count-while-initialising-descriptor-.patch
 extra/CVE-2016-7156-scsi-pvscsi-avoid-infinite-loop-while-building-SG-li.patch
+extra/CVE-2016-7157-scsi-mptconfig-fix-an-assert-expression.patch
 extra/CVE-2016-7170-vmsvga-correct-bitmap-and-pixmap-size-checks.patch
-extra/x86-lapic-Load-LAPIC-state-at-post_load.patch
-extra/CVE-2016-7161-hw-net-Fix-a-heap-overflow-in-xlnx.xps-ethernetlite.patch
+extra/CVE-2016-7421-scsi-pvscsi-limit-process-IO-loop-to-ring-size.patch
 extra/CVE-2016-7422-virtio-add-check-for-descriptor-s-mapped-address.patch
+extra/CVE-2016-7423-scsi-mptsas-use-g_new0-to-allocate-MPTSASRequest-obj.patch
+extra/CVE-2016-7466-usb-xhci-fix-memory-leak-in-usb_xhci_exit.patch
 extra/CVE-2016-7907-net-imx-limit-buffer-descriptor-count.patch
 extra/CVE-2016-7908-net-mcf-limit-buffer-descriptor-count.patch
 extra/CVE-2016-7909-net-pcnet-check-rx-tx-descriptor-ring-length.patch
-extra/CVE-2016-7466-usb-xhci-fix-memory-leak-in-usb_xhci_exit.patch
+extra/CVE-2016-7994-virtio-gpu-fix-memory-leak-in-virtio_gpu_resource_cr.patch
+extra/CVE-2016-7995-usb-ehci-fix-memory-leak-in-ehci_process_itd.patch
index bc0fba07a09942c2789bfe83132912fb869a6908..26a06a7e3723723fe7a01fb42a5431a2e9b87aa4 100755 (executable)
@@ -77,7 +77,6 @@ install: build
        mv $(destdir)/usr/share/man/man1/qemu.1 $(destdir)/usr/share/man/man1/kvm.1
 
        # Install the userspace utilities
-       install -m 0755 scripts/kvm/kvm_stat $(destdir)/usr/bin/
        install -s -m 0755 vma $(destdir)/usr/bin/
 
        install -D -m 0755 $(CURDIR)/debian/kvm-ifup $(destdir)/etc/kvm/kvm-ifup
index 43ca5e55ed58ce23498f6254d4adb9fd147edf7c..21700f5292c63b71395a9af65085e83114e68734 100644 (file)
Binary files a/qemu-kvm-src.tar.gz and b/qemu-kvm-src.tar.gz differ