├── debian ├── docs ├── source │ ├── format │ ├── include-binaries │ └── lintian-overrides ├── kvm-ifdown ├── Logo.bmp ├── OVMF_CODE-pure-efi.fd ├── OVMF_VARS-pure-efi.fd ├── kvm-ifup ├── pve-qemu-kvm.install ├── OVMF_README.txt ├── parse-cpu-flags.pl ├── pve-qemu-kvm.lintian-overrides ├── parse-machines.pl ├── pve-qemu-kvm.links ├── patches │ ├── pve │ │ ├── 0037-PVE-block-stream-increase-chunk-size.patch │ │ ├── 0008-PVE-Up-qemu-img-return-success-on-info-without-snaps.patch │ │ ├── 0003-PVE-Config-set-the-CPU-model-to-kvm64-32-instead-of-.patch │ │ ├── 0002-PVE-Config-Adjust-network-script-path-to-etc-kvm.patch │ │ ├── 0021-PVE-Config-Revert-target-i386-disable-LINT0-after-re.patch │ │ ├── 0006-PVE-Config-rbd-block-rbd-disable-rbd_cache_writethro.patch │ │ ├── 0023-PVE-monitor-disable-oob-capability.patch │ │ ├── 0001-PVE-Config-block-file-change-locking-default-to-off.patch │ │ ├── 0035-migration-block-dirty-bitmap-migrate-other-bitmaps-e.patch │ │ ├── 0015-PVE-qapi-modify-spice-query.patch │ │ ├── 0005-PVE-Config-glusterfs-no-default-logfile-if-daemonize.patch │ │ ├── 0024-PVE-Compat-4.0-used-balloon-qemu-4-0-config-size-fal.patch │ │ ├── 0041-PVE-backup-factor-out-helper-to-clear-backup-state-s.patch │ │ ├── 0033-PVE-redirect-stderr-to-journal-when-daemonized.patch │ │ ├── 0014-PVE-qapi-modify-query-machines.patch │ │ ├── 0004-PVE-Config-ui-spice-default-to-pve-certificates.patch │ │ ├── 0020-PVE-Add-dummy-id-command-line-parameter.patch │ │ ├── 0043-PVE-backup-add-target-ID-in-backup-state.patch │ │ ├── 0036-PVE-fall-back-to-open-iscsi-initiatorname.patch │ │ ├── 0044-PVE-backup-get-device-info-allow-caller-to-specify-f.patch │ │ ├── 0026-block-backup-move-bcs-bitmap-initialization-to-job-c.patch │ │ ├── 0007-PVE-Up-glusterfs-allow-partial-reads.patch │ │ ├── 0029-PVE-Add-sequential-job-transaction-support.patch │ │ ├── 0042-PVE-backup-factor-out-helper-to-initialize-backup-st.patch │ │ ├── 0010-PVE-Up-qemu-img-dd-add-isize-parameter.patch │ │ ├── 0046-PVE-backup-prepare-for-the-switch-to-using-blockdev-.patch │ │ ├── 0011-PVE-Up-qemu-img-dd-add-n-skip_create.patch │ │ ├── 0025-PVE-Allow-version-code-in-machine-type.patch │ │ ├── 0012-qemu-img-dd-add-l-option-for-loading-a-snapshot.patch │ │ ├── 0022-PVE-Up-Config-file-posix-make-locking-optiono-on-cre.patch │ │ ├── 0013-PVE-virtio-balloon-improve-query-balloon.patch │ │ ├── 0047-savevm-async-reuse-migration-blocker-check-for-snaps.patch │ │ ├── 0034-PVE-Migrate-dirty-bitmap-state-via-savevm.patch │ │ ├── 0018-PVE-add-optional-buffer-size-to-QEMUFile.patch │ │ ├── 0040-adapt-machine-version-deprecation-for-Proxmox-VE.patch │ │ ├── 0031-PVE-Backup-pbs-restore-new-command-to-restore-from-p.patch │ │ └── 0019-PVE-block-add-the-zeroinit-block-driver-filter.patch │ ├── bitmap-mirror │ │ ├── 0003-mirror-add-check-for-bitmap-mode-without-bitmap.patch │ │ ├── 0004-mirror-switch-to-bdrv_dirty_bitmap_merge_internal.patch │ │ └── 0002-drive-mirror-add-support-for-conditional-and-always-.patch │ ├── extra │ │ ├── 0003-tcg-arm-Fix-tgen_deposit.patch │ │ ├── 0009-file-posix-populate-pwrite_zeroes_alignment.patch │ │ ├── 0007-vfio-only-check-region-info-cache-for-initial-region.patch │ │ ├── 0004-vfio-igd-Enable-quirks-when-IGD-is-not-the-primary-d.patch │ │ ├── 0005-hw-scsi-avoid-deadlock-upon-TMF-request-cancelling-w.patch │ │ ├── 0010-block-use-pwrite_zeroes_alignment-when-writing-first.patch │ │ ├── 0002-ide-avoid-potential-deadlock-when-draining-during-tr.patch │ │ ├── 0008-ui-vdagent-fix-windows-agent-regression.patch │ │ ├── 0011-block-io_uring-avoid-potentially-getting-stuck-after.patch │ │ └── 0001-monitor-qmp-fix-race-with-clients-disconnecting-earl.patch │ └── series ├── control ├── copyright └── rules ├── .gitmodules ├── .gitignore ├── Makefile ├── vma_spec.txt └── backup.txt /debian/docs: -------------------------------------------------------------------------------- 1 | debian/SOURCE 2 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (quilt) 2 | -------------------------------------------------------------------------------- /debian/kvm-ifdown: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | exit 0 -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "qemu"] 2 | path = qemu 3 | url = ../mirror_qemu 4 | -------------------------------------------------------------------------------- /debian/Logo.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/proxmox/pve-qemu/HEAD/debian/Logo.bmp -------------------------------------------------------------------------------- /debian/OVMF_CODE-pure-efi.fd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/proxmox/pve-qemu/HEAD/debian/OVMF_CODE-pure-efi.fd -------------------------------------------------------------------------------- /debian/OVMF_VARS-pure-efi.fd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/proxmox/pve-qemu/HEAD/debian/OVMF_VARS-pure-efi.fd -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /*.build 2 | /*.buildinfo 3 | /*.changes 4 | /*.deb 5 | /*.dsc 6 | /*.tar* 7 | /pve-qemu-kvm-*.*/ 8 | -------------------------------------------------------------------------------- /debian/source/include-binaries: -------------------------------------------------------------------------------- 1 | debian/OVMF_CODE-pure-efi.fd 2 | debian/OVMF_VARS-pure-efi.fd 3 | debian/Logo.bmp 4 | -------------------------------------------------------------------------------- /debian/source/lintian-overrides: -------------------------------------------------------------------------------- 1 | source-is-missing [roms/SLOF/*.oco] 2 | source-is-missing [linux-user/*/vdso-*.so] 3 | -------------------------------------------------------------------------------- /debian/kvm-ifup: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | switch=$(/sbin/ip route show |sed -nre 's/^default .* dev ([^ ]+).*$/\1/;T;p;q') 4 | /sbin/ip link set "$1" up promisc on 5 | test -d "/sys/class/net/$switch/bridge" && /sbin/ip link set "$1" master "$switch" 6 | -------------------------------------------------------------------------------- /debian/pve-qemu-kvm.install: -------------------------------------------------------------------------------- 1 | #install ovmf uefi rom 2 | debian/OVMF_CODE-pure-efi.fd usr/share/kvm/ 3 | debian/OVMF_VARS-pure-efi.fd usr/share/kvm/ 4 | debian/kvm-ifdown etc/kvm/ 5 | # install the userspace utilities 6 | debian/kvm-ifup etc/kvm/ 7 | -------------------------------------------------------------------------------- /debian/OVMF_README.txt: -------------------------------------------------------------------------------- 1 | The OVMF images were built through the edk2 github repository. 2 | 3 | git clone https://github.com/tianocore/edk2 4 | 5 | set up the build environment 6 | 7 | copy the Logo.bmp to ./edk2/MdeModulePkg/Logo/ 8 | 9 | call ./edk2/OvmfPkg/build.sh -a X64 -b RELEASE 10 | 11 | The license is under ./edk2/OvmfPkg/License.txt 12 | -------------------------------------------------------------------------------- /debian/parse-cpu-flags.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use warnings; 4 | use strict; 5 | 6 | my @flags = (); 7 | my $got_flags_section; 8 | 9 | while () { 10 | if (/^\s*Recognized CPUID flags:/) { 11 | $got_flags_section = 1; 12 | next; 13 | } 14 | next if !$got_flags_section; 15 | 16 | s/^\s+//; 17 | 18 | push @flags, split(/\s+/); 19 | } 20 | 21 | die "no QEMU/KVM CPU flags detected from STDIN input" if scalar (@flags) <= 0; 22 | 23 | print join("\n", @flags) or die "$!\n"; 24 | -------------------------------------------------------------------------------- /debian/pve-qemu-kvm.lintian-overrides: -------------------------------------------------------------------------------- 1 | pve-qemu-kvm: arch-dependent-file-in-usr-share [usr/share/kvm/hppa-firmware.img] 2 | pve-qemu-kvm: binary-from-other-architecture [usr/share/kvm/hppa-firmware.img] 3 | pve-qemu-kvm: embedded-javascript-library please use * [usr/share/doc/pve-qemu-kvm/kvm/_static/*] 4 | pve-qemu-kvm: groff-message *: warning [*]: can't break line [usr/share/man/*] 5 | pve-qemu-kvm: groff-message *: warning [*]: cannot adjust line [usr/share/man/*] 6 | pve-qemu-kvm: statically-linked-binary [usr/share/kvm/hppa-firmware.img] 7 | pve-qemu-kvm: unstripped-binary-or-object [usr/share/kvm/hppa-firmware.img] 8 | -------------------------------------------------------------------------------- /debian/parse-machines.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use warnings; 4 | use strict; 5 | 6 | use JSON; 7 | 8 | my $machines = []; 9 | 10 | while () { 11 | if (/^\s*Supported machines are:/) { 12 | next; 13 | } 14 | 15 | s/^\s+//; 16 | my @machine = split(/\s+/); 17 | next if $machine[0] !~ m/^pc-(i440fx|q35)-(.+)$/; 18 | push @$machines, { 19 | 'id' => $machine[0], 20 | 'type' => $1, 21 | 'version' => $2, 22 | }; 23 | } 24 | 25 | die "no QEMU machine types detected from STDIN input" if scalar (@$machines) <= 0; 26 | 27 | print to_json($machines, { utf8 => 1, canonical => 1 }) 28 | or die "failed to encode detected machines as JSON - $!\n"; 29 | -------------------------------------------------------------------------------- /debian/pve-qemu-kvm.links: -------------------------------------------------------------------------------- 1 | # also use aarch64 for 32 bit arm 2 | usr/bin/qemu-system-aarch64 usr/bin/qemu-system-arm 3 | usr/bin/qemu-system-x86_64 usr/bin/kvm 4 | # qemu-system-i386 and qemu-system-x86_64 provides the same hardware emulation 5 | usr/bin/qemu-system-x86_64 usr/bin/qemu-system-i386 6 | # upstream provides a qemu man page, 7 | # we symlink to kvm for backward compatibility 8 | # and to qemu-system-{i386,x86_64} to fullfill our 'Provides: qemu-system-x86' 9 | usr/share/man/man1/qemu.1 usr/share/man/man1/kvm.1 10 | usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-aarch64.1 11 | usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-arm.1 12 | usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-i386.1 13 | usr/share/man/man1/qemu.1 usr/share/man/man1/qemu-system-x86_64.1 14 | -------------------------------------------------------------------------------- /debian/patches/pve/0037-PVE-block-stream-increase-chunk-size.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Stefan Reiter 3 | Date: Tue, 2 Mar 2021 16:34:28 +0100 4 | Subject: [PATCH] PVE: block/stream: increase chunk size 5 | 6 | Ceph favors bigger chunks, so increase to 4M. 7 | 8 | Signed-off-by: Thomas Lamprecht 9 | --- 10 | block/stream.c | 2 +- 11 | 1 file changed, 1 insertion(+), 1 deletion(-) 12 | 13 | diff --git a/block/stream.c b/block/stream.c 14 | index c0616b69e2..d023753091 100644 15 | --- a/block/stream.c 16 | +++ b/block/stream.c 17 | @@ -27,7 +27,7 @@ enum { 18 | * large enough to process multiple clusters in a single call, so 19 | * that populating contiguous regions of the image is efficient. 20 | */ 21 | - STREAM_CHUNK = 512 * 1024, /* in bytes */ 22 | + STREAM_CHUNK = 4 * 1024 * 1024, /* in bytes */ 23 | }; 24 | 25 | typedef struct StreamBlockJob { 26 | -------------------------------------------------------------------------------- /debian/patches/pve/0008-PVE-Up-qemu-img-return-success-on-info-without-snaps.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Wolfgang Bumiller 3 | Date: Mon, 6 Apr 2020 12:16:39 +0200 4 | Subject: [PATCH] PVE: [Up] qemu-img: return success on info without snapshots 5 | 6 | Signed-off-by: Thomas Lamprecht 7 | --- 8 | qemu-img.c | 3 ++- 9 | 1 file changed, 2 insertions(+), 1 deletion(-) 10 | 11 | diff --git a/qemu-img.c b/qemu-img.c 12 | index 7a162fdc08..0bed551960 100644 13 | --- a/qemu-img.c 14 | +++ b/qemu-img.c 15 | @@ -3158,7 +3158,8 @@ static int img_info(const img_cmd_t *ccmd, int argc, char **argv) 16 | list = collect_image_info_list(image_opts, filename, fmt, chain, 17 | force_share); 18 | if (!list) { 19 | - return 1; 20 | + // return success if snapshot does not exist 21 | + return 0; 22 | } 23 | 24 | switch (output_format) { 25 | -------------------------------------------------------------------------------- /debian/patches/pve/0003-PVE-Config-set-the-CPU-model-to-kvm64-32-instead-of-.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Wolfgang Bumiller 3 | Date: Mon, 6 Apr 2020 12:16:32 +0200 4 | Subject: [PATCH] PVE: [Config] set the CPU model to kvm64/32 instead of 5 | qemu64/32 6 | 7 | Signed-off-by: Thomas Lamprecht 8 | --- 9 | target/i386/cpu.h | 4 ++-- 10 | 1 file changed, 2 insertions(+), 2 deletions(-) 11 | 12 | diff --git a/target/i386/cpu.h b/target/i386/cpu.h 13 | index 42168f1d6d..4f63100453 100644 14 | --- a/target/i386/cpu.h 15 | +++ b/target/i386/cpu.h 16 | @@ -2630,9 +2630,9 @@ uint64_t cpu_get_tsc(CPUX86State *env); 17 | #define CPU_RESOLVING_TYPE TYPE_X86_CPU 18 | 19 | #ifdef TARGET_X86_64 20 | -#define TARGET_DEFAULT_CPU_TYPE X86_CPU_TYPE_NAME("qemu64") 21 | +#define TARGET_DEFAULT_CPU_TYPE X86_CPU_TYPE_NAME("kvm64") 22 | #else 23 | -#define TARGET_DEFAULT_CPU_TYPE X86_CPU_TYPE_NAME("qemu32") 24 | +#define TARGET_DEFAULT_CPU_TYPE X86_CPU_TYPE_NAME("kvm32") 25 | #endif 26 | 27 | /* MMU modes definitions */ 28 | -------------------------------------------------------------------------------- /debian/patches/pve/0002-PVE-Config-Adjust-network-script-path-to-etc-kvm.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Wolfgang Bumiller 3 | Date: Mon, 6 Apr 2020 12:16:31 +0200 4 | Subject: [PATCH] PVE: [Config] Adjust network script path to /etc/kvm/ 5 | 6 | Signed-off-by: Thomas Lamprecht 7 | --- 8 | include/net/net.h | 4 ++-- 9 | 1 file changed, 2 insertions(+), 2 deletions(-) 10 | 11 | diff --git a/include/net/net.h b/include/net/net.h 12 | index 84ee18e0f9..d42d935db5 100644 13 | --- a/include/net/net.h 14 | +++ b/include/net/net.h 15 | @@ -311,8 +311,8 @@ void netdev_add(QemuOpts *opts, Error **errp); 16 | 17 | int net_hub_id_for_client(NetClientState *nc, int *id); 18 | 19 | -#define DEFAULT_NETWORK_SCRIPT CONFIG_SYSCONFDIR "/qemu-ifup" 20 | -#define DEFAULT_NETWORK_DOWN_SCRIPT CONFIG_SYSCONFDIR "/qemu-ifdown" 21 | +#define DEFAULT_NETWORK_SCRIPT CONFIG_SYSCONFDIR "/kvm/kvm-ifup" 22 | +#define DEFAULT_NETWORK_DOWN_SCRIPT CONFIG_SYSCONFDIR "/kvm/kvm-ifdown" 23 | #define DEFAULT_BRIDGE_HELPER CONFIG_QEMU_HELPERDIR "/qemu-bridge-helper" 24 | #define DEFAULT_BRIDGE_INTERFACE "br0" 25 | 26 | -------------------------------------------------------------------------------- /debian/patches/pve/0021-PVE-Config-Revert-target-i386-disable-LINT0-after-re.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Wolfgang Bumiller 3 | Date: Mon, 6 Apr 2020 12:16:49 +0200 4 | Subject: [PATCH] PVE: [Config] Revert "target-i386: disable LINT0 after reset" 5 | 6 | This reverts commit b8eb5512fd8a115f164edbbe897cdf8884920ccb. 7 | 8 | Signed-off-by: Thomas Lamprecht 9 | --- 10 | hw/intc/apic_common.c | 9 +++++++++ 11 | 1 file changed, 9 insertions(+) 12 | 13 | diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c 14 | index 37a7a7019d..444136c665 100644 15 | --- a/hw/intc/apic_common.c 16 | +++ b/hw/intc/apic_common.c 17 | @@ -263,6 +263,15 @@ static void apic_reset_common(DeviceState *dev) 18 | info->vapic_base_update(s); 19 | 20 | apic_init_reset(dev); 21 | + 22 | + if (bsp) { 23 | + /* 24 | + * LINT0 delivery mode on CPU #0 is set to ExtInt at initialization 25 | + * time typically by BIOS, so PIC interrupt can be delivered to the 26 | + * processor when local APIC is enabled. 27 | + */ 28 | + s->lvt[APIC_LVT_LINT0] = 0x700; 29 | + } 30 | } 31 | 32 | static const VMStateDescription vmstate_apic_common; 33 | -------------------------------------------------------------------------------- /debian/patches/bitmap-mirror/0003-mirror-add-check-for-bitmap-mode-without-bitmap.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?Fabian=20Gr=C3=BCnbichler?= 3 | Date: Mon, 6 Apr 2020 12:17:05 +0200 4 | Subject: [PATCH] mirror: add check for bitmap-mode without bitmap 5 | MIME-Version: 1.0 6 | Content-Type: text/plain; charset=UTF-8 7 | Content-Transfer-Encoding: 8bit 8 | 9 | as one without the other does not make much sense with the current set 10 | of modes. 11 | 12 | Signed-off-by: Fabian Grünbichler 13 | Signed-off-by: Thomas Lamprecht 14 | --- 15 | blockdev.c | 3 +++ 16 | 1 file changed, 3 insertions(+) 17 | 18 | diff --git a/blockdev.c b/blockdev.c 19 | index 5855e9cac2..f132b4985b 100644 20 | --- a/blockdev.c 21 | +++ b/blockdev.c 22 | @@ -2950,6 +2950,9 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs, 23 | if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_ALLOW_RO, errp)) { 24 | return; 25 | } 26 | + } else if (has_bitmap_mode) { 27 | + error_setg(errp, "Cannot specify bitmap sync mode without a bitmap"); 28 | + return; 29 | } 30 | 31 | if (!replaces) { 32 | -------------------------------------------------------------------------------- /debian/patches/pve/0006-PVE-Config-rbd-block-rbd-disable-rbd_cache_writethro.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Wolfgang Bumiller 3 | Date: Mon, 6 Apr 2020 12:16:36 +0200 4 | Subject: [PATCH] PVE: [Config] rbd: block: rbd: disable 5 | rbd_cache_writethrough_until_flush 6 | 7 | Either the cache mode asks for a cache or not. There's no 8 | point in having a "temporary" cache mode. This option AFAIK 9 | was introduced as a hack for ancient virtio drivers. If 10 | anything, we should have a separate option for it. Better 11 | yet, VMs affected by the related issue should simply 12 | explicitly choose writethrough. 13 | 14 | Signed-off-by: Wolfgang Bumiller 15 | Signed-off-by: Thomas Lamprecht 16 | --- 17 | block/rbd.c | 2 ++ 18 | 1 file changed, 2 insertions(+) 19 | 20 | diff --git a/block/rbd.c b/block/rbd.c 21 | index 3611dc81cf..d114119671 100644 22 | --- a/block/rbd.c 23 | +++ b/block/rbd.c 24 | @@ -1017,6 +1017,8 @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx, 25 | rados_conf_set(*cluster, "rbd_cache", "false"); 26 | } 27 | 28 | + rados_conf_set(*cluster, "rbd_cache_writethrough_until_flush", "false"); 29 | + 30 | r = rados_connect(*cluster); 31 | if (r < 0) { 32 | error_setg_errno(errp, -r, "error connecting"); 33 | -------------------------------------------------------------------------------- /debian/patches/pve/0023-PVE-monitor-disable-oob-capability.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Wolfgang Bumiller 3 | Date: Mon, 6 Apr 2020 12:16:53 +0200 4 | Subject: [PATCH] PVE: monitor: disable oob capability 5 | 6 | A bisect revealed that commit 8258292e18c3 7 | ("monitor: Remove "x-oob", offer capability "oob" unconditionally") 8 | causes unexpected hangs when restoring live snapshots from some 9 | types of block devices (particularly RBD). 10 | We need to figure out what's happnening there. For now, since we 11 | had this disabled before and probably don't need it now either, 12 | disable oob, so we can get a functioning qemu out... 13 | 14 | Signed-off-by: Wolfgang Bumiller 15 | Signed-off-by: Thomas Lamprecht 16 | --- 17 | monitor/qmp.c | 3 +-- 18 | 1 file changed, 1 insertion(+), 2 deletions(-) 19 | 20 | diff --git a/monitor/qmp.c b/monitor/qmp.c 21 | index 170fef4531..448403b45b 100644 22 | --- a/monitor/qmp.c 23 | +++ b/monitor/qmp.c 24 | @@ -535,8 +535,7 @@ void monitor_init_qmp(Chardev *chr, bool pretty, Error **errp) 25 | qemu_chr_fe_set_echo(&mon->common.chr, true); 26 | 27 | /* Note: we run QMP monitor in I/O thread when @chr supports that */ 28 | - monitor_data_init(&mon->common, true, false, 29 | - qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_GCONTEXT)); 30 | + monitor_data_init(&mon->common, true, false, false); 31 | 32 | mon->pretty = pretty; 33 | 34 | -------------------------------------------------------------------------------- /debian/patches/pve/0001-PVE-Config-block-file-change-locking-default-to-off.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Wolfgang Bumiller 3 | Date: Mon, 6 Apr 2020 12:16:30 +0200 4 | Subject: [PATCH] PVE: [Config] block/file: change locking default to off 5 | 6 | 'auto' only checks whether the system generally supports OFD 7 | locks but not whether the storage the file resides on 8 | supports any locking, causing issues with NFS. 9 | 10 | Signed-off-by: Wolfgang Bumiller 11 | Signed-off-by: Thomas Lamprecht 12 | --- 13 | block/file-posix.c | 4 ++-- 14 | 1 file changed, 2 insertions(+), 2 deletions(-) 15 | 16 | diff --git a/block/file-posix.c b/block/file-posix.c 17 | index 827ffa77a5..baac7653db 100644 18 | --- a/block/file-posix.c 19 | +++ b/block/file-posix.c 20 | @@ -588,7 +588,7 @@ static QemuOptsList raw_runtime_opts = { 21 | { 22 | .name = "locking", 23 | .type = QEMU_OPT_STRING, 24 | - .help = "file locking mode (on/off/auto, default: auto)", 25 | + .help = "file locking mode (on/off/auto, default: off)", 26 | }, 27 | { 28 | .name = "pr-manager", 29 | @@ -688,7 +688,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, 30 | s->use_lock = false; 31 | break; 32 | case ON_OFF_AUTO_AUTO: 33 | - s->use_lock = qemu_has_ofd_lock(); 34 | + s->use_lock = false; 35 | break; 36 | default: 37 | abort(); 38 | -------------------------------------------------------------------------------- /debian/patches/pve/0035-migration-block-dirty-bitmap-migrate-other-bitmaps-e.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Stefan Reiter 3 | Date: Tue, 3 Nov 2020 14:57:32 +0100 4 | Subject: [PATCH] migration/block-dirty-bitmap: migrate other bitmaps even if 5 | one fails 6 | 7 | If the checks in bdrv_dirty_bitmap_check fail, that only means that this 8 | one specific bitmap cannot be migrated. That is not an error condition 9 | for any other bitmaps on the same block device. 10 | 11 | Fixes dirty-bitmap migration with sync=bitmap, as the bitmaps used for 12 | that are obviously marked as "busy", which would cause none at all to be 13 | transferred. 14 | 15 | Signed-off-by: Stefan Reiter 16 | Signed-off-by: Thomas Lamprecht 17 | --- 18 | migration/block-dirty-bitmap.c | 6 +++++- 19 | 1 file changed, 5 insertions(+), 1 deletion(-) 20 | 21 | diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c 22 | index a061aad817..d5fca0b96a 100644 23 | --- a/migration/block-dirty-bitmap.c 24 | +++ b/migration/block-dirty-bitmap.c 25 | @@ -539,7 +539,11 @@ static int add_bitmaps_to_list(DBMSaveState *s, BlockDriverState *bs, 26 | } 27 | 28 | if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_DEFAULT, errp)) { 29 | - return -1; 30 | + if (errp != NULL) { 31 | + error_report_err(*errp); 32 | + *errp = NULL; 33 | + } 34 | + continue; 35 | } 36 | 37 | if (bitmap_aliases) { 38 | -------------------------------------------------------------------------------- /debian/patches/extra/0003-tcg-arm-Fix-tgen_deposit.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Richard Henderson 3 | Date: Fri, 29 Aug 2025 13:49:06 +0000 4 | Subject: [PATCH] tcg/arm: Fix tgen_deposit 5 | MIME-Version: 1.0 6 | Content-Type: text/plain; charset=UTF-8 7 | Content-Transfer-Encoding: 8bit 8 | 9 | When converting from tcg_out_deposit, the arguments were not 10 | shuffled properly. 11 | 12 | Cc: qemu-stable@nongnu.org 13 | Fixes: cf4905c03135f1181e8 ("tcg: Convert deposit to TCGOutOpDeposit") 14 | Reported-by: Michael Tokarev 15 | Tested-by: Michael Tokarev 16 | Reviewed-by: Philippe Mathieu-Daudé 17 | Signed-off-by: Richard Henderson 18 | (cherry picked from commit 27ea28a0b369b4b14a485a5d6f045e0dc1db4e38) 19 | Signed-off-by: Fiona Ebner 20 | --- 21 | tcg/arm/tcg-target.c.inc | 3 ++- 22 | 1 file changed, 2 insertions(+), 1 deletion(-) 23 | 24 | diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc 25 | index 836894b16a..338c57b061 100644 26 | --- a/tcg/arm/tcg-target.c.inc 27 | +++ b/tcg/arm/tcg-target.c.inc 28 | @@ -975,7 +975,8 @@ static void tgen_deposit(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, 29 | TCGReg a2, unsigned ofs, unsigned len) 30 | { 31 | /* bfi/bfc */ 32 | - tcg_out32(s, 0x07c00010 | (COND_AL << 28) | (a0 << 12) | a1 33 | + tcg_debug_assert(a0 == a1); 34 | + tcg_out32(s, 0x07c00010 | (COND_AL << 28) | (a0 << 12) | a2 35 | | (ofs << 7) | ((ofs + len - 1) << 16)); 36 | } 37 | 38 | -------------------------------------------------------------------------------- /debian/patches/pve/0015-PVE-qapi-modify-spice-query.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Wolfgang Bumiller 3 | Date: Mon, 6 Apr 2020 12:16:45 +0200 4 | Subject: [PATCH] PVE: qapi: modify spice query 5 | 6 | Provide the last ticket in the SpiceInfo struct optionally. 7 | 8 | Signed-off-by: Thomas Lamprecht 9 | [FE: adapt to QAPI change] 10 | Signed-off-by: Fiona Ebner 11 | --- 12 | qapi/ui.json | 3 +++ 13 | ui/spice-core.c | 4 ++++ 14 | 2 files changed, 7 insertions(+) 15 | 16 | diff --git a/qapi/ui.json b/qapi/ui.json 17 | index 1b2f4a4769..c9982e1bcc 100644 18 | --- a/qapi/ui.json 19 | +++ b/qapi/ui.json 20 | @@ -315,11 +315,14 @@ 21 | # 22 | # @channels: a list of `SpiceChannel` for each active spice channel 23 | # 24 | +# @ticket: The last ticket set with set_password 25 | +# 26 | # Since: 0.14 27 | ## 28 | { 'struct': 'SpiceInfo', 29 | 'data': {'enabled': 'bool', 'migrated': 'bool', '*host': 'str', '*port': 'int', 30 | '*tls-port': 'int', '*auth': 'str', '*compiled-version': 'str', 31 | + '*ticket': 'str', 32 | 'mouse-mode': 'SpiceQueryMouseMode', '*channels': ['SpiceChannel']}, 33 | 'if': 'CONFIG_SPICE' } 34 | 35 | diff --git a/ui/spice-core.c b/ui/spice-core.c 36 | index a8b34d3bf5..994079ec87 100644 37 | --- a/ui/spice-core.c 38 | +++ b/ui/spice-core.c 39 | @@ -554,6 +554,10 @@ static SpiceInfo *qmp_query_spice_real(Error **errp) 40 | micro = SPICE_SERVER_VERSION & 0xff; 41 | info->compiled_version = g_strdup_printf("%d.%d.%d", major, minor, micro); 42 | 43 | + if (auth_passwd) { 44 | + info->ticket = g_strdup(auth_passwd); 45 | + } 46 | + 47 | if (port) { 48 | info->has_port = true; 49 | info->port = port; 50 | -------------------------------------------------------------------------------- /debian/patches/pve/0005-PVE-Config-glusterfs-no-default-logfile-if-daemonize.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Wolfgang Bumiller 3 | Date: Mon, 6 Apr 2020 12:16:35 +0200 4 | Subject: [PATCH] PVE: [Config] glusterfs: no default logfile if daemonized 5 | 6 | Signed-off-by: Thomas Lamprecht 7 | --- 8 | block/gluster.c | 15 +++++++++++---- 9 | 1 file changed, 11 insertions(+), 4 deletions(-) 10 | 11 | diff --git a/block/gluster.c b/block/gluster.c 12 | index 89abd40f31..d3f2e56229 100644 13 | --- a/block/gluster.c 14 | +++ b/block/gluster.c 15 | @@ -42,7 +42,7 @@ 16 | #define GLUSTER_DEBUG_DEFAULT 4 17 | #define GLUSTER_DEBUG_MAX 9 18 | #define GLUSTER_OPT_LOGFILE "logfile" 19 | -#define GLUSTER_LOGFILE_DEFAULT "-" /* handled in libgfapi as /dev/stderr */ 20 | +#define GLUSTER_LOGFILE_DEFAULT NULL 21 | /* 22 | * Several versions of GlusterFS (3.12? -> 6.0.1) fail when the transfer size 23 | * is greater or equal to 1024 MiB, so we are limiting the transfer size to 512 24 | @@ -421,6 +421,7 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf, 25 | int old_errno; 26 | SocketAddressList *server; 27 | uint64_t port; 28 | + const char *logfile; 29 | 30 | glfs = glfs_find_preopened(gconf->volume); 31 | if (glfs) { 32 | @@ -463,9 +464,15 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf, 33 | } 34 | } 35 | 36 | - ret = glfs_set_logging(glfs, gconf->logfile, gconf->debug); 37 | - if (ret < 0) { 38 | - goto out; 39 | + logfile = gconf->logfile; 40 | + if (!logfile && !is_daemonized()) { 41 | + logfile = "-"; 42 | + } 43 | + if (logfile) { 44 | + ret = glfs_set_logging(glfs, logfile, gconf->debug); 45 | + if (ret < 0) { 46 | + goto out; 47 | + } 48 | } 49 | 50 | ret = glfs_init(glfs); 51 | -------------------------------------------------------------------------------- /debian/patches/bitmap-mirror/0004-mirror-switch-to-bdrv_dirty_bitmap_merge_internal.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?Fabian=20Gr=C3=BCnbichler?= 3 | Date: Mon, 6 Apr 2020 12:17:06 +0200 4 | Subject: [PATCH] mirror: switch to bdrv_dirty_bitmap_merge_internal 5 | MIME-Version: 1.0 6 | Content-Type: text/plain; charset=UTF-8 7 | Content-Transfer-Encoding: 8bit 8 | 9 | since sync_bitmap is busy at the point of merging, and we checked access 10 | beforehand. 11 | 12 | Signed-off-by: Fabian Grünbichler 13 | Signed-off-by: Thomas Lamprecht 14 | --- 15 | block/mirror.c | 11 ++++------- 16 | 1 file changed, 4 insertions(+), 7 deletions(-) 17 | 18 | diff --git a/block/mirror.c b/block/mirror.c 19 | index 79b6f16d27..4741930d9b 100644 20 | --- a/block/mirror.c 21 | +++ b/block/mirror.c 22 | @@ -855,8 +855,8 @@ static int mirror_exit_common(Job *job) 23 | job->ret == 0 && ret == 0)) { 24 | /* Success; synchronize copy back to sync. */ 25 | bdrv_clear_dirty_bitmap(s->sync_bitmap, NULL); 26 | - bdrv_merge_dirty_bitmap(s->sync_bitmap, s->dirty_bitmap, 27 | - NULL, &error_abort); 28 | + bdrv_dirty_bitmap_merge_internal(s->sync_bitmap, s->dirty_bitmap, 29 | + NULL, true); 30 | } 31 | } 32 | bdrv_release_dirty_bitmap(s->dirty_bitmap); 33 | @@ -2085,11 +2085,8 @@ static BlockJob *mirror_start_job( 34 | } 35 | 36 | if (s->sync_mode == MIRROR_SYNC_MODE_BITMAP) { 37 | - bdrv_merge_dirty_bitmap(s->dirty_bitmap, s->sync_bitmap, 38 | - NULL, &local_err); 39 | - if (local_err) { 40 | - goto fail; 41 | - } 42 | + bdrv_dirty_bitmap_merge_internal(s->dirty_bitmap, s->sync_bitmap, 43 | + NULL, true); 44 | } 45 | 46 | bdrv_graph_wrlock_drained(); 47 | -------------------------------------------------------------------------------- /debian/patches/extra/0009-file-posix-populate-pwrite_zeroes_alignment.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Stefan Hajnoczi 3 | Date: Tue, 7 Oct 2025 10:16:58 -0400 4 | Subject: [PATCH] file-posix: populate pwrite_zeroes_alignment 5 | 6 | Linux block devices require write zeroes alignment whereas files do not. 7 | 8 | It may come as a surprise that block devices opened in buffered I/O mode 9 | require the alignment for write zeroes requests although normal 10 | read/write requests do not. 11 | 12 | Therefore it is necessary to populate the pwrite_zeroes_alignment field. 13 | 14 | Signed-off-by: Stefan Hajnoczi 15 | Reviewed-by: Vladimir Sementsov-Ogievskiy 16 | Link: https://lore.kernel.org/20251007141700.71891-2-stefanha@redhat.com 17 | [FE: picked from qemu-devel] 18 | Signed-off-by: Fiona Ebner 19 | --- 20 | block/file-posix.c | 16 ++++++++++++++++ 21 | 1 file changed, 16 insertions(+) 22 | 23 | diff --git a/block/file-posix.c b/block/file-posix.c 24 | index 8c738674ce..827ffa77a5 100644 25 | --- a/block/file-posix.c 26 | +++ b/block/file-posix.c 27 | @@ -1602,6 +1602,22 @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp) 28 | 29 | bs->bl.pdiscard_alignment = dalign; 30 | } 31 | + 32 | +#ifdef __linux__ 33 | + /* 34 | + * Linux requires logical block size alignment for write zeroes even 35 | + * when normal reads/writes do not require alignment. 36 | + */ 37 | + if (!s->needs_alignment) { 38 | + ret = probe_logical_blocksize(s->fd, 39 | + &bs->bl.pwrite_zeroes_alignment); 40 | + if (ret < 0) { 41 | + error_setg_errno(errp, -ret, 42 | + "Failed to probe logical block size"); 43 | + return; 44 | + } 45 | + } 46 | +#endif /* __linux__ */ 47 | } 48 | 49 | raw_refresh_zoned_limits(bs, &st, errp); 50 | -------------------------------------------------------------------------------- /debian/patches/pve/0024-PVE-Compat-4.0-used-balloon-qemu-4-0-config-size-fal.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Thomas Lamprecht 3 | Date: Mon, 6 Apr 2020 12:16:54 +0200 4 | Subject: [PATCH] PVE: [Compat]: 4.0 used balloon qemu-4-0-config-size false 5 | here 6 | 7 | The underlying issue why this change from upstream to us arised in 8 | the first place is that QEMU 4.0 was already released at the point we 9 | run into this migration issue, so we did the then obvious fallback to 10 | false for virtio-balloon-device qemu-4-0-config-size. 11 | 12 | QEMU made that switch back in 4.1, where it now uses a backward 13 | compatible mechanism to detect if the bigger CFG sizes should be 14 | used, i.e., checking the VIRTIO_BALLOON_F_PAGE_POISON or 15 | VIRTIO_BALLOON_F_FREE_PAGE_HINT balloon feature flags. 16 | As for them, upstream released version 4.0 had this to true they keep 17 | it to true in their compatibility record for the 4.0 machine, to 18 | allow live migrations from 4.0 to 4.1. 19 | As for us, downstream released version 4.0 (first public release of 20 | this QEMU) had this to false, we change it back to false again, for 21 | the same reason. 22 | 23 | Signed-off-by: Thomas Lamprecht 24 | --- 25 | hw/core/machine.c | 3 ++- 26 | 1 file changed, 2 insertions(+), 1 deletion(-) 27 | 28 | diff --git a/hw/core/machine.c b/hw/core/machine.c 29 | index bd47527479..e59b12d9f0 100644 30 | --- a/hw/core/machine.c 31 | +++ b/hw/core/machine.c 32 | @@ -201,7 +201,8 @@ GlobalProperty hw_compat_4_0[] = { 33 | { "virtio-vga", "edid", "false" }, 34 | { "virtio-gpu-device", "edid", "false" }, 35 | { "virtio-device", "use-started", "false" }, 36 | - { "virtio-balloon-device", "qemu-4-0-config-size", "true" }, 37 | + // PVE differed from upstream for 4.0 balloon cfg size 38 | + { "virtio-balloon-device", "qemu-4-0-config-size", "false" }, 39 | { "pl031", "migrate-tick-offset", "false" }, 40 | }; 41 | const size_t hw_compat_4_0_len = G_N_ELEMENTS(hw_compat_4_0); 42 | -------------------------------------------------------------------------------- /debian/patches/pve/0041-PVE-backup-factor-out-helper-to-clear-backup-state-s.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Fiona Ebner 3 | Date: Thu, 3 Apr 2025 14:30:42 +0200 4 | Subject: [PATCH] PVE backup: factor out helper to clear backup state's bitmap 5 | list 6 | 7 | Suggested-by: Wolfgang Bumiller 8 | Signed-off-by: Fiona Ebner 9 | Reviewed-by: Wolfgang Bumiller 10 | --- 11 | pve-backup.c | 28 ++++++++++++++++++---------- 12 | 1 file changed, 18 insertions(+), 10 deletions(-) 13 | 14 | diff --git a/pve-backup.c b/pve-backup.c 15 | index 8b83465ebd..3e0d1ffc5c 100644 16 | --- a/pve-backup.c 17 | +++ b/pve-backup.c 18 | @@ -811,6 +811,23 @@ err: 19 | return di_list; 20 | } 21 | 22 | +/* 23 | + * To be called with the backup_state.stat mutex held. 24 | + */ 25 | +static void clear_backup_state_bitmap_list(void) { 26 | + 27 | + if (backup_state.stat.bitmap_list) { 28 | + GList *bl = backup_state.stat.bitmap_list; 29 | + while (bl) { 30 | + g_free(((PBSBitmapInfo *)bl->data)->drive); 31 | + g_free(bl->data); 32 | + bl = g_list_next(bl); 33 | + } 34 | + g_list_free(backup_state.stat.bitmap_list); 35 | + backup_state.stat.bitmap_list = NULL; 36 | + } 37 | +} 38 | + 39 | UuidInfo coroutine_fn *qmp_backup( 40 | const char *backup_file, 41 | const char *password, 42 | @@ -898,16 +915,7 @@ UuidInfo coroutine_fn *qmp_backup( 43 | backup_state.stat.reused = 0; 44 | 45 | /* clear previous backup's bitmap_list */ 46 | - if (backup_state.stat.bitmap_list) { 47 | - GList *bl = backup_state.stat.bitmap_list; 48 | - while (bl) { 49 | - g_free(((PBSBitmapInfo *)bl->data)->drive); 50 | - g_free(bl->data); 51 | - bl = g_list_next(bl); 52 | - } 53 | - g_list_free(backup_state.stat.bitmap_list); 54 | - backup_state.stat.bitmap_list = NULL; 55 | - } 56 | + clear_backup_state_bitmap_list(); 57 | 58 | if (format == BACKUP_FORMAT_PBS) { 59 | if (!password) { 60 | -------------------------------------------------------------------------------- /debian/patches/pve/0033-PVE-redirect-stderr-to-journal-when-daemonized.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Stefan Reiter 3 | Date: Tue, 12 Jan 2021 14:12:20 +0100 4 | Subject: [PATCH] PVE: redirect stderr to journal when daemonized 5 | 6 | QEMU uses the logging for error messages usually, so LOG_ERR is most 7 | fitting. 8 | 9 | Signed-off-by: Stefan Reiter 10 | Signed-off-by: Thomas Lamprecht 11 | --- 12 | meson.build | 3 ++- 13 | os-posix.c | 7 +++++-- 14 | 2 files changed, 7 insertions(+), 3 deletions(-) 15 | 16 | diff --git a/meson.build b/meson.build 17 | index 4861b69412..7e1935d43f 100644 18 | --- a/meson.build 19 | +++ b/meson.build 20 | @@ -2200,6 +2200,7 @@ endif 21 | has_gettid = cc.has_function('gettid') 22 | 23 | libuuid = cc.find_library('uuid', required: true) 24 | +libsystemd = cc.find_library('systemd', required: true) 25 | libproxmox_backup_qemu = cc.find_library('proxmox_backup_qemu', required: true) 26 | 27 | # libselinux 28 | @@ -3875,7 +3876,7 @@ if have_block 29 | elif host_os == 'emscripten' 30 | blockdev_ss.add(files('os-wasm.c')) 31 | else 32 | - blockdev_ss.add(files('os-posix.c')) 33 | + blockdev_ss.add(files('os-posix.c'), libsystemd) 34 | endif 35 | endif 36 | 37 | diff --git a/os-posix.c b/os-posix.c 38 | index 52925c23d3..84b96d3da9 100644 39 | --- a/os-posix.c 40 | +++ b/os-posix.c 41 | @@ -29,6 +29,8 @@ 42 | #include 43 | #include 44 | #include 45 | +#include 46 | +#include 47 | 48 | #include "qemu/error-report.h" 49 | #include "qemu/log.h" 50 | @@ -306,9 +308,10 @@ void os_setup_post(void) 51 | 52 | dup2(fd, 0); 53 | dup2(fd, 1); 54 | - /* In case -D is given do not redirect stderr to /dev/null */ 55 | + /* In case -D is given do not redirect stderr to journal */ 56 | if (!qemu_log_enabled()) { 57 | - dup2(fd, 2); 58 | + int journal_fd = sd_journal_stream_fd("QEMU", LOG_ERR, 0); 59 | + dup2(journal_fd, 2); 60 | } 61 | 62 | close(fd); 63 | -------------------------------------------------------------------------------- /debian/patches/pve/0014-PVE-qapi-modify-query-machines.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Dietmar Maurer 3 | Date: Mon, 6 Apr 2020 12:16:44 +0200 4 | Subject: [PATCH] PVE: qapi: modify query machines 5 | 6 | provide '*is-current' in MachineInfo struct 7 | 8 | Signed-off-by: Thomas Lamprecht 9 | Signed-off-by: Dietmar Maurer 10 | --- 11 | hw/core/machine-qmp-cmds.c | 6 ++++++ 12 | qapi/machine.json | 4 +++- 13 | 2 files changed, 9 insertions(+), 1 deletion(-) 14 | 15 | diff --git a/hw/core/machine-qmp-cmds.c b/hw/core/machine-qmp-cmds.c 16 | index 6aca1a626e..934cdb886d 100644 17 | --- a/hw/core/machine-qmp-cmds.c 18 | +++ b/hw/core/machine-qmp-cmds.c 19 | @@ -94,6 +94,12 @@ MachineInfoList *qmp_query_machines(bool has_compat_props, bool compat_props, 20 | info->numa_mem_supported = mc->numa_mem_supported; 21 | info->deprecated = !!mc->deprecation_reason; 22 | info->acpi = !!object_class_property_find(OBJECT_CLASS(mc), "acpi"); 23 | + 24 | + if (strcmp(mc->name, MACHINE_GET_CLASS(current_machine)->name) == 0) { 25 | + info->has_is_current = true; 26 | + info->is_current = true; 27 | + } 28 | + 29 | if (default_cpu_type) { 30 | info->default_cpu_type = g_strdup(default_cpu_type); 31 | } 32 | diff --git a/qapi/machine.json b/qapi/machine.json 33 | index 5f172ece18..47ac68a3b5 100644 34 | --- a/qapi/machine.json 35 | +++ b/qapi/machine.json 36 | @@ -170,6 +170,8 @@ 37 | # 38 | # @is-default: whether the machine is default 39 | # 40 | +# @is-current: whether this machine is currently used 41 | +# 42 | # @cpu-max: maximum number of CPUs supported by the machine type 43 | # (since 1.5) 44 | # 45 | @@ -202,7 +204,7 @@ 46 | ## 47 | { 'struct': 'MachineInfo', 48 | 'data': { 'name': 'str', '*alias': 'str', 49 | - '*is-default': 'bool', 'cpu-max': 'int', 50 | + '*is-default': 'bool', '*is-current': 'bool', 'cpu-max': 'int', 51 | 'hotpluggable-cpus': 'bool', 'numa-mem-supported': 'bool', 52 | 'deprecated': 'bool', '*default-cpu-type': 'str', 53 | '*default-ram-id': 'str', 'acpi': 'bool', 54 | -------------------------------------------------------------------------------- /debian/patches/pve/0004-PVE-Config-ui-spice-default-to-pve-certificates.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Wolfgang Bumiller 3 | Date: Mon, 6 Apr 2020 12:16:33 +0200 4 | Subject: [PATCH] PVE: [Config] ui/spice: default to pve certificates 5 | 6 | Signed-off-by: Thomas Lamprecht 7 | --- 8 | ui/spice-core.c | 15 +++++++++------ 9 | 1 file changed, 9 insertions(+), 6 deletions(-) 10 | 11 | diff --git a/ui/spice-core.c b/ui/spice-core.c 12 | index 2645e96ef6..a8b34d3bf5 100644 13 | --- a/ui/spice-core.c 14 | +++ b/ui/spice-core.c 15 | @@ -694,32 +694,35 @@ static void qemu_spice_init(void) 16 | 17 | if (tls_port) { 18 | x509_dir = qemu_opt_get(opts, "x509-dir"); 19 | - if (!x509_dir) { 20 | - x509_dir = "."; 21 | - } 22 | 23 | str = qemu_opt_get(opts, "x509-key-file"); 24 | if (str) { 25 | x509_key_file = g_strdup(str); 26 | - } else { 27 | + } else if (x509_dir) { 28 | x509_key_file = g_strdup_printf("%s/%s", x509_dir, 29 | X509_SERVER_KEY_FILE); 30 | + } else { 31 | + x509_key_file = g_strdup("/etc/pve/local/pve-ssl.key"); 32 | } 33 | 34 | str = qemu_opt_get(opts, "x509-cert-file"); 35 | if (str) { 36 | x509_cert_file = g_strdup(str); 37 | - } else { 38 | + } else if (x509_dir) { 39 | x509_cert_file = g_strdup_printf("%s/%s", x509_dir, 40 | X509_SERVER_CERT_FILE); 41 | + } else { 42 | + x509_cert_file = g_strdup("/etc/pve/local/pve-ssl.pem"); 43 | } 44 | 45 | str = qemu_opt_get(opts, "x509-cacert-file"); 46 | if (str) { 47 | x509_cacert_file = g_strdup(str); 48 | - } else { 49 | + } else if (x509_dir) { 50 | x509_cacert_file = g_strdup_printf("%s/%s", x509_dir, 51 | X509_CA_CERT_FILE); 52 | + } else { 53 | + x509_cacert_file = g_strdup("/etc/pve/pve-root-ca.pem"); 54 | } 55 | 56 | x509_key_password = qemu_opt_get(opts, "x509-key-password"); 57 | -------------------------------------------------------------------------------- /debian/patches/pve/0020-PVE-Add-dummy-id-command-line-parameter.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Wolfgang Bumiller 3 | Date: Mon, 6 Apr 2020 12:16:48 +0200 4 | Subject: [PATCH] PVE: Add dummy -id command line parameter 5 | 6 | This used to be part of the qemu-side PVE authentication for 7 | VNC. Now this does nothing. 8 | 9 | Signed-off-by: Wolfgang Bumiller 10 | Signed-off-by: Thomas Lamprecht 11 | --- 12 | qemu-options.hx | 3 +++ 13 | system/vl.c | 8 ++++++++ 14 | 2 files changed, 11 insertions(+) 15 | 16 | diff --git a/qemu-options.hx b/qemu-options.hx 17 | index 3ec9e52d31..bb41239111 100644 18 | --- a/qemu-options.hx 19 | +++ b/qemu-options.hx 20 | @@ -1285,6 +1285,9 @@ legacy PC, they are not recommended for modern configurations. 21 | 22 | ERST 23 | 24 | +DEF("id", HAS_ARG, QEMU_OPTION_id, 25 | + "-id n set the VMID", QEMU_ARCH_ALL) 26 | + 27 | DEF("fda", HAS_ARG, QEMU_OPTION_fda, 28 | "-fda/-fdb file use 'file' as floppy disk 0/1 image\n", QEMU_ARCH_ALL) 29 | DEF("fdb", HAS_ARG, QEMU_OPTION_fdb, "", QEMU_ARCH_ALL) 30 | diff --git a/system/vl.c b/system/vl.c 31 | index 28a7d74f5b..56f8900451 100644 32 | --- a/system/vl.c 33 | +++ b/system/vl.c 34 | @@ -2851,6 +2851,7 @@ void qemu_init(int argc, char **argv) 35 | MachineClass *machine_class; 36 | bool userconfig = true; 37 | FILE *vmstate_dump_file = NULL; 38 | + long vm_id; 39 | 40 | qemu_add_opts(&qemu_drive_opts); 41 | qemu_add_drive_opts(&qemu_legacy_drive_opts); 42 | @@ -3469,6 +3470,13 @@ void qemu_init(int argc, char **argv) 43 | machine_parse_property_opt(qemu_find_opts("smp-opts"), 44 | "smp", optarg); 45 | break; 46 | + case QEMU_OPTION_id: 47 | + vm_id = strtol(optarg, (char **)&optarg, 10); 48 | + if (*optarg != 0 || vm_id < 100 || vm_id > INT_MAX) { 49 | + error_report("invalid -id argument %s", optarg); 50 | + exit(1); 51 | + } 52 | + break; 53 | #ifdef CONFIG_VNC 54 | case QEMU_OPTION_vnc: 55 | vnc_parse(optarg); 56 | -------------------------------------------------------------------------------- /debian/patches/pve/0043-PVE-backup-add-target-ID-in-backup-state.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Fiona Ebner 3 | Date: Thu, 3 Apr 2025 14:30:44 +0200 4 | Subject: [PATCH] PVE backup: add target ID in backup state 5 | 6 | In preparation for allowing multiple backup providers and potentially 7 | multiple targets for a given provider. Each backup target can then 8 | have its own dirty bitmap and there can be additional checks that the 9 | current backup state is actually associated to the expected target. 10 | 11 | Signed-off-by: Fiona Ebner 12 | Reviewed-by: Wolfgang Bumiller 13 | --- 14 | pve-backup.c | 15 ++++++++++++++- 15 | 1 file changed, 14 insertions(+), 1 deletion(-) 16 | 17 | diff --git a/pve-backup.c b/pve-backup.c 18 | index cc71279518..5f0ad5042f 100644 19 | --- a/pve-backup.c 20 | +++ b/pve-backup.c 21 | @@ -70,6 +70,7 @@ static struct PVEBackupState { 22 | JobTxn *txn; 23 | CoMutex backup_mutex; 24 | CoMutex dump_callback_mutex; 25 | + char *target_id; 26 | } backup_state; 27 | 28 | static void pvebackup_init(void) 29 | @@ -865,6 +866,16 @@ static void initialize_backup_state_stat( 30 | backup_state.stat.starting = true; 31 | } 32 | 33 | +/* 34 | + * To be called with the backup_state mutex held. 35 | + */ 36 | +static void backup_state_set_target_id(const char *target_id) { 37 | + if (backup_state.target_id) { 38 | + g_free(backup_state.target_id); 39 | + } 40 | + backup_state.target_id = g_strdup(target_id); 41 | +} 42 | + 43 | UuidInfo coroutine_fn *qmp_backup( 44 | const char *backup_file, 45 | const char *password, 46 | @@ -904,7 +915,7 @@ UuidInfo coroutine_fn *qmp_backup( 47 | 48 | if (backup_state.di_list) { 49 | error_set(errp, ERROR_CLASS_GENERIC_ERROR, 50 | - "previous backup not finished"); 51 | + "previous backup for target '%s' not finished", backup_state.target_id); 52 | qemu_co_mutex_unlock(&backup_state.backup_mutex); 53 | return NULL; 54 | } 55 | @@ -1122,6 +1133,8 @@ UuidInfo coroutine_fn *qmp_backup( 56 | backup_state.vmaw = vmaw; 57 | backup_state.pbs = pbs; 58 | 59 | + backup_state_set_target_id("Proxmox"); 60 | + 61 | backup_state.di_list = di_list; 62 | 63 | uuid_info = g_malloc0(sizeof(*uuid_info)); 64 | -------------------------------------------------------------------------------- /debian/patches/pve/0036-PVE-fall-back-to-open-iscsi-initiatorname.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Fabian Ebner 3 | Date: Tue, 17 Nov 2020 10:51:05 +0100 4 | Subject: [PATCH] PVE: fall back to open-iscsi initiatorname 5 | 6 | When no explicit option is given, try reading the initiator name from 7 | /etc/iscsi/initiatorname.iscsi and only use the generic fallback, i.e. 8 | iqn.2008-11.org.linux-kvmXXX, as a third alternative. 9 | 10 | This avoids the need to add an explicit option for vma and to explicitly set it 11 | for each call to qemu that deals with iSCSI disks, while still allowing to set 12 | the option if a different name is needed. 13 | 14 | According to RFC 3720, an initiator name is at most 223 bytes long, so the 15 | 4 KiB buffer is big enough, even if many whitespaces are used. 16 | 17 | Signed-off-by: Fabian Ebner 18 | Signed-off-by: Thomas Lamprecht 19 | --- 20 | block/iscsi.c | 30 ++++++++++++++++++++++++++++++ 21 | 1 file changed, 30 insertions(+) 22 | 23 | diff --git a/block/iscsi.c b/block/iscsi.c 24 | index 15b96ee880..5aa4b602b1 100644 25 | --- a/block/iscsi.c 26 | +++ b/block/iscsi.c 27 | @@ -1392,12 +1392,42 @@ static char *get_initiator_name(QemuOpts *opts) 28 | const char *name; 29 | char *iscsi_name; 30 | UuidInfo *uuid_info; 31 | + FILE *name_fh; 32 | 33 | name = qemu_opt_get(opts, "initiator-name"); 34 | if (name) { 35 | return g_strdup(name); 36 | } 37 | 38 | + name_fh = fopen("/etc/iscsi/initiatorname.iscsi", "r"); 39 | + if (name_fh) { 40 | + const char *key = "InitiatorName"; 41 | + char buffer[4096]; 42 | + char *line; 43 | + 44 | + while ((line = fgets(buffer, sizeof(buffer), name_fh))) { 45 | + line = g_strstrip(line); 46 | + if (!strncmp(line, key, strlen(key))) { 47 | + line = strchr(line, '='); 48 | + if (!line || strlen(line) == 1) { 49 | + continue; 50 | + } 51 | + line++; 52 | + g_strstrip(line); 53 | + if (!strlen(line)) { 54 | + continue; 55 | + } 56 | + name = line; 57 | + break; 58 | + } 59 | + } 60 | + fclose(name_fh); 61 | + 62 | + if (name) { 63 | + return g_strdup(name); 64 | + } 65 | + } 66 | + 67 | uuid_info = qmp_query_uuid(NULL); 68 | if (strcmp(uuid_info->UUID, UUID_NONE) == 0) { 69 | name = qemu_get_vm_name(); 70 | -------------------------------------------------------------------------------- /debian/patches/pve/0044-PVE-backup-get-device-info-allow-caller-to-specify-f.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Fiona Ebner 3 | Date: Thu, 3 Apr 2025 14:30:45 +0200 4 | Subject: [PATCH] PVE backup: get device info: allow caller to specify filter 5 | for which devices use fleecing 6 | 7 | For providing snapshot-access to external backup providers, EFI and 8 | TPM also need an associated fleecing image. The new caller will thus 9 | need a different filter. 10 | 11 | Signed-off-by: Fiona Ebner 12 | Reviewed-by: Wolfgang Bumiller 13 | --- 14 | pve-backup.c | 9 +++++---- 15 | 1 file changed, 5 insertions(+), 4 deletions(-) 16 | 17 | diff --git a/pve-backup.c b/pve-backup.c 18 | index 5f0ad5042f..7718065c63 100644 19 | --- a/pve-backup.c 20 | +++ b/pve-backup.c 21 | @@ -719,7 +719,7 @@ static void create_backup_jobs_bh(void *opaque) { 22 | /* 23 | * EFI disk and TPM state are small and it's just not worth setting up fleecing for them. 24 | */ 25 | -static bool device_uses_fleecing(const char *device_id) 26 | +static bool fleecing_no_efi_tpm(const char *device_id) 27 | { 28 | return strncmp(device_id, "drive-efidisk", 13) && strncmp(device_id, "drive-tpmstate", 14); 29 | } 30 | @@ -731,7 +731,7 @@ static bool device_uses_fleecing(const char *device_id) 31 | */ 32 | static GList coroutine_fn GRAPH_RDLOCK *get_device_info( 33 | const char *devlist, 34 | - bool fleecing, 35 | + bool (*device_uses_fleecing)(const char*), 36 | Error **errp) 37 | { 38 | gchar **devs = NULL; 39 | @@ -757,7 +757,7 @@ static GList coroutine_fn GRAPH_RDLOCK *get_device_info( 40 | di->bs = bs; 41 | di->device_name = g_strdup(bdrv_get_device_name(bs)); 42 | 43 | - if (fleecing && device_uses_fleecing(*d)) { 44 | + if (device_uses_fleecing && device_uses_fleecing(*d)) { 45 | g_autofree gchar *fleecing_devid = g_strconcat(*d, "-fleecing", NULL); 46 | BlockBackend *fleecing_blk = blk_by_name(fleecing_devid); 47 | if (!fleecing_blk) { 48 | @@ -924,7 +924,8 @@ UuidInfo coroutine_fn *qmp_backup( 49 | format = has_format ? format : BACKUP_FORMAT_VMA; 50 | 51 | bdrv_graph_co_rdlock(); 52 | - di_list = get_device_info(devlist, has_fleecing && fleecing, &local_err); 53 | + di_list = get_device_info(devlist, (has_fleecing && fleecing) ? fleecing_no_efi_tpm : NULL, 54 | + &local_err); 55 | bdrv_graph_co_rdunlock(); 56 | if (local_err) { 57 | error_propagate(errp, local_err); 58 | -------------------------------------------------------------------------------- /debian/patches/pve/0026-block-backup-move-bcs-bitmap-initialization-to-job-c.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Fabian Ebner 3 | Date: Wed, 2 Mar 2022 08:35:05 +0100 4 | Subject: [PATCH] block/backup: move bcs bitmap initialization to job creation 5 | 6 | For backing up the state of multiple disks from the same time, a job 7 | for each disk has to be created. It's convenient if the jobs don't 8 | have to be started at the same time and if operation of the VM can be 9 | resumed after job creation. This would lead to a window between job 10 | creation and running the job, where writes can happen. But no writes 11 | should happen between setting up the copy-before-write filter and 12 | setting up the block copy state bitmap, because then new writes would 13 | just pass through. 14 | 15 | Commit 06e0a9c16405c0a4c1eca33cf286cc04c42066a2 moved initalization of 16 | the bitmap to setting up the copy-before-write filter when sync_mode 17 | is not MIRROR_SYNC_MODE_BITMAP. Ensure that the bitmap is initialized 18 | upon job creation for the remaining case too, by moving the 19 | backup_init_bcs_bitmap call to backup_job_create. 20 | 21 | Signed-off-by: Fabian Ebner 22 | Signed-off-by: Thomas Lamprecht 23 | --- 24 | block/backup.c | 8 ++++---- 25 | 1 file changed, 4 insertions(+), 4 deletions(-) 26 | 27 | diff --git a/block/backup.c b/block/backup.c 28 | index d4713fa1cd..9189f64ebc 100644 29 | --- a/block/backup.c 30 | +++ b/block/backup.c 31 | @@ -237,8 +237,8 @@ static void backup_init_bcs_bitmap(BackupBlockJob *job) 32 | true); 33 | } else if (job->sync_mode == MIRROR_SYNC_MODE_TOP) { 34 | /* 35 | - * We can't hog the coroutine to initialize this thoroughly. 36 | - * Set a flag and resume work when we are able to yield safely. 37 | + * Initialization is costly here. Simply set a flag and let the 38 | + * backup_run coroutine resume work once it can yield safely. 39 | */ 40 | block_copy_set_skip_unallocated(job->bcs, true); 41 | } 42 | @@ -252,8 +252,6 @@ static int coroutine_fn backup_run(Job *job, Error **errp) 43 | BackupBlockJob *s = container_of(job, BackupBlockJob, common.job); 44 | int ret; 45 | 46 | - backup_init_bcs_bitmap(s); 47 | - 48 | if (s->sync_mode == MIRROR_SYNC_MODE_TOP) { 49 | int64_t offset = 0; 50 | int64_t count; 51 | @@ -503,6 +501,8 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, 52 | &error_abort); 53 | bdrv_graph_wrunlock(); 54 | 55 | + backup_init_bcs_bitmap(job); 56 | + 57 | return &job->common; 58 | 59 | error: 60 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | include /usr/share/dpkg/default.mk 2 | 3 | PACKAGE = pve-qemu-kvm 4 | 5 | SRCDIR := qemu 6 | BUILDDIR ?= $(PACKAGE)-$(DEB_VERSION_UPSTREAM) 7 | ORIG_SRC_TAR=$(PACKAGE)_$(DEB_VERSION_UPSTREAM).orig.tar.gz 8 | 9 | GITVERSION := $(shell git rev-parse HEAD) 10 | 11 | DSC=$(PACKAGE)_$(DEB_VERSION_UPSTREAM_REVISION).dsc 12 | DEB = $(PACKAGE)_$(DEB_VERSION_UPSTREAM_REVISION)_$(DEB_BUILD_ARCH).deb 13 | DEB_DBG = $(PACKAGE)-dbgsym_$(DEB_VERSION_UPSTREAM_REVISION)_$(DEB_BUILD_ARCH).deb 14 | DEBS = $(DEB) $(DEB_DBG) 15 | 16 | all: $(DEBS) 17 | 18 | .PHONY: submodule 19 | submodule: 20 | ifeq ($(shell test -f "$(SRCDIR)/configure" && echo 1 || echo 0), 0) 21 | git submodule update --init --recursive 22 | cd $(SRCDIR); meson subprojects download 23 | endif 24 | 25 | PC_BIOS_FW_PURGE_LIST_IN = \ 26 | hppa-firmware.img \ 27 | hppa-firmware64.img \ 28 | openbios-ppc \ 29 | openbios-sparc32 \ 30 | openbios-sparc64 \ 31 | palcode-clipper \ 32 | s390-ccw.img \ 33 | s390-netboot.img \ 34 | u-boot.e500 \ 35 | qemu_vga.ndrv \ 36 | slof.bin \ 37 | opensbi-riscv.*-generic-fw_dynamic.bin \ 38 | 39 | BLOB_PURGE_SED_CMDS = $(foreach FILE,$(PC_BIOS_FW_PURGE_LIST_IN),-e "/$(FILE)/d") 40 | BLOB_PURGE_FILTER = $(foreach FILE,$(PC_BIOS_FW_PURGE_LIST_IN),-e "$(FILE)") 41 | 42 | $(BUILDDIR): submodule 43 | # check if qemu/ was used for a build 44 | # if so, please run 'make distclean' in the submodule and try again 45 | test ! -f $(SRCDIR)/build/config.status 46 | rm -rf $@.tmp $@ 47 | cp -a $(SRCDIR) $@.tmp 48 | cp -a debian $@.tmp/debian 49 | rm -rf $@.tmp/roms/edk2 # packaged separately 50 | rm -rf $@.tmp/pc-bios/dtb 51 | find $@.tmp/pc-bios -type f | grep $(BLOB_PURGE_FILTER) | xargs rm -f 52 | sed -i $(BLOB_PURGE_SED_CMDS) $@.tmp/pc-bios/meson.build 53 | sed -i "/subdir('dtb')/d" $@.tmp/pc-bios/meson.build 54 | echo "git clone git://git.proxmox.com/git/pve-qemu.git\\ngit checkout $(GITVERSION)" > $@.tmp/debian/SOURCE 55 | mv $@.tmp $@ 56 | 57 | .PHONY: deb kvm 58 | deb kvm: $(DEBS) 59 | $(DEBS) &: $(BUILDDIR) 60 | cd $(BUILDDIR); dpkg-buildpackage -b -us -uc 61 | lintian $(DEBS) 62 | 63 | sbuild: $(DSC) 64 | sbuild $(DSC) 65 | 66 | $(ORIG_SRC_TAR): $(BUILDDIR) 67 | tar czf $(ORIG_SRC_TAR) --exclude="$(BUILDDIR)/debian" $(BUILDDIR) 68 | 69 | .PHONY: dsc 70 | dsc: 71 | rm -rf *.dsc $(BUILDDIR) 72 | $(MAKE) $(DSC) 73 | lintian $(DSC) 74 | 75 | $(DSC): $(ORIG_SRC_TAR) $(BUILDDIR) 76 | cd $(BUILDDIR); dpkg-buildpackage -S -us -uc -d 77 | 78 | .PHONY: upload 79 | upload: UPLOAD_DIST ?= $(DEB_DISTRIBUTION) 80 | upload: $(DEBS) 81 | tar cf - $(DEBS) | ssh repoman@repo.proxmox.com upload --product pve --dist $(UPLOAD_DIST) 82 | 83 | .PHONY: distclean clean 84 | distclean: clean 85 | clean: 86 | rm -rf $(PACKAGE)-[0-9]*/ $(PACKAGE)*.tar* *.deb *.dsc *.build *.buildinfo *.changes 87 | 88 | .PHONY: dinstall 89 | dinstall: $(DEBS) 90 | dpkg -i $(DEBS) 91 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: pve-qemu-kvm 2 | Section: admin 3 | Priority: optional 4 | Maintainer: Proxmox Support Team 5 | Build-Depends: debhelper-compat (= 13), 6 | check, 7 | libacl1-dev, 8 | libaio-dev, 9 | libattr1-dev, 10 | libcap-ng-dev, 11 | libcurl4-gnutls-dev, 12 | libepoxy-dev, 13 | libfdt-dev, 14 | libfuse3-dev, 15 | libgbm-dev, 16 | libgnutls28-dev, 17 | libiscsi-dev (>= 1.12.0), 18 | libjpeg-dev, 19 | libjson-perl, 20 | libnuma-dev, 21 | libpci-dev, 22 | libpixman-1-dev, 23 | libproxmox-backup-qemu0-dev (>= 1.3.0), 24 | librbd-dev (>= 0.48), 25 | libsdl1.2-dev, 26 | libseccomp-dev, 27 | libslirp-dev, 28 | libspice-protocol-dev (>= 0.12.14~), 29 | libspice-server-dev (>= 0.14.0~), 30 | libsystemd-dev, 31 | liburing-dev, 32 | libusb-1.0-0-dev (>= 1.0.17), 33 | libusbredirparser-dev (>= 0.6-2), 34 | libvirglrenderer-dev, 35 | libzstd-dev, 36 | meson, 37 | python3-minimal, 38 | python3-sphinx, 39 | python3-sphinx-rtd-theme, 40 | python3-venv, 41 | quilt, 42 | uuid-dev, 43 | xfslibs-dev, 44 | Standards-Version: 3.7.2 45 | 46 | Package: pve-qemu-kvm 47 | Architecture: any 48 | Depends: ceph-common (>= 0.48), 49 | fuse3, 50 | iproute2, 51 | libiscsi4 (>= 1.12.0) | libiscsi7, 52 | libjpeg62-turbo, 53 | libspice-server1 (>= 0.14.0~), 54 | libusb-1.0-0 (>= 1.0.17-1), 55 | libusbredirparser1 (>= 0.6-2), 56 | libuuid1, 57 | ${misc:Depends}, 58 | ${shlibs:Depends}, 59 | Recommends: numactl, 60 | Suggests: libgl1, 61 | Conflicts: kvm, 62 | pve-kvm, 63 | pve-qemu-kvm-2.6.18, 64 | qemu, 65 | qemu-kvm, 66 | qemu-system-arm, 67 | qemu-system-common, 68 | qemu-system-data, 69 | qemu-system-x86, 70 | qemu-utils, 71 | Provides: qemu-system-arm, qemu-system-x86, qemu-utils, 72 | Replaces: pve-kvm, 73 | pve-qemu-kvm-2.6.18, 74 | qemu-system-arm, 75 | qemu-system-x86, 76 | qemu-utils, 77 | Breaks: qemu-server (<= 8.0.6) 78 | Description: Full virtualization on x86 hardware 79 | Using KVM, one can run multiple virtual PCs, each running unmodified Linux or 80 | Windows images. Each virtual machine has private virtualized hardware: a 81 | network card, disk, graphics adapter, etc. 82 | -------------------------------------------------------------------------------- /debian/patches/extra/0007-vfio-only-check-region-info-cache-for-initial-region.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: John Levon 3 | Date: Tue, 14 Oct 2025 17:12:27 +0200 4 | Subject: [PATCH] vfio: only check region info cache for initial regions 5 | MIME-Version: 1.0 6 | Content-Type: text/plain; charset=UTF-8 7 | Content-Transfer-Encoding: 8bit 8 | 9 | It is semantically valid for a VFIO device to increase the number of 10 | regions after initialization. In this case, we'd attempt to check for 11 | cached region info past the size of the ->reginfo array. Check for the 12 | region index and skip the cache in these cases. 13 | 14 | This also works around some VGPU use cases which appear to be a bug, 15 | where VFIO_DEVICE_QUERY_GFX_PLANE returns a region index beyond the 16 | reported ->num_regions. 17 | 18 | Fixes: 95cdb024 ("vfio: add region info cache") 19 | Signed-off-by: John Levon 20 | Reviewed-by: Cédric Le Goater 21 | Reviewed-by: Alex Williamson 22 | Link: https://lore.kernel.org/qemu-devel/20251014151227.2298892-3-john.levon@nutanix.com 23 | Signed-off-by: Cédric Le Goater 24 | (cherry picked from commit 5bdcf2df64bf7e4be58524ef1442836b6d41282e 25 | from https://gitlab.com/legoater/qemu/-/tree/vfio-next) 26 | Signed-off-by: Fiona Ebner 27 | --- 28 | hw/vfio/device.c | 27 +++++++++++++++++++-------- 29 | 1 file changed, 19 insertions(+), 8 deletions(-) 30 | 31 | diff --git a/hw/vfio/device.c b/hw/vfio/device.c 32 | index 0b459c0f7c..7ebf41c95e 100644 33 | --- a/hw/vfio/device.c 34 | +++ b/hw/vfio/device.c 35 | @@ -205,10 +205,19 @@ int vfio_device_get_region_info(VFIODevice *vbasedev, int index, 36 | int fd = -1; 37 | int ret; 38 | 39 | - /* check cache */ 40 | - if (vbasedev->reginfo[index] != NULL) { 41 | - *info = vbasedev->reginfo[index]; 42 | - return 0; 43 | + /* 44 | + * We only set up the region info cache for the initial number of regions. 45 | + * 46 | + * Since a VFIO device may later increase the number of regions then use 47 | + * such regions with an index past ->num_initial_regions, don't attempt to 48 | + * use the info cache in those cases. 49 | + */ 50 | + if (index < vbasedev->num_initial_regions) { 51 | + /* check cache */ 52 | + if (vbasedev->reginfo[index] != NULL) { 53 | + *info = vbasedev->reginfo[index]; 54 | + return 0; 55 | + } 56 | } 57 | 58 | *info = g_malloc0(argsz); 59 | @@ -236,10 +245,12 @@ retry: 60 | goto retry; 61 | } 62 | 63 | - /* fill cache */ 64 | - vbasedev->reginfo[index] = *info; 65 | - if (vbasedev->region_fds != NULL) { 66 | - vbasedev->region_fds[index] = fd; 67 | + if (index < vbasedev->num_initial_regions) { 68 | + /* fill cache */ 69 | + vbasedev->reginfo[index] = *info; 70 | + if (vbasedev->region_fds != NULL) { 71 | + vbasedev->region_fds[index] = fd; 72 | + } 73 | } 74 | 75 | return 0; 76 | -------------------------------------------------------------------------------- /debian/patches/pve/0007-PVE-Up-glusterfs-allow-partial-reads.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Wolfgang Bumiller 3 | Date: Mon, 6 Apr 2020 12:16:38 +0200 4 | Subject: [PATCH] PVE: [Up] glusterfs: allow partial reads 5 | 6 | This should deal with qemu bug #1644754 until upstream 7 | decides which way to go. The general direction seems to be 8 | away from sector based block APIs and with that in mind, and 9 | when comparing to other network block backends (eg. nfs) 10 | treating partial reads as errors doesn't seem to make much 11 | sense. 12 | 13 | Signed-off-by: Thomas Lamprecht 14 | --- 15 | block/gluster.c | 10 +++++++++- 16 | 1 file changed, 9 insertions(+), 1 deletion(-) 17 | 18 | diff --git a/block/gluster.c b/block/gluster.c 19 | index d3f2e56229..de0fb4cf68 100644 20 | --- a/block/gluster.c 21 | +++ b/block/gluster.c 22 | @@ -57,6 +57,7 @@ typedef struct GlusterAIOCB { 23 | int ret; 24 | Coroutine *coroutine; 25 | AioContext *aio_context; 26 | + bool is_write; 27 | } GlusterAIOCB; 28 | 29 | typedef struct BDRVGlusterState { 30 | @@ -746,8 +747,10 @@ static void gluster_finish_aiocb(struct glfs_fd *fd, ssize_t ret, 31 | acb->ret = 0; /* Success */ 32 | } else if (ret < 0) { 33 | acb->ret = -errno; /* Read/Write failed */ 34 | + } else if (acb->is_write) { 35 | + acb->ret = -EIO; /* Partial write - fail it */ 36 | } else { 37 | - acb->ret = -EIO; /* Partial read/write - fail it */ 38 | + acb->ret = 0; /* Success */ 39 | } 40 | 41 | aio_co_schedule(acb->aio_context, acb->coroutine); 42 | @@ -1014,6 +1017,7 @@ static coroutine_fn int qemu_gluster_co_pwrite_zeroes(BlockDriverState *bs, 43 | acb.ret = 0; 44 | acb.coroutine = qemu_coroutine_self(); 45 | acb.aio_context = bdrv_get_aio_context(bs); 46 | + acb.is_write = true; 47 | 48 | ret = glfs_zerofill_async(s->fd, offset, bytes, gluster_finish_aiocb, &acb); 49 | if (ret < 0) { 50 | @@ -1194,9 +1198,11 @@ static coroutine_fn int qemu_gluster_co_rw(BlockDriverState *bs, 51 | acb.aio_context = bdrv_get_aio_context(bs); 52 | 53 | if (write) { 54 | + acb.is_write = true; 55 | ret = glfs_pwritev_async(s->fd, qiov->iov, qiov->niov, offset, 0, 56 | gluster_finish_aiocb, &acb); 57 | } else { 58 | + acb.is_write = false; 59 | ret = glfs_preadv_async(s->fd, qiov->iov, qiov->niov, offset, 0, 60 | gluster_finish_aiocb, &acb); 61 | } 62 | @@ -1259,6 +1265,7 @@ static coroutine_fn int qemu_gluster_co_flush_to_disk(BlockDriverState *bs) 63 | acb.ret = 0; 64 | acb.coroutine = qemu_coroutine_self(); 65 | acb.aio_context = bdrv_get_aio_context(bs); 66 | + acb.is_write = true; 67 | 68 | ret = glfs_fsync_async(s->fd, gluster_finish_aiocb, &acb); 69 | if (ret < 0) { 70 | @@ -1307,6 +1314,7 @@ static coroutine_fn int qemu_gluster_co_pdiscard(BlockDriverState *bs, 71 | acb.ret = 0; 72 | acb.coroutine = qemu_coroutine_self(); 73 | acb.aio_context = bdrv_get_aio_context(bs); 74 | + acb.is_write = true; 75 | 76 | ret = glfs_discard_async(s->fd, offset, bytes, gluster_finish_aiocb, &acb); 77 | if (ret < 0) { 78 | -------------------------------------------------------------------------------- /debian/patches/bitmap-mirror/0002-drive-mirror-add-support-for-conditional-and-always-.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: John Snow 3 | Date: Mon, 6 Apr 2020 12:17:04 +0200 4 | Subject: [PATCH] drive-mirror: add support for conditional and always bitmap 5 | sync modes 6 | MIME-Version: 1.0 7 | Content-Type: text/plain; charset=UTF-8 8 | Content-Transfer-Encoding: 8bit 9 | 10 | Teach mirror two new tricks for using bitmaps: 11 | 12 | Always: no matter what, we synchronize the copy_bitmap back to the 13 | sync_bitmap. In effect, this allows us resume a failed mirror at a later 14 | date. 15 | 16 | Conditional: On success only, we sync the bitmap. This is akin to 17 | incremental backup modes; we can use this bitmap to later refresh a 18 | successfully created mirror. 19 | 20 | Signed-off-by: Fabian Grünbichler 21 | Signed-off-by: Thomas Lamprecht 22 | --- 23 | block/mirror.c | 24 ++++++++++++++++++------ 24 | 1 file changed, 18 insertions(+), 6 deletions(-) 25 | 26 | diff --git a/block/mirror.c b/block/mirror.c 27 | index a184e91478..79b6f16d27 100644 28 | --- a/block/mirror.c 29 | +++ b/block/mirror.c 30 | @@ -734,8 +734,6 @@ static int mirror_exit_common(Job *job) 31 | bdrv_unfreeze_backing_chain(mirror_top_bs, target_bs); 32 | } 33 | 34 | - bdrv_release_dirty_bitmap(s->dirty_bitmap); 35 | - 36 | /* Make sure that the source BDS doesn't go away during bdrv_replace_node, 37 | * before we can call bdrv_drained_end */ 38 | bdrv_ref(src); 39 | @@ -851,6 +849,18 @@ static int mirror_exit_common(Job *job) 40 | bdrv_drained_end(target_bs); 41 | bdrv_unref(target_bs); 42 | 43 | + if (s->sync_bitmap) { 44 | + if (s->bitmap_mode == BITMAP_SYNC_MODE_ALWAYS || 45 | + (s->bitmap_mode == BITMAP_SYNC_MODE_ON_SUCCESS && 46 | + job->ret == 0 && ret == 0)) { 47 | + /* Success; synchronize copy back to sync. */ 48 | + bdrv_clear_dirty_bitmap(s->sync_bitmap, NULL); 49 | + bdrv_merge_dirty_bitmap(s->sync_bitmap, s->dirty_bitmap, 50 | + NULL, &error_abort); 51 | + } 52 | + } 53 | + bdrv_release_dirty_bitmap(s->dirty_bitmap); 54 | + 55 | bs_opaque->job = NULL; 56 | 57 | bdrv_drained_end(src); 58 | @@ -1877,10 +1887,6 @@ static BlockJob *mirror_start_job( 59 | " sync mode", 60 | MirrorSyncMode_str(sync_mode)); 61 | return NULL; 62 | - } else if (bitmap_mode != BITMAP_SYNC_MODE_NEVER) { 63 | - error_setg(errp, 64 | - "Bitmap Sync Mode '%s' is not supported by Mirror", 65 | - BitmapSyncMode_str(bitmap_mode)); 66 | } 67 | } else if (bitmap) { 68 | error_setg(errp, 69 | @@ -1897,6 +1903,12 @@ static BlockJob *mirror_start_job( 70 | return NULL; 71 | } 72 | granularity = bdrv_dirty_bitmap_granularity(bitmap); 73 | + 74 | + if (bitmap_mode != BITMAP_SYNC_MODE_NEVER) { 75 | + if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_DEFAULT, errp)) { 76 | + return NULL; 77 | + } 78 | + } 79 | } else if (granularity == 0) { 80 | granularity = bdrv_get_default_bitmap_granularity(target); 81 | } 82 | -------------------------------------------------------------------------------- /debian/patches/extra/0004-vfio-igd-Enable-quirks-when-IGD-is-not-the-primary-d.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Tomita Moeko 3 | Date: Thu, 14 Aug 2025 00:05:10 +0800 4 | Subject: [PATCH] vfio/igd: Enable quirks when IGD is not the primary display 5 | MIME-Version: 1.0 6 | Content-Type: text/plain; charset=UTF-8 7 | Content-Transfer-Encoding: 8bit 8 | 9 | Since linux 6.15, commit 41112160ca87 ("vfio/pci: match IGD devices in 10 | display controller class"), IGD related regions are also exposed when 11 | IGD is not primary display (device class is Display controller). 12 | 13 | Allow IGD quirks to be enabled in this configuration so that guests can 14 | have display output on IGD when it is not the primary display. 15 | 16 | Signed-off-by: Tomita Moeko 17 | Reviewed-by: Alex Williamson 18 | Link: https://lore.kernel.org/qemu-devel/20250813160510.23553-1-tomitamoeko@gmail.com 19 | Signed-off-by: Cédric Le Goater 20 | (cherry picked from commit 432ca3dfa3d57a7bf1e427576fcfca4ab0079a50) 21 | Signed-off-by: Fiona Ebner 22 | --- 23 | hw/vfio/igd.c | 7 ++++--- 24 | hw/vfio/pci.h | 5 +++++ 25 | 2 files changed, 9 insertions(+), 3 deletions(-) 26 | 27 | diff --git a/hw/vfio/igd.c b/hw/vfio/igd.c 28 | index ee0767b0b8..f116c40ccd 100644 29 | --- a/hw/vfio/igd.c 30 | +++ b/hw/vfio/igd.c 31 | @@ -460,7 +460,7 @@ void vfio_probe_igd_bar0_quirk(VFIOPCIDevice *vdev, int nr) 32 | int gen; 33 | 34 | if (!vfio_pci_is(vdev, PCI_VENDOR_ID_INTEL, PCI_ANY_ID) || 35 | - !vfio_is_vga(vdev) || nr != 0) { 36 | + !vfio_is_base_display(vdev) || nr != 0) { 37 | return; 38 | } 39 | 40 | @@ -518,7 +518,7 @@ static bool vfio_pci_igd_config_quirk(VFIOPCIDevice *vdev, Error **errp) 41 | Error *err = NULL; 42 | 43 | if (!vfio_pci_is(vdev, PCI_VENDOR_ID_INTEL, PCI_ANY_ID) || 44 | - !vfio_is_vga(vdev)) { 45 | + !vfio_is_base_display(vdev)) { 46 | return true; 47 | } 48 | 49 | @@ -534,12 +534,13 @@ static bool vfio_pci_igd_config_quirk(VFIOPCIDevice *vdev, Error **errp) 50 | /* 51 | * For backward compatibility, enable legacy mode when 52 | * - Device geneation is 6 to 9 (including both) 53 | - * - IGD claims VGA cycles on host 54 | + * - IGD exposes itself as VGA controller and claims VGA cycles on host 55 | * - Machine type is i440fx (pc_piix) 56 | * - IGD device is at guest BDF 00:02.0 57 | * - Not manually disabled by x-igd-legacy-mode=off 58 | */ 59 | if ((vdev->igd_legacy_mode != ON_OFF_AUTO_OFF) && 60 | + vfio_is_vga(vdev) && 61 | (gen >= 6 && gen <= 9) && 62 | !(gmch & IGD_GMCH_VGA_DISABLE) && 63 | !strcmp(MACHINE_GET_CLASS(qdev_get_machine())->family, "pc_piix") && 64 | diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h 65 | index 810a842f4a..923cf9c2f7 100644 66 | --- a/hw/vfio/pci.h 67 | +++ b/hw/vfio/pci.h 68 | @@ -203,6 +203,11 @@ static inline bool vfio_is_vga(VFIOPCIDevice *vdev) 69 | return (vdev->class_code >> 8) == PCI_CLASS_DISPLAY_VGA; 70 | } 71 | 72 | +static inline bool vfio_is_base_display(VFIOPCIDevice *vdev) 73 | +{ 74 | + return (vdev->class_code >> 16) == PCI_BASE_CLASS_DISPLAY; 75 | +} 76 | + 77 | /* MSI/MSI-X/INTx */ 78 | void vfio_pci_vector_init(VFIOPCIDevice *vdev, int nr); 79 | void vfio_pci_add_kvm_msi_virq(VFIOPCIDevice *vdev, VFIOMSIVector *vector, 80 | -------------------------------------------------------------------------------- /debian/patches/pve/0029-PVE-Add-sequential-job-transaction-support.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Stefan Reiter 3 | Date: Thu, 20 Aug 2020 14:31:59 +0200 4 | Subject: [PATCH] PVE: Add sequential job transaction support 5 | 6 | Signed-off-by: Stefan Reiter 7 | Signed-off-by: Thomas Lamprecht 8 | --- 9 | include/qemu/job.h | 12 ++++++++++++ 10 | job.c | 34 ++++++++++++++++++++++++++++++++++ 11 | 2 files changed, 46 insertions(+) 12 | 13 | diff --git a/include/qemu/job.h b/include/qemu/job.h 14 | index ead31578d3..2ed533de6f 100644 15 | --- a/include/qemu/job.h 16 | +++ b/include/qemu/job.h 17 | @@ -362,6 +362,18 @@ void job_unlock(void); 18 | */ 19 | JobTxn *job_txn_new(void); 20 | 21 | +/** 22 | + * Create a new transaction and set it to sequential mode, i.e. run all jobs 23 | + * one after the other instead of at the same time. 24 | + */ 25 | +JobTxn *job_txn_new_seq(void); 26 | + 27 | +/** 28 | + * Helper method to start the first job in a sequential transaction to kick it 29 | + * off. Other jobs will be run after this one completes. 30 | + */ 31 | +void job_txn_start_seq(JobTxn *txn); 32 | + 33 | /** 34 | * Release a reference that was previously acquired with job_txn_add_job or 35 | * job_txn_new. If it's the last reference to the object, it will be freed. 36 | diff --git a/job.c b/job.c 37 | index b981070ee8..f4646866ec 100644 38 | --- a/job.c 39 | +++ b/job.c 40 | @@ -94,6 +94,8 @@ struct JobTxn { 41 | 42 | /* Reference count */ 43 | int refcnt; 44 | + 45 | + bool sequential; 46 | }; 47 | 48 | void job_lock(void) 49 | @@ -119,6 +121,25 @@ JobTxn *job_txn_new(void) 50 | return txn; 51 | } 52 | 53 | +JobTxn *job_txn_new_seq(void) 54 | +{ 55 | + JobTxn *txn = job_txn_new(); 56 | + txn->sequential = true; 57 | + return txn; 58 | +} 59 | + 60 | +void job_txn_start_seq(JobTxn *txn) 61 | +{ 62 | + assert(txn->sequential); 63 | + assert(!txn->aborting); 64 | + 65 | + Job *first = QLIST_FIRST(&txn->jobs); 66 | + assert(first); 67 | + assert(first->status == JOB_STATUS_CREATED); 68 | + 69 | + job_start(first); 70 | +} 71 | + 72 | /* Called with job_mutex held. */ 73 | static void job_txn_ref_locked(JobTxn *txn) 74 | { 75 | @@ -1048,6 +1069,12 @@ static void job_completed_txn_success_locked(Job *job) 76 | */ 77 | QLIST_FOREACH(other_job, &txn->jobs, txn_list) { 78 | if (!job_is_completed_locked(other_job)) { 79 | + if (txn->sequential) { 80 | + job_unlock(); 81 | + /* Needs to be called without holding the job lock */ 82 | + job_start(other_job); 83 | + job_lock(); 84 | + } 85 | return; 86 | } 87 | assert(other_job->ret == 0); 88 | @@ -1259,6 +1286,13 @@ int job_finish_sync_locked(Job *job, 89 | return -EBUSY; 90 | } 91 | 92 | + /* in a sequential transaction jobs with status CREATED can appear at time 93 | + * of cancelling, these have not begun work so job_enter won't do anything, 94 | + * let's ensure they are marked as ABORTING if required */ 95 | + if (job->status == JOB_STATUS_CREATED && job->txn->sequential) { 96 | + job_update_rc_locked(job); 97 | + } 98 | + 99 | job_unlock(); 100 | AIO_WAIT_WHILE_UNLOCKED(job->aio_context, 101 | (job_enter(job), !job_is_completed(job))); 102 | -------------------------------------------------------------------------------- /debian/patches/pve/0042-PVE-backup-factor-out-helper-to-initialize-backup-st.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Fiona Ebner 3 | Date: Thu, 3 Apr 2025 14:30:43 +0200 4 | Subject: [PATCH] PVE backup: factor out helper to initialize backup state stat 5 | struct 6 | 7 | Suggested-by: Wolfgang Bumiller 8 | Signed-off-by: Fiona Ebner 9 | Reviewed-by: Wolfgang Bumiller 10 | --- 11 | pve-backup.c | 62 ++++++++++++++++++++++++++++++++-------------------- 12 | 1 file changed, 38 insertions(+), 24 deletions(-) 13 | 14 | diff --git a/pve-backup.c b/pve-backup.c 15 | index 3e0d1ffc5c..cc71279518 100644 16 | --- a/pve-backup.c 17 | +++ b/pve-backup.c 18 | @@ -828,6 +828,43 @@ static void clear_backup_state_bitmap_list(void) { 19 | } 20 | } 21 | 22 | +/* 23 | + * Initializes most of the backup state 'stat' struct. Note that 'reused' and 24 | + * 'bitmap_list' are not changed by this function and need to be handled by 25 | + * the caller. In particular, 'reused' needs to be set before calling this 26 | + * function. 27 | + * 28 | + * To be called with the backup_state.stat mutex held. 29 | + */ 30 | +static void initialize_backup_state_stat( 31 | + const char *backup_file, 32 | + uuid_t uuid, 33 | + size_t total) 34 | +{ 35 | + if (backup_state.stat.error) { 36 | + error_free(backup_state.stat.error); 37 | + backup_state.stat.error = NULL; 38 | + } 39 | + 40 | + backup_state.stat.start_time = time(NULL); 41 | + backup_state.stat.end_time = 0; 42 | + 43 | + if (backup_state.stat.backup_file) { 44 | + g_free(backup_state.stat.backup_file); 45 | + } 46 | + backup_state.stat.backup_file = g_strdup(backup_file); 47 | + 48 | + uuid_copy(backup_state.stat.uuid, uuid); 49 | + uuid_unparse_lower(uuid, backup_state.stat.uuid_str); 50 | + 51 | + backup_state.stat.total = total; 52 | + backup_state.stat.dirty = total - backup_state.stat.reused; 53 | + backup_state.stat.transferred = 0; 54 | + backup_state.stat.zero_bytes = 0; 55 | + backup_state.stat.finishing = false; 56 | + backup_state.stat.starting = true; 57 | +} 58 | + 59 | UuidInfo coroutine_fn *qmp_backup( 60 | const char *backup_file, 61 | const char *password, 62 | @@ -1070,32 +1107,9 @@ UuidInfo coroutine_fn *qmp_backup( 63 | } 64 | } 65 | /* initialize global backup_state now */ 66 | - /* note: 'reused' and 'bitmap_list' are initialized earlier */ 67 | - 68 | - if (backup_state.stat.error) { 69 | - error_free(backup_state.stat.error); 70 | - backup_state.stat.error = NULL; 71 | - } 72 | - 73 | - backup_state.stat.start_time = time(NULL); 74 | - backup_state.stat.end_time = 0; 75 | - 76 | - if (backup_state.stat.backup_file) { 77 | - g_free(backup_state.stat.backup_file); 78 | - } 79 | - backup_state.stat.backup_file = g_strdup(backup_file); 80 | - 81 | - uuid_copy(backup_state.stat.uuid, uuid); 82 | - uuid_unparse_lower(uuid, backup_state.stat.uuid_str); 83 | + initialize_backup_state_stat(backup_file, uuid, total); 84 | char *uuid_str = g_strdup(backup_state.stat.uuid_str); 85 | 86 | - backup_state.stat.total = total; 87 | - backup_state.stat.dirty = total - backup_state.stat.reused; 88 | - backup_state.stat.transferred = 0; 89 | - backup_state.stat.zero_bytes = 0; 90 | - backup_state.stat.finishing = false; 91 | - backup_state.stat.starting = true; 92 | - 93 | qemu_mutex_unlock(&backup_state.stat.lock); 94 | 95 | backup_state.speed = (has_speed && speed > 0) ? speed : 0; 96 | -------------------------------------------------------------------------------- /debian/patches/extra/0005-hw-scsi-avoid-deadlock-upon-TMF-request-cancelling-w.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Fiona Ebner 3 | Date: Fri, 17 Oct 2025 11:43:30 +0200 4 | Subject: [PATCH] hw/scsi: avoid deadlock upon TMF request cancelling with 5 | VirtIO 6 | 7 | When scsi_req_dequeue() is reached via 8 | scsi_req_cancel_async() 9 | virtio_scsi_tmf_cancel_req() 10 | virtio_scsi_do_tmf_aio_context(), 11 | there is a deadlock when trying to acquire the SCSI device's requests 12 | lock, because it was already acquired in 13 | virtio_scsi_do_tmf_aio_context(). 14 | 15 | In particular, the issue happens with a FreeBSD guest (13, 14, 15, 16 | maybe more), when it cancels SCSI requests, because of timeout. 17 | 18 | This is a regression caused by commit da6eebb33b ("virtio-scsi: 19 | perform TMFs in appropriate AioContexts") and the introduction of the 20 | requests_lock earlier. 21 | 22 | To fix the issue, only cancel the requests after releasing the 23 | requests_lock. For this, the SCSI device's requests are iterated while 24 | holding the requests_lock and the requests to be cancelled are 25 | collected in a list. Then, the collected requests are cancelled 26 | one by one while not holding the requests_lock. This is safe, because 27 | only requests from the current AioContext are collected and acted 28 | upon. 29 | 30 | Originally reported by Proxmox VE users: 31 | https://bugzilla.proxmox.com/show_bug.cgi?id=6810 32 | https://forum.proxmox.com/threads/173914/ 33 | 34 | Fixes: da6eebb33b ("virtio-scsi: perform TMFs in appropriate AioContexts") 35 | Suggested-by: Stefan Hajnoczi 36 | Signed-off-by: Fiona Ebner 37 | Message-id: 20251017094518.328905-1-f.ebner@proxmox.com 38 | [Changed g_list_append() to g_list_prepend() to avoid traversing the 39 | list each time. 40 | --Stefan] 41 | Signed-off-by: Stefan Hajnoczi 42 | (cherry picked from commit 7d80d6d82db4c73e335f9e738d7a5778124df35e 43 | from https://gitlab.com/stefanha/qemu/-/tree/block) 44 | Signed-off-by: Fiona Ebner 45 | --- 46 | hw/scsi/virtio-scsi.c | 14 +++++++++++++- 47 | 1 file changed, 13 insertions(+), 1 deletion(-) 48 | 49 | diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c 50 | index 34ae14f7bf..3b635053b5 100644 51 | --- a/hw/scsi/virtio-scsi.c 52 | +++ b/hw/scsi/virtio-scsi.c 53 | @@ -343,6 +343,7 @@ static void virtio_scsi_do_tmf_aio_context(void *opaque) 54 | SCSIDevice *d = virtio_scsi_device_get(s, tmf->req.tmf.lun); 55 | SCSIRequest *r; 56 | bool match_tag; 57 | + g_autoptr(GList) reqs = NULL; 58 | 59 | if (!d) { 60 | tmf->resp.tmf.response = VIRTIO_SCSI_S_BAD_TARGET; 61 | @@ -378,10 +379,21 @@ static void virtio_scsi_do_tmf_aio_context(void *opaque) 62 | if (match_tag && cmd_req->req.cmd.tag != tmf->req.tmf.tag) { 63 | continue; 64 | } 65 | - virtio_scsi_tmf_cancel_req(tmf, r); 66 | + /* 67 | + * Cannot cancel directly, because scsi_req_dequeue() would deadlock 68 | + * when attempting to acquire the request_lock a second time. Taking 69 | + * a reference here is paired with an unref after cancelling below. 70 | + */ 71 | + scsi_req_ref(r); 72 | + reqs = g_list_prepend(reqs, r); 73 | } 74 | } 75 | 76 | + for (GList *elem = g_list_first(reqs); elem; elem = g_list_next(elem)) { 77 | + virtio_scsi_tmf_cancel_req(tmf, elem->data); 78 | + scsi_req_unref(elem->data); 79 | + } 80 | + 81 | /* Incremented by virtio_scsi_do_tmf() */ 82 | virtio_scsi_tmf_dec_remaining(tmf); 83 | 84 | -------------------------------------------------------------------------------- /debian/patches/extra/0010-block-use-pwrite_zeroes_alignment-when-writing-first.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Stefan Hajnoczi 3 | Date: Tue, 7 Oct 2025 10:16:59 -0400 4 | Subject: [PATCH] block: use pwrite_zeroes_alignment when writing first sector 5 | 6 | Since commit 5634622bcb33 ("file-posix: allow BLKZEROOUT with -t 7 | writeback"), qemu-img create errors out on a Linux loop block device 8 | with a 4 KB sector size: 9 | 10 | # dd if=/dev/zero of=blockfile bs=1M count=1024 11 | # losetup --sector-size 4096 /dev/loop0 blockfile 12 | # qemu-img create -f raw /dev/loop0 1G 13 | Formatting '/dev/loop0', fmt=raw size=1073741824 14 | qemu-img: /dev/loop0: Failed to clear the new image's first sector: Invalid argument 15 | 16 | Use the pwrite_zeroes_alignment block limit to avoid misaligned 17 | fallocate(2) or ioctl(BLKZEROOUT) in the block/file-posix.c block 18 | driver. 19 | 20 | Fixes: 5634622bcb33 ("file-posix: allow BLKZEROOUT with -t writeback") 21 | Reported-by: Jean-Louis Dupond 22 | Buglink: https://gitlab.com/qemu-project/qemu/-/issues/3127 23 | Reviewed-by: Vladimir Sementsov-Ogievskiy 24 | Signed-off-by: Stefan Hajnoczi 25 | Link: https://lore.kernel.org/20251007141700.71891-3-stefanha@redhat.com 26 | [FE: picked from qemu-devel] 27 | Signed-off-by: Fiona Ebner 28 | --- 29 | block.c | 3 ++- 30 | block/block-backend.c | 11 +++++++++++ 31 | include/system/block-backend-io.h | 1 + 32 | 3 files changed, 14 insertions(+), 1 deletion(-) 33 | 34 | diff --git a/block.c b/block.c 35 | index 8848e9a7ed..be77e03904 100644 36 | --- a/block.c 37 | +++ b/block.c 38 | @@ -606,12 +606,13 @@ create_file_fallback_zero_first_sector(BlockBackend *blk, 39 | int64_t current_size, 40 | Error **errp) 41 | { 42 | + uint32_t alignment = blk_get_pwrite_zeroes_alignment(blk); 43 | int64_t bytes_to_clear; 44 | int ret; 45 | 46 | GLOBAL_STATE_CODE(); 47 | 48 | - bytes_to_clear = MIN(current_size, BDRV_SECTOR_SIZE); 49 | + bytes_to_clear = MIN(current_size, MAX(BDRV_SECTOR_SIZE, alignment)); 50 | if (bytes_to_clear) { 51 | ret = blk_co_pwrite_zeroes(blk, 0, bytes_to_clear, BDRV_REQ_MAY_UNMAP); 52 | if (ret < 0) { 53 | diff --git a/block/block-backend.c b/block/block-backend.c 54 | index f8d6ba65c1..239d6eca37 100644 55 | --- a/block/block-backend.c 56 | +++ b/block/block-backend.c 57 | @@ -2305,6 +2305,17 @@ uint32_t blk_get_request_alignment(BlockBackend *blk) 58 | return bs ? bs->bl.request_alignment : BDRV_SECTOR_SIZE; 59 | } 60 | 61 | +/* Returns the optimal write zeroes alignment, in bytes; guaranteed nonzero */ 62 | +uint32_t blk_get_pwrite_zeroes_alignment(BlockBackend *blk) 63 | +{ 64 | + BlockDriverState *bs = blk_bs(blk); 65 | + IO_CODE(); 66 | + if (!bs) { 67 | + return BDRV_SECTOR_SIZE; 68 | + } 69 | + return bs->bl.pwrite_zeroes_alignment ?: bs->bl.request_alignment; 70 | +} 71 | + 72 | /* Returns the maximum hardware transfer length, in bytes; guaranteed nonzero */ 73 | uint64_t blk_get_max_hw_transfer(BlockBackend *blk) 74 | { 75 | diff --git a/include/system/block-backend-io.h b/include/system/block-backend-io.h 76 | index ba8dfcc7d0..6d5ac476fc 100644 77 | --- a/include/system/block-backend-io.h 78 | +++ b/include/system/block-backend-io.h 79 | @@ -116,6 +116,7 @@ BlockAIOCB *blk_abort_aio_request(BlockBackend *blk, 80 | void *opaque, int ret); 81 | 82 | uint32_t blk_get_request_alignment(BlockBackend *blk); 83 | +uint32_t blk_get_pwrite_zeroes_alignment(BlockBackend *blk); 84 | uint32_t blk_get_max_transfer(BlockBackend *blk); 85 | uint64_t blk_get_max_hw_transfer(BlockBackend *blk); 86 | 87 | -------------------------------------------------------------------------------- /debian/patches/pve/0010-PVE-Up-qemu-img-dd-add-isize-parameter.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Wolfgang Bumiller 3 | Date: Mon, 6 Apr 2020 12:16:41 +0200 4 | Subject: [PATCH] PVE: [Up] qemu-img dd: add isize parameter 5 | 6 | for writing small images from stdin to bigger ones 7 | 8 | In order to distinguish between an actually unexpected and 9 | an expected end of input. 10 | 11 | Signed-off-by: Wolfgang Bumiller 12 | Signed-off-by: Thomas Lamprecht 13 | [FE: rebase for 10.1.0] 14 | Signed-off-by: Fiona Ebner 15 | --- 16 | qemu-img.c | 28 +++++++++++++++++++++++++--- 17 | 1 file changed, 25 insertions(+), 3 deletions(-) 18 | 19 | diff --git a/qemu-img.c b/qemu-img.c 20 | index 0a0ca0cec7..89ef74ae07 100644 21 | --- a/qemu-img.c 22 | +++ b/qemu-img.c 23 | @@ -5254,11 +5254,13 @@ static int img_bitmap(const img_cmd_t *ccmd, int argc, char **argv) 24 | #define C_OF 010 25 | #define C_SKIP 020 26 | #define C_OSIZE 040 27 | +#define C_ISIZE 0100 28 | 29 | struct DdInfo { 30 | unsigned int flags; 31 | int64_t count; 32 | int64_t osize; 33 | + int64_t isize; 34 | }; 35 | 36 | struct DdIo { 37 | @@ -5347,6 +5349,19 @@ static int img_dd_osize(const char *arg, 38 | return 0; 39 | } 40 | 41 | +static int img_dd_isize(const char *arg, 42 | + struct DdIo *in, struct DdIo *out, 43 | + struct DdInfo *dd) 44 | +{ 45 | + dd->isize = cvtnum("isize", arg, true); 46 | + 47 | + if (dd->isize < 0) { 48 | + return 1; 49 | + } 50 | + 51 | + return 0; 52 | +} 53 | + 54 | static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) 55 | { 56 | int ret = 0; 57 | @@ -5361,12 +5376,14 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) 58 | int c, i; 59 | const char *out_fmt = "raw"; 60 | const char *fmt = NULL; 61 | - int64_t size = 0; 62 | + int64_t size = 0, readsize = 0; 63 | int64_t out_pos, in_pos; 64 | bool force_share = false; 65 | struct DdInfo dd = { 66 | .flags = 0, 67 | .count = 0, 68 | + .osize = 0, 69 | + .isize = -1, 70 | }; 71 | struct DdIo in = { 72 | .bsz = 512, /* Block size is by default 512 bytes */ 73 | @@ -5388,6 +5405,7 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) 74 | { "of", img_dd_of, C_OF }, 75 | { "skip", img_dd_skip, C_SKIP }, 76 | { "osize", img_dd_osize, C_OSIZE }, 77 | + { "isize", img_dd_isize, C_ISIZE }, 78 | { NULL, NULL, 0 } 79 | }; 80 | const struct option long_options[] = { 81 | @@ -5606,9 +5624,10 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) 82 | 83 | in.buf = g_new(uint8_t, in.bsz); 84 | 85 | - for (out_pos = 0; in_pos < size; ) { 86 | + readsize = (dd.isize > 0) ? dd.isize : size; 87 | + for (out_pos = 0; in_pos < readsize; ) { 88 | int in_ret, out_ret; 89 | - int bytes = (in_pos + in.bsz > size) ? size - in_pos : in.bsz; 90 | + int bytes = (in_pos + in.bsz > readsize) ? readsize - in_pos : in.bsz; 91 | if (blk1) { 92 | in_ret = blk_pread(blk1, in_pos, bytes, in.buf, 0); 93 | if (in_ret == 0) { 94 | @@ -5617,6 +5636,9 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) 95 | } else { 96 | in_ret = read(STDIN_FILENO, in.buf, bytes); 97 | if (in_ret == 0) { 98 | + if (dd.isize == 0) { 99 | + goto out; 100 | + } 101 | /* early EOF is considered an error */ 102 | error_report("Input ended unexpectedly"); 103 | ret = -1; 104 | -------------------------------------------------------------------------------- /debian/patches/series: -------------------------------------------------------------------------------- 1 | extra/0001-monitor-qmp-fix-race-with-clients-disconnecting-earl.patch 2 | extra/0002-ide-avoid-potential-deadlock-when-draining-during-tr.patch 3 | extra/0003-tcg-arm-Fix-tgen_deposit.patch 4 | extra/0004-vfio-igd-Enable-quirks-when-IGD-is-not-the-primary-d.patch 5 | extra/0005-hw-scsi-avoid-deadlock-upon-TMF-request-cancelling-w.patch 6 | extra/0006-vfio-rename-field-to-num_initial_regions.patch 7 | extra/0007-vfio-only-check-region-info-cache-for-initial-region.patch 8 | extra/0008-ui-vdagent-fix-windows-agent-regression.patch 9 | extra/0009-file-posix-populate-pwrite_zeroes_alignment.patch 10 | extra/0010-block-use-pwrite_zeroes_alignment-when-writing-first.patch 11 | extra/0011-block-io_uring-avoid-potentially-getting-stuck-after.patch 12 | bitmap-mirror/0001-drive-mirror-add-support-for-sync-bitmap-mode-never.patch 13 | bitmap-mirror/0002-drive-mirror-add-support-for-conditional-and-always-.patch 14 | bitmap-mirror/0003-mirror-add-check-for-bitmap-mode-without-bitmap.patch 15 | bitmap-mirror/0004-mirror-switch-to-bdrv_dirty_bitmap_merge_internal.patch 16 | bitmap-mirror/0005-iotests-add-test-for-bitmap-mirror.patch 17 | bitmap-mirror/0006-mirror-move-some-checks-to-qmp.patch 18 | pve/0001-PVE-Config-block-file-change-locking-default-to-off.patch 19 | pve/0002-PVE-Config-Adjust-network-script-path-to-etc-kvm.patch 20 | pve/0003-PVE-Config-set-the-CPU-model-to-kvm64-32-instead-of-.patch 21 | pve/0004-PVE-Config-ui-spice-default-to-pve-certificates.patch 22 | pve/0005-PVE-Config-glusterfs-no-default-logfile-if-daemonize.patch 23 | pve/0006-PVE-Config-rbd-block-rbd-disable-rbd_cache_writethro.patch 24 | pve/0007-PVE-Up-glusterfs-allow-partial-reads.patch 25 | pve/0008-PVE-Up-qemu-img-return-success-on-info-without-snaps.patch 26 | pve/0009-PVE-Up-qemu-img-dd-add-osize-and-read-from-to-stdin-.patch 27 | pve/0010-PVE-Up-qemu-img-dd-add-isize-parameter.patch 28 | pve/0011-PVE-Up-qemu-img-dd-add-n-skip_create.patch 29 | pve/0012-qemu-img-dd-add-l-option-for-loading-a-snapshot.patch 30 | pve/0013-PVE-virtio-balloon-improve-query-balloon.patch 31 | pve/0014-PVE-qapi-modify-query-machines.patch 32 | pve/0015-PVE-qapi-modify-spice-query.patch 33 | pve/0016-PVE-add-IOChannel-implementation-for-savevm-async.patch 34 | pve/0017-PVE-add-savevm-async-for-background-state-snapshots.patch 35 | pve/0018-PVE-add-optional-buffer-size-to-QEMUFile.patch 36 | pve/0019-PVE-block-add-the-zeroinit-block-driver-filter.patch 37 | pve/0020-PVE-Add-dummy-id-command-line-parameter.patch 38 | pve/0021-PVE-Config-Revert-target-i386-disable-LINT0-after-re.patch 39 | pve/0022-PVE-Up-Config-file-posix-make-locking-optiono-on-cre.patch 40 | pve/0023-PVE-monitor-disable-oob-capability.patch 41 | pve/0024-PVE-Compat-4.0-used-balloon-qemu-4-0-config-size-fal.patch 42 | pve/0025-PVE-Allow-version-code-in-machine-type.patch 43 | pve/0026-block-backup-move-bcs-bitmap-initialization-to-job-c.patch 44 | pve/0027-PVE-Backup-add-vma-backup-format-code.patch 45 | pve/0028-PVE-Backup-add-backup-dump-block-driver.patch 46 | pve/0029-PVE-Add-sequential-job-transaction-support.patch 47 | pve/0030-PVE-Backup-Proxmox-backup-patches-for-QEMU.patch 48 | pve/0031-PVE-Backup-pbs-restore-new-command-to-restore-from-p.patch 49 | pve/0032-PVE-Add-PBS-block-driver-to-map-backup-archives-into.patch 50 | pve/0033-PVE-redirect-stderr-to-journal-when-daemonized.patch 51 | pve/0034-PVE-Migrate-dirty-bitmap-state-via-savevm.patch 52 | pve/0035-migration-block-dirty-bitmap-migrate-other-bitmaps-e.patch 53 | pve/0036-PVE-fall-back-to-open-iscsi-initiatorname.patch 54 | pve/0037-PVE-block-stream-increase-chunk-size.patch 55 | pve/0038-block-add-alloc-track-driver.patch 56 | pve/0039-PVE-backup-add-fleecing-option.patch 57 | pve/0040-adapt-machine-version-deprecation-for-Proxmox-VE.patch 58 | pve/0041-PVE-backup-factor-out-helper-to-clear-backup-state-s.patch 59 | pve/0042-PVE-backup-factor-out-helper-to-initialize-backup-st.patch 60 | pve/0043-PVE-backup-add-target-ID-in-backup-state.patch 61 | pve/0044-PVE-backup-get-device-info-allow-caller-to-specify-f.patch 62 | pve/0045-PVE-backup-implement-backup-access-setup-and-teardow.patch 63 | pve/0046-PVE-backup-prepare-for-the-switch-to-using-blockdev-.patch 64 | pve/0047-savevm-async-reuse-migration-blocker-check-for-snaps.patch 65 | -------------------------------------------------------------------------------- /vma_spec.txt: -------------------------------------------------------------------------------- 1 | = Virtual Machine Archive format (VMA) = 2 | 3 | This format contains a header which includes the VM configuration as 4 | binary blobs, and a list of devices (dev_id, name). 5 | 6 | The actual VM image data is stored inside extents. An extent contains 7 | up to 64 clusters, and start with a 512 byte header containing 8 | additional information for those clusters. 9 | 10 | We use a cluster size of 65536, and use 8 bytes for each 11 | cluster in the header to store the following information: 12 | 13 | * 1 byte dev_id (to identity the drive) 14 | * 1 byte not used (reserved) 15 | * 2 bytes zero indicator (mark zero regions (16x4096)) 16 | * 4 bytes cluster number 17 | 18 | We only store non-zero blocks (such block is 4096 bytes). 19 | 20 | Each archive is marked with a uuid. The archive header and all 21 | extent headers includes that uuid and a MD5 checksum (over header 22 | data). 23 | 24 | All numbers in VMA archive are stored in Big Endian byte order. 25 | 26 | == VMA Header == 27 | 28 | Byte 0 - 3: magic 29 | VMA magic string ("VMA\x00") 30 | 31 | 4 - 7: version 32 | Version number (valid value is 1) 33 | 34 | 8 - 23: uuid 35 | Unique ID, Same uuid is used to mark extents. 36 | 37 | 24 - 31: ctime 38 | Backup time stamp (seconds since epoch) 39 | 40 | 32 - 47: md5sum 41 | Header checksum (from byte 0 to header_size). This field 42 | is filled with zero to generate the checksum. 43 | 44 | 48 - 51: blob_buffer_offset 45 | Start of blob buffer (multiple of 512) 46 | 47 | 52 - 55: blob_buffer_size 48 | Size of blob buffer (multiple of 512) 49 | 50 | 56 - 59: header_size 51 | Overall size of this header (multiple of 512) 52 | 53 | 60 - 2043: reserved 54 | 55 | 2044 - 3067: uint32_t config_names[256] 56 | Offsets into blob_buffer table 57 | 58 | 3068 - 4091: uint32_t config_data[256] 59 | Offsets into blob_buffer table 60 | 61 | 4092 - 4095: reserved 62 | 63 | 4096 - 12287: VmaDeviceInfoHeader dev_info[256] 64 | The offset in this table is used as 'dev_id' inside 65 | the data streams. 66 | 67 | 12288 - header_size: Blob buffer 68 | 69 | 70 | === Devive Info Header (VmaDeviceInfoHeader) === 71 | 72 | This is use to store details about the contained disk images. 73 | 74 | Byte 0 - 3: devive name (offsets into blob_buffer table) 75 | 76 | 4 - 7: reserved 77 | 78 | 8 - 15: device size in bytes 79 | 80 | 16 - 31: reserved 81 | 82 | Note: Devive name 'vmstate' is reserved to store VM RAM state. 83 | 84 | === Blob buffer === 85 | 86 | The blob buffer is used to store both configuration file names and 87 | configuration data. 88 | 89 | This region contain a list of binary data blobs. Each blob starts with 90 | a 2 byte size field, followed by the actual data. 91 | 92 | == Image Data Streams == 93 | 94 | The VMA header is followed by the image data stream. Image data is grouped 95 | with extents, which contains up to 59 clusters from different images. 96 | 97 | === VMA Extent Header === 98 | 99 | Byte 0 - 3: magic 100 | VMA extent magic string ("VMAE") 101 | 102 | 4 - 5: reserved 103 | 104 | 6 - 7: block_count 105 | Overall number of contained 4K block 106 | 107 | 8 - 23: uuid 108 | Unique ID, Same uuid as used in the VMA header. 109 | 110 | 24 - 39: md5sum 111 | Header checksum (from byte 0 to header_size). This field 112 | is filled with zero to generate the checksum. 113 | 114 | 40 - 511: blockinfo[59] 115 | 116 | 117 | Each 'blockinfo' (8 bytes) give further details about contained clusters: 118 | 119 | Byte 0 - 1: mask 120 | Bitmap used to indicate non-zero 4K blocks inside the 121 | cluster. 122 | 123 | 2: reserved 124 | 125 | 3: dev_id 126 | Device ID (offset into dev_info table) 127 | 128 | 4 - 7: cluster_num 129 | 130 | The extend header if followed by the actual cluster data, where we only 131 | store non-zero 4K blocks. 132 | 133 | -------------------------------------------------------------------------------- /debian/patches/extra/0002-ide-avoid-potential-deadlock-when-draining-during-tr.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Fiona Ebner 3 | Date: Tue, 7 Mar 2023 15:03:02 +0100 4 | Subject: [PATCH] ide: avoid potential deadlock when draining during trim 5 | MIME-Version: 1.0 6 | Content-Type: text/plain; charset=UTF-8 7 | Content-Transfer-Encoding: 8bit 8 | 9 | The deadlock can happen as follows: 10 | 1. ide_issue_trim is called, and increments the in_flight counter. 11 | 2. ide_issue_trim_cb calls blk_aio_pdiscard. 12 | 3. Somebody else starts draining (e.g. backup to insert the cbw node). 13 | 4. ide_issue_trim_cb is called as the completion callback for 14 | blk_aio_pdiscard. 15 | 5. ide_issue_trim_cb issues yet another blk_aio_pdiscard request. 16 | 6. The request is added to the wait queue via blk_wait_while_drained, 17 | because draining has been started. 18 | 7. Nobody ever decrements the in_flight counter and draining can't 19 | finish. This would be done by ide_trim_bh_cb, which is called after 20 | ide_issue_trim_cb has issued its last request, but 21 | ide_issue_trim_cb is not called anymore, because it's the 22 | completion callback of blk_aio_pdiscard, which waits on draining. 23 | 24 | Quoting Hanna Czenczek: 25 | > The point of 7e5cdb345f was that we need any in-flight count to 26 | > accompany a set s->bus->dma->aiocb. While blk_aio_pdiscard() is 27 | > happening, we don’t necessarily need another count. But we do need 28 | > it while there is no blk_aio_pdiscard(). 29 | > ide_issue_trim_cb() returns in two cases (and, recursively through 30 | > its callers, leaves s->bus->dma->aiocb set): 31 | > 1. After calling blk_aio_pdiscard(), which will keep an in-flight 32 | > count, 33 | > 2. After calling replay_bh_schedule_event() (i.e. 34 | > qemu_bh_schedule()), which does not keep an in-flight count. 35 | 36 | Thus, even after moving the blk_inc_in_flight to above the 37 | replay_bh_schedule_event call, the invariant "ide_issue_trim_cb 38 | returns with an accompanying in-flight count" is still satisfied. 39 | 40 | However, the issue 7e5cdb345f fixed for canceling resurfaces, because 41 | ide_cancel_dma_sync assumes that it just needs to drain once. But now 42 | the in_flight count is not consistently > 0 during the trim operation. 43 | So, change it to drain until !s->bus->dma->aiocb, which means that the 44 | operation finished (s->bus->dma->aiocb is cleared by ide_set_inactive 45 | via the ide_dma_cb when the end of the transfer is reached). 46 | 47 | Discussion here: 48 | https://lists.nongnu.org/archive/html/qemu-devel/2023-03/msg02506.html 49 | 50 | Fixes: 7e5cdb345f ("ide: Increment BB in-flight counter for TRIM BH") 51 | Suggested-by: Hanna Czenczek 52 | Signed-off-by: Fiona Ebner 53 | --- 54 | hw/ide/core.c | 12 ++++++------ 55 | 1 file changed, 6 insertions(+), 6 deletions(-) 56 | 57 | diff --git a/hw/ide/core.c b/hw/ide/core.c 58 | index b14983ec54..41c543e627 100644 59 | --- a/hw/ide/core.c 60 | +++ b/hw/ide/core.c 61 | @@ -456,7 +456,7 @@ static void ide_trim_bh_cb(void *opaque) 62 | iocb->bh = NULL; 63 | qemu_aio_unref(iocb); 64 | 65 | - /* Paired with an increment in ide_issue_trim() */ 66 | + /* Paired with an increment in ide_issue_trim_cb() */ 67 | blk_dec_in_flight(blk); 68 | } 69 | 70 | @@ -516,6 +516,8 @@ static void ide_issue_trim_cb(void *opaque, int ret) 71 | done: 72 | iocb->aiocb = NULL; 73 | if (iocb->bh) { 74 | + /* Paired with a decrement in ide_trim_bh_cb() */ 75 | + blk_inc_in_flight(s->blk); 76 | replay_bh_schedule_event(iocb->bh); 77 | } 78 | } 79 | @@ -528,9 +530,6 @@ BlockAIOCB *ide_issue_trim( 80 | IDEDevice *dev = s->unit ? s->bus->slave : s->bus->master; 81 | TrimAIOCB *iocb; 82 | 83 | - /* Paired with a decrement in ide_trim_bh_cb() */ 84 | - blk_inc_in_flight(s->blk); 85 | - 86 | iocb = blk_aio_get(&trim_aiocb_info, s->blk, cb, cb_opaque); 87 | iocb->s = s; 88 | iocb->bh = qemu_bh_new_guarded(ide_trim_bh_cb, iocb, 89 | @@ -754,8 +753,9 @@ void ide_cancel_dma_sync(IDEState *s) 90 | */ 91 | if (s->bus->dma->aiocb) { 92 | trace_ide_cancel_dma_sync_remaining(); 93 | - blk_drain(s->blk); 94 | - assert(s->bus->dma->aiocb == NULL); 95 | + while (s->bus->dma->aiocb) { 96 | + blk_drain(s->blk); 97 | + } 98 | } 99 | } 100 | 101 | -------------------------------------------------------------------------------- /debian/patches/pve/0046-PVE-backup-prepare-for-the-switch-to-using-blockdev-.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Fiona Ebner 3 | Date: Wed, 2 Jul 2025 18:27:34 +0200 4 | Subject: [PATCH] PVE backup: prepare for the switch to using blockdev rather 5 | than drive 6 | MIME-Version: 1.0 7 | Content-Type: text/plain; charset=UTF-8 8 | Content-Transfer-Encoding: 8bit 9 | 10 | Also allow finding block nodes by their node name rather than just via 11 | an associated block backend, which might not exist for block nodes. 12 | 13 | For regular drives, it is essential to not use the throttle group, 14 | because otherwise the limits intended only for the guest would also 15 | apply to the backup job. 16 | 17 | Signed-off-by: Fiona Ebner 18 | Signed-off-by: Fabian Grünbichler 19 | --- 20 | pve-backup.c | 51 +++++++++++++++++++++++++++++++++++++++------------ 21 | 1 file changed, 39 insertions(+), 12 deletions(-) 22 | 23 | diff --git a/pve-backup.c b/pve-backup.c 24 | index da4995d368..ad0f8668fd 100644 25 | --- a/pve-backup.c 26 | +++ b/pve-backup.c 27 | @@ -847,29 +847,56 @@ static PVEBackupDevInfo coroutine_fn GRAPH_RDLOCK *get_single_device_info( 28 | Error **errp) 29 | { 30 | BlockBackend *blk = blk_by_name(device); 31 | - if (!blk) { 32 | - error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 33 | - "Device '%s' not found", device); 34 | - return NULL; 35 | + BlockDriverState *root_bs, *bs; 36 | + 37 | + if (blk) { 38 | + root_bs = bs = blk_bs(blk); 39 | + } else { 40 | + /* TODO PVE 10 - fleecing will always be attached without blk */ 41 | + root_bs = bs = bdrv_find_node(device); 42 | + if (!bs) { 43 | + error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 44 | + "Device '%s' not found", device); 45 | + return NULL; 46 | + } 47 | + /* For TPM, bs is already correct, otherwise need the file child. */ 48 | + if (!strncmp(bs->drv->format_name, "throttle", 8)) { 49 | + if (!bs->file || !bs->file->bs) { 50 | + error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 51 | + "Device '%s' not found (no file child)", device); 52 | + return NULL; 53 | + } 54 | + bs = bs->file->bs; 55 | + } 56 | } 57 | - BlockDriverState *bs = blk_bs(blk); 58 | + 59 | if (!bdrv_co_is_inserted(bs)) { 60 | error_setg(errp, "Device '%s' has no medium", device); 61 | return NULL; 62 | } 63 | + 64 | PVEBackupDevInfo *di = g_new0(PVEBackupDevInfo, 1); 65 | di->bs = bs; 66 | - di->device_name = g_strdup(bdrv_get_device_name(bs)); 67 | + /* Need the name of the root node, e.g. drive-scsi0 */ 68 | + di->device_name = g_strdup(bdrv_get_device_or_node_name(root_bs)); 69 | 70 | if (device_uses_fleecing && device_uses_fleecing(device)) { 71 | g_autofree gchar *fleecing_devid = g_strconcat(device, "-fleecing", NULL); 72 | + BlockDriverState *fleecing_bs; 73 | + 74 | BlockBackend *fleecing_blk = blk_by_name(fleecing_devid); 75 | - if (!fleecing_blk) { 76 | - error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 77 | - "Device '%s' not found", fleecing_devid); 78 | - goto fail; 79 | + if (fleecing_blk) { 80 | + fleecing_bs = blk_bs(fleecing_blk); 81 | + } else { 82 | + /* TODO PVE 10 - fleecing will always be attached without blk */ 83 | + fleecing_bs = bdrv_find_node(fleecing_devid); 84 | + if (!fleecing_bs) { 85 | + error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 86 | + "Device '%s' not found", fleecing_devid); 87 | + goto fail; 88 | + } 89 | } 90 | - BlockDriverState *fleecing_bs = blk_bs(fleecing_blk); 91 | + 92 | if (!bdrv_co_is_inserted(fleecing_bs)) { 93 | error_setg(errp, "Device '%s' has no medium", fleecing_devid); 94 | goto fail; 95 | @@ -927,7 +954,7 @@ static GList coroutine_fn GRAPH_RDLOCK *get_device_info( 96 | 97 | PVEBackupDevInfo *di = g_new0(PVEBackupDevInfo, 1); 98 | di->bs = bs; 99 | - di->device_name = g_strdup(bdrv_get_device_name(bs)); 100 | + di->device_name = g_strdup(bdrv_get_device_or_node_name(bs)); 101 | di_list = g_list_append(di_list, di); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /debian/patches/extra/0008-ui-vdagent-fix-windows-agent-regression.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= 3 | Date: Mon, 27 Oct 2025 17:07:44 +0400 4 | Subject: [PATCH] ui/vdagent: fix windows agent regression 5 | MIME-Version: 1.0 6 | Content-Type: text/plain; charset=UTF-8 7 | Content-Transfer-Encoding: 8bit 8 | 9 | Since commit f626116f ("ui/vdagent: factor out clipboard peer 10 | registration"), the QEMU clipboard serial is reset whenever the vdagent 11 | chardev receives the guest caps. This triggers a CHR_EVENT_CLOSED which 12 | is handled by virtio_serial_close() to notify the guest. 13 | 14 | The "reconnection logic" is there to reset the agent when a 15 | client (dbus, spice etc) reconnects, or the agent is restarted. 16 | It is required to sync the clipboard serials and to prevent races or 17 | loops due to clipboard managers on both ends (but this is not 18 | implemented by windows vdagent). 19 | 20 | The Unix agent has been reconnecting without resending caps, thus 21 | working with this approach. 22 | 23 | However, the Windows agent does not seem to have a way to handle 24 | VIRTIO_CONSOLE_PORT_OPEN=0 event and do not receive further data... 25 | 26 | Let's not trigger this disconnection/reset logic if the agent does not 27 | support VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL. 28 | 29 | Fixes: f626116f ("ui/vdagent: factor out clipboard peer registration") 30 | Signed-off-by: Marc-André Lureau 31 | Reported-by: Lucas Kornicki 32 | Tested-by: Lucas Kornicki 33 | Link: https://lore.kernel.org/all/20251027130744.2714610-1-marcandre.lureau@redhat.com/ 34 | [FE: picked from qemu-devel] 35 | Signed-off-by: Fiona Ebner 36 | --- 37 | ui/vdagent.c | 20 ++++++++++++++------ 38 | 1 file changed, 14 insertions(+), 6 deletions(-) 39 | 40 | diff --git a/ui/vdagent.c b/ui/vdagent.c 41 | index c0746fe5b1..a7c959e8ab 100644 42 | --- a/ui/vdagent.c 43 | +++ b/ui/vdagent.c 44 | @@ -316,6 +316,15 @@ static bool have_selection(VDAgentChardev *vd) 45 | return vd->caps & (1 << VD_AGENT_CAP_CLIPBOARD_SELECTION); 46 | } 47 | 48 | +static bool have_clipboard_serial(VDAgentChardev *vd) 49 | +{ 50 | +#if CHECK_SPICE_PROTOCOL_VERSION(0, 14, 1) 51 | + return vd->caps & (1 << VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL); 52 | +#else 53 | + return false; 54 | +#endif 55 | +} 56 | + 57 | static uint32_t type_qemu_to_vdagent(enum QemuClipboardType type) 58 | { 59 | switch (type) { 60 | @@ -345,8 +354,7 @@ static void vdagent_send_clipboard_grab(VDAgentChardev *vd, 61 | return; 62 | } 63 | 64 | -#if CHECK_SPICE_PROTOCOL_VERSION(0, 14, 1) 65 | - if (vd->caps & (1 << VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL)) { 66 | + if (have_clipboard_serial(vd)) { 67 | if (!info->has_serial) { 68 | /* client should win */ 69 | info->serial = vd->last_serial[info->selection]++; 70 | @@ -356,7 +364,6 @@ static void vdagent_send_clipboard_grab(VDAgentChardev *vd, 71 | data++; 72 | msg->size += sizeof(uint32_t); 73 | } 74 | -#endif 75 | 76 | for (q = 0; q < QEMU_CLIPBOARD_TYPE__COUNT; q++) { 77 | type = type_qemu_to_vdagent(q); 78 | @@ -464,6 +471,9 @@ static void vdagent_clipboard_reset_serial(VDAgentChardev *vd) 79 | { 80 | Chardev *chr = CHARDEV(vd); 81 | 82 | + if (!have_clipboard_serial(vd)) { 83 | + return; 84 | + } 85 | /* reopen the agent connection to reset the serial state */ 86 | qemu_chr_be_event(chr, CHR_EVENT_CLOSED); 87 | /* OPENED again after the guest disconnected, see set_fe_open */ 88 | @@ -518,8 +528,7 @@ static void vdagent_clipboard_recv_grab(VDAgentChardev *vd, uint8_t s, uint32_t 89 | 90 | trace_vdagent_cb_grab_selection(GET_NAME(sel_name, s)); 91 | info = qemu_clipboard_info_new(&vd->cbpeer, s); 92 | -#if CHECK_SPICE_PROTOCOL_VERSION(0, 14, 1) 93 | - if (vd->caps & (1 << VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL)) { 94 | + if (have_clipboard_serial(vd)) { 95 | if (size < sizeof(uint32_t)) { 96 | /* this shouldn't happen! */ 97 | return; 98 | @@ -537,7 +546,6 @@ static void vdagent_clipboard_recv_grab(VDAgentChardev *vd, uint8_t s, uint32_t 99 | data += sizeof(uint32_t); 100 | size -= sizeof(uint32_t); 101 | } 102 | -#endif 103 | if (size > sizeof(uint32_t) * 10) { 104 | /* 105 | * spice has 6 types as of 2021. Limiting to 10 entries 106 | -------------------------------------------------------------------------------- /backup.txt: -------------------------------------------------------------------------------- 1 | Efficient VM backup for qemu 2 | 3 | =Requirements= 4 | 5 | * Backup to a single archive file 6 | * Backup needs to contain all data to restore VM (full backup) 7 | * Do not depend on storage type or image format 8 | * Avoid use of temporary storage 9 | * store sparse images efficiently 10 | 11 | =Introduction= 12 | 13 | Most VM backup solutions use some kind of snapshot to get a consistent 14 | VM view at a specific point in time. For example, we previously used 15 | LVM to create a snapshot of all used VM images, which are then copied 16 | into a tar file. 17 | 18 | That basically means that any data written during backup involve 19 | considerable overhead. For LVM we get the following steps: 20 | 21 | 1.) read original data (VM write) 22 | 2.) write original data into snapshot (VM write) 23 | 3.) write new data (VM write) 24 | 4.) read data from snapshot (backup) 25 | 5.) write data from snapshot into tar file (backup) 26 | 27 | Another approach to backup VM images is to create a new qcow2 image 28 | which use the old image as base. During backup, writes are redirected 29 | to the new image, so the old image represents a 'snapshot'. After 30 | backup, data need to be copied back from new image into the old 31 | one (commit). So a simple write during backup triggers the following 32 | steps: 33 | 34 | 1.) write new data to new image (VM write) 35 | 2.) read data from old image (backup) 36 | 3.) write data from old image into tar file (backup) 37 | 38 | 4.) read data from new image (commit) 39 | 5.) write data to old image (commit) 40 | 41 | This is in fact the same overhead as before. Other tools like qemu 42 | livebackup produces similar overhead (2 reads, 3 writes). 43 | 44 | Some storage types/formats supports internal snapshots using some kind 45 | of reference counting (rados, sheepdog, dm-thin, qcow2). It would be possible 46 | to use that for backups, but for now we want to be storage-independent. 47 | 48 | =Make it more efficient= 49 | 50 | The be more efficient, we simply need to avoid unnecessary steps. The 51 | following steps are always required: 52 | 53 | 1.) read old data before it gets overwritten 54 | 2.) write that data into the backup archive 55 | 3.) write new data (VM write) 56 | 57 | As you can see, this involves only one read, and two writes. 58 | 59 | To make that work, our backup archive need to be able to store image 60 | data 'out of order'. It is important to notice that this will not work 61 | with traditional archive formats like tar. 62 | 63 | During backup we simply intercept writes, then read existing data and 64 | store that directly into the archive. After that we can continue the 65 | write. 66 | 67 | ==Advantages== 68 | 69 | * very good performance (1 read, 2 writes) 70 | * works on any storage type and image format. 71 | * avoid usage of temporary storage 72 | * we can define a new and simple archive format, which is able to 73 | store sparse files efficiently. 74 | 75 | Note: Storing sparse files is a mess with existing archive 76 | formats. For example, tar requires information about holes at the 77 | beginning of the archive. 78 | 79 | ==Disadvantages== 80 | 81 | * we need to define a new archive format 82 | 83 | Note: Most existing archive formats are optimized to store small files 84 | including file attributes. We simply do not need that for VM archives. 85 | 86 | * archive contains data 'out of order' 87 | 88 | If you want to access image data in sequential order, you need to 89 | re-order archive data. It would be possible to to that on the fly, 90 | using temporary files. 91 | 92 | Fortunately, a normal restore/extract works perfectly with 'out of 93 | order' data, because the target files are seekable. 94 | 95 | * slow backup storage can slow down VM during backup 96 | 97 | It is important to note that we only do sequential writes to the 98 | backup storage. Furthermore one can compress the backup stream. IMHO, 99 | it is better to slow down the VM a bit. All other solutions creates 100 | large amounts of temporary data during backup. 101 | 102 | =Archive format requirements= 103 | 104 | The basic requirement for such new format is that we can store image 105 | date 'out of order'. It is also very likely that we have less than 256 106 | drives/images per VM, and we want to be able to store VM configuration 107 | files. 108 | 109 | We have defined a very simply format with those properties, see: 110 | 111 | https://git.proxmox.com/?p=pve-qemu.git;a=blob;f=vma_spec.txt; 112 | 113 | Please let us know if you know an existing format which provides the 114 | same functionality. 115 | 116 | 117 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | This package was debianized by the proxmox support team 2 | 3 | 4 | It was downloaded from 5 | 6 | git://git.kernel.org/pub/scm/virt/kvm/qemu-kvm.git 7 | 8 | Upstream Author: Fabrice Bellard 9 | 10 | Upstream Maintainers: Avi Kivity 11 | Anthony Liguori 12 | 13 | Copyright: Copyright (C) 2006 Qumranet, Inc. 14 | Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Fabrice Bellard 15 | 16 | License: 17 | 18 | QEMU as a whole is released under the GNU General Public License version 2. 19 | On Debian systems, the complete text of the GNU General Public License 20 | version 2 can be found in the file /usr/share/common-licenses/GPL-2. 21 | 22 | Parts of QEMU have specific licenses which are compatible with the 23 | GNU General Public License. Hence each source file contains its own 24 | licensing information. 25 | 26 | In particular, the QEMU virtual CPU core library (libqemu.a) is 27 | released under the GNU Lesser General Public License version 2 or later. 28 | On Debian systems, the complete text of the GNU Lesser General Public 29 | License can be found in the file /usr/share/common-licenses/LGPL. 30 | 31 | Some hardware device emulation sources and other QEMU functionality are 32 | released under the BSD license, including: 33 | * aes, bsd-user, sd, slirp, sys-queue 34 | 35 | Some hardware device emulation sources and other QEMU functionality are 36 | released under the MIT/X11 (BSD-like) license, including: 37 | * sdl, host-utils, vnc, keymaps, ioport, usb, hw/*, net, acl, block, 38 | kqemu, monitor, curses, readline, vl, savevm, osdep, audio, tcg, 39 | qemu-malloc, qemu-img 40 | 41 | The following points clarify the QEMU license: 42 | 1) QEMU as a whole is released under the GNU General Public License 43 | 2) Parts of QEMU have specific licenses which are compatible with the 44 | GNU General Public License. Hence each source file contains its own 45 | licensing information. 46 | In particular, the QEMU virtual CPU core library (libqemu.a) is 47 | released under the GNU Lesser General Public License. Many hardware 48 | device emulation sources are released under the BSD license. 49 | 3) The Tiny Code Generator (TCG) is released under the BSD license 50 | (see license headers in files). 51 | 4) QEMU is a trademark of Fabrice Bellard. 52 | -- Fabrice Bellard. 53 | 54 | BIOS sources in QEMU: 55 | bios.bin: Copyright (C) 2002 MandrakeSoft S.A. and others. This file 56 | is licensed under the GNU LGPL, version 2, or (at your option) any later 57 | version. 58 | Homepage: http://sourceforge.net/projects/bochs 59 | 60 | vgabios.bin and vgabios-cirrus.bin: (C) 2003 the LGPL VGABios 61 | developers Team. These files are licensed under the GNU LGPL, version 2, 62 | or (at your option) any later version. 63 | Homepage: http://savannah.nongnu.org/projects/vgabios 64 | 65 | BSD license: 66 | 67 | Copyright (c) The Regents of the University of California. 68 | All rights reserved. 69 | 70 | Redistribution and use in source and binary forms, with or without 71 | modification, are permitted provided that the following conditions 72 | are met: 73 | 1. Redistributions of source code must retain the above copyright 74 | notice, this list of conditions and the following disclaimer. 75 | 2. Redistributions in binary form must reproduce the above copyright 76 | notice, this list of conditions and the following disclaimer in the 77 | documentation and/or other materials provided with the distribution. 78 | 3. Neither the name of the University nor the names of its contributors 79 | may be used to endorse or promote products derived from this software 80 | without specific prior written permission. 81 | 82 | THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 83 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 84 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 85 | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 86 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 87 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 88 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 89 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 90 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 91 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 92 | SUCH DAMAGE. 93 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # -*- makefile -*- 3 | 4 | # Uncomment this to turn on verbose mode. 5 | #export DH_VERBOSE=1 6 | 7 | include /usr/share/dpkg/default.mk 8 | 9 | HOST_CPU ?= $(DEB_HOST_GNU_CPU) 10 | 11 | PACKAGE=pve-qemu-kvm 12 | destdir := $(CURDIR)/debian/$(PACKAGE) 13 | 14 | flagfile := $(destdir)/usr/share/kvm/recognized-CPUID-flags-x86_64 15 | machinefile := $(destdir)/usr/share/kvm/machine-versions-x86_64.json 16 | 17 | # default QEMU out-of-tree build directory is ./build 18 | BUILDDIR=build 19 | 20 | # FIXME: pass to configure as --extra-cflags=CFLAGS ?! also LDFLAGS? 21 | CFLAGS += -Wall 22 | 23 | export CFLAGS 24 | 25 | # DEB_BUILD_OPTIONS=parallel=N 26 | MAKEFLAGS += $(subst parallel=,-j,$(filter parallel=%,${DEB_BUILD_OPTIONS})) 27 | 28 | ${BUILDDIR}/config.status: configure 29 | dh_testdir 30 | # Add here commands to configure the package. 31 | 32 | ifneq "$(wildcard /usr/share/misc/config.sub)" "" 33 | cp -f /usr/share/misc/config.sub config.sub 34 | endif 35 | ifneq "$(wildcard /usr/share/misc/config.guess)" "" 36 | cp -f /usr/share/misc/config.guess config.guess 37 | endif 38 | 39 | # guest-agent is only required for guest systems 40 | ./configure \ 41 | --disable-download \ 42 | --docdir=/usr/share/doc/pve-qemu-kvm \ 43 | --localstatedir=/var \ 44 | --prefix=/usr \ 45 | --sysconfdir=/etc \ 46 | --target-list=$(HOST_CPU)-softmmu,aarch64-softmmu \ 47 | --with-suffix="kvm" \ 48 | --with-pkgversion="${DEB_SOURCE}_${DEB_VERSION_UPSTREAM_REVISION}" \ 49 | --audio-drv-list="alsa" \ 50 | --datadir=/usr/share \ 51 | --libexecdir=/usr/lib/kvm \ 52 | --disable-capstone \ 53 | --disable-gtk \ 54 | --disable-guest-agent \ 55 | --disable-guest-agent-msi \ 56 | --disable-libnfs \ 57 | --disable-libssh \ 58 | --disable-sdl \ 59 | --disable-smartcard \ 60 | --disable-strip \ 61 | --disable-xen \ 62 | --enable-curl \ 63 | --enable-docs \ 64 | --enable-fuse \ 65 | --enable-gnutls \ 66 | --enable-libiscsi \ 67 | --enable-libusb \ 68 | --enable-linux-aio \ 69 | --enable-linux-io-uring \ 70 | --enable-numa \ 71 | --enable-opengl \ 72 | --enable-rbd \ 73 | --enable-seccomp \ 74 | --enable-slirp \ 75 | --enable-spice \ 76 | --enable-usb-redir \ 77 | --enable-virglrenderer \ 78 | --enable-virtfs \ 79 | --enable-zstd 80 | 81 | build: build-arch build-indep 82 | build-arch: build-stamp 83 | build-indep: build-stamp 84 | build: build-stamp 85 | 86 | build-stamp: ${BUILDDIR}/config.status 87 | dh_testdir 88 | 89 | # Add here commands to compile the package. 90 | $(MAKE) 91 | 92 | #docbook-to-man debian/kvm.sgml > kvm.1 93 | 94 | touch $@ 95 | 96 | clean: 97 | dh_testdir 98 | dh_testroot 99 | rm -f build-stamp 100 | 101 | # Add here commands to clean up before the build process. 102 | -$(MAKE) distclean 103 | 104 | dh_clean 105 | 106 | install: build 107 | dh_testdir 108 | dh_testroot 109 | dh_prep 110 | dh_installdirs 111 | dh_lintian 112 | 113 | # Add here commands to install the package into debian/pve-kvm. 114 | $(MAKE) DESTDIR=$(destdir) install 115 | 116 | # Remove things we don't package at all, would be a "kvm-dev" package 117 | rm -Rf $(destdir)/usr/include/linux/ 118 | rm -Rf $(destdir)/usr/include 119 | rm -f $(destdir)/usr/lib/kvm/qemu-bridge-helper 120 | rm -f $(destdir)/usr/lib/kvm/virtfs-proxy-helper 121 | 122 | # CPU flags are static for QEMU version, allows avoiding more costly checks 123 | $(destdir)/usr/bin/qemu-system-x86_64 -cpu help | ./debian/parse-cpu-flags.pl > $(flagfile) 124 | $(destdir)/usr/bin/qemu-system-x86_64 -machine help | ./debian/parse-machines.pl > $(machinefile) 125 | 126 | # Build architecture-independent files here. 127 | binary-indep: build install 128 | # We have nothing to do by default. 129 | 130 | # Build architecture-dependent files here. 131 | binary-arch: build install 132 | dh_testdir 133 | dh_testroot 134 | dh_installchangelogs 135 | dh_installdocs 136 | dh_installexamples 137 | dh_install 138 | # dh_installmenu 139 | # dh_installdebconf 140 | # dh_installlogrotate 141 | # dh_installemacsen 142 | # dh_installpam 143 | # dh_installmime 144 | # dh_python 145 | # dh_installinit 146 | # dh_installcron 147 | # dh_installinfo 148 | dh_installman 149 | dh_link 150 | dh_strip --dbgsym-migration='pve-qemu-kvm-dbg (<<8.0.0-1~)' 151 | dh_compress 152 | dh_fixperms 153 | # dh_perl 154 | # dh_makeshlibs 155 | dh_installdeb 156 | # Debian >= Buster has libglusterfs0 and lots of libgfFOO, upstream has the libs in glusterfs-common 157 | # pass -x to dpkg-shlibdeps and specify dependencies in d/control instead 158 | dh_shlibdeps -- -xlibglusterfs0 -xlibgfxdr0 -xlibgfrpc0 -xlibgfdb0 -xlibgfchangelog0 -xlibgfapi0 159 | dh_gencontrol 160 | dh_md5sums 161 | dh_builddeb 162 | 163 | binary: binary-indep binary-arch 164 | .PHONY: build clean binary-indep binary-arch binary install 165 | -------------------------------------------------------------------------------- /debian/patches/pve/0011-PVE-Up-qemu-img-dd-add-n-skip_create.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alexandre Derumier 3 | Date: Mon, 6 Apr 2020 12:16:42 +0200 4 | Subject: [PATCH] PVE: [Up] qemu-img dd: add -n skip_create 5 | 6 | Signed-off-by: Thomas Lamprecht 7 | [FE: fix getopt-string + add documentation 8 | rebase for 10.1.0] 9 | Signed-off-by: Fiona Ebner 10 | --- 11 | docs/tools/qemu-img.rst | 11 ++++++++++- 12 | qemu-img-cmds.hx | 4 ++-- 13 | qemu-img.c | 23 ++++++++++++++--------- 14 | 3 files changed, 26 insertions(+), 12 deletions(-) 15 | 16 | diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst 17 | index 5e7b85079d..6249e01da9 100644 18 | --- a/docs/tools/qemu-img.rst 19 | +++ b/docs/tools/qemu-img.rst 20 | @@ -212,6 +212,10 @@ Parameters to convert subcommand: 21 | 22 | Parameters to dd subcommand: 23 | 24 | +.. option:: -n 25 | + 26 | + Skip the creation of the target volume 27 | + 28 | .. program:: qemu-img-dd 29 | 30 | .. option:: bs=BLOCK_SIZE 31 | @@ -492,7 +496,7 @@ Command description: 32 | it doesn't need to be specified separately in this case. 33 | 34 | 35 | -.. option:: dd [--image-opts] [-U] [-f FMT] [-O OUTPUT_FMT] [bs=BLOCK_SIZE] [count=BLOCKS] [skip=BLOCKS] if=INPUT of=OUTPUT 36 | +.. option:: dd [--image-opts] [-U] [-f FMT] [-O OUTPUT_FMT] [-n] [bs=BLOCK_SIZE] [count=BLOCKS] [skip=BLOCKS] if=INPUT of=OUTPUT 37 | 38 | dd copies from *INPUT* file to *OUTPUT* file converting it from 39 | *FMT* format to *OUTPUT_FMT* format. 40 | @@ -503,6 +507,11 @@ Command description: 41 | 42 | The size syntax is similar to :manpage:`dd(1)`'s size syntax. 43 | 44 | + If the ``-n`` option is specified, the target volume creation will be 45 | + skipped. This is useful for formats such as ``rbd`` if the target 46 | + volume has already been created with site specific options that cannot 47 | + be supplied through ``qemu-img``. 48 | + 49 | .. option:: info [--object OBJECTDEF] [--image-opts] [-f FMT] [--output=OFMT] [--backing-chain] [-U] FILENAME 50 | 51 | Give information about the disk image *FILENAME*. Use it in 52 | diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx 53 | index a6de1434a3..d584624f8e 100644 54 | --- a/qemu-img-cmds.hx 55 | +++ b/qemu-img-cmds.hx 56 | @@ -60,9 +60,9 @@ SRST 57 | ERST 58 | 59 | DEF("dd", img_dd, 60 | - "dd [--image-opts] [-U] [-f fmt] [-O output_fmt] [bs=block_size] [count=blocks] [skip=blocks] [osize=output_size] if=input of=output") 61 | + "dd [--image-opts] [-U] [-f fmt] [-O output_fmt] [-n] [bs=block_size] [count=blocks] [skip=blocks] [osize=output_size] if=input of=output") 62 | SRST 63 | -.. option:: dd [--image-opts] [-U] [-f FMT] [-O OUTPUT_FMT] [bs=BLOCK_SIZE] [count=BLOCKS] [skip=BLOCKS] [osize=OUTPUT_SIZE] if=INPUT of=OUTPUT 64 | +.. option:: dd [--image-opts] [-U] [-f FMT] [-O OUTPUT_FMT] [-n] [bs=BLOCK_SIZE] [count=BLOCKS] [skip=BLOCKS] [osize=OUTPUT_SIZE] if=INPUT of=OUTPUT 65 | ERST 66 | 67 | DEF("info", img_info, 68 | diff --git a/qemu-img.c b/qemu-img.c 69 | index 89ef74ae07..6e92a70254 100644 70 | --- a/qemu-img.c 71 | +++ b/qemu-img.c 72 | @@ -5378,7 +5378,7 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) 73 | const char *fmt = NULL; 74 | int64_t size = 0, readsize = 0; 75 | int64_t out_pos, in_pos; 76 | - bool force_share = false; 77 | + bool force_share = false, skip_create = false; 78 | struct DdInfo dd = { 79 | .flags = 0, 80 | .count = 0, 81 | @@ -5418,7 +5418,7 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) 82 | { 0, 0, 0, 0 } 83 | }; 84 | 85 | - while ((c = getopt_long(argc, argv, "hf:O:U", long_options, NULL))) { 86 | + while ((c = getopt_long(argc, argv, "hf:O:Un", long_options, NULL))) { 87 | if (c == EOF) { 88 | break; 89 | } 90 | @@ -5459,6 +5459,9 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) 91 | case 'O': 92 | out_fmt = optarg; 93 | break; 94 | + case 'n': 95 | + skip_create = true; 96 | + break; 97 | case 'U': 98 | force_share = true; 99 | break; 100 | @@ -5588,13 +5591,15 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) 101 | size - in.bsz * in.offset, &error_abort); 102 | } 103 | 104 | - ret = bdrv_create(drv, out.filename, opts, &local_err); 105 | - if (ret < 0) { 106 | - error_reportf_err(local_err, 107 | - "%s: error while creating output image: ", 108 | - out.filename); 109 | - ret = -1; 110 | - goto out; 111 | + if (!skip_create) { 112 | + ret = bdrv_create(drv, out.filename, opts, &local_err); 113 | + if (ret < 0) { 114 | + error_reportf_err(local_err, 115 | + "%s: error while creating output image: ", 116 | + out.filename); 117 | + ret = -1; 118 | + goto out; 119 | + } 120 | } 121 | 122 | /* TODO, we can't honour --image-opts for the target, 123 | -------------------------------------------------------------------------------- /debian/patches/pve/0025-PVE-Allow-version-code-in-machine-type.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Dietmar Maurer 3 | Date: Mon, 6 Apr 2020 12:16:55 +0200 4 | Subject: [PATCH] PVE: Allow version code in machine type 5 | 6 | E.g. pc-i440fx-4.0+pve3 would print 'pve3' as version code while 7 | selecting pc-i440fx-4.0 as machine type. 8 | 9 | Version is made available as 'pve-version' in query-machines (same as, 10 | and only if 'is-current'). 11 | 12 | Signed-off-by: Stefan Reiter 13 | Signed-off-by: Thomas Lamprecht 14 | [FE: adapt to QAPI changes] 15 | Signed-off-by: Fiona Ebner 16 | --- 17 | hw/core/machine-qmp-cmds.c | 5 +++++ 18 | include/hw/boards.h | 2 ++ 19 | qapi/machine.json | 3 +++ 20 | system/vl.c | 24 ++++++++++++++++++++++++ 21 | 4 files changed, 34 insertions(+) 22 | 23 | diff --git a/hw/core/machine-qmp-cmds.c b/hw/core/machine-qmp-cmds.c 24 | index 934cdb886d..124000b771 100644 25 | --- a/hw/core/machine-qmp-cmds.c 26 | +++ b/hw/core/machine-qmp-cmds.c 27 | @@ -98,6 +98,11 @@ MachineInfoList *qmp_query_machines(bool has_compat_props, bool compat_props, 28 | if (strcmp(mc->name, MACHINE_GET_CLASS(current_machine)->name) == 0) { 29 | info->has_is_current = true; 30 | info->is_current = true; 31 | + 32 | + // PVE version string only exists for current machine 33 | + if (mc->pve_version) { 34 | + info->pve_version = g_strdup(mc->pve_version); 35 | + } 36 | } 37 | 38 | if (default_cpu_type) { 39 | diff --git a/include/hw/boards.h b/include/hw/boards.h 40 | index f94713e6e2..7a389f6998 100644 41 | --- a/include/hw/boards.h 42 | +++ b/include/hw/boards.h 43 | @@ -271,6 +271,8 @@ struct MachineClass { 44 | const char *desc; 45 | const char *deprecation_reason; 46 | 47 | + const char *pve_version; 48 | + 49 | void (*init)(MachineState *state); 50 | void (*reset)(MachineState *state, ResetType type); 51 | void (*wakeup)(MachineState *state); 52 | diff --git a/qapi/machine.json b/qapi/machine.json 53 | index 47ac68a3b5..957ff0f4dd 100644 54 | --- a/qapi/machine.json 55 | +++ b/qapi/machine.json 56 | @@ -192,6 +192,8 @@ 57 | # 58 | # @acpi: machine type supports ACPI (since 8.0) 59 | # 60 | +# @pve-version: custom PVE version suffix specified as 'machine+pveN' 61 | +# 62 | # @compat-props: The machine type's compatibility properties. Only 63 | # present when `query-machines` argument @compat-props is true. 64 | # (since 9.1) 65 | @@ -208,6 +210,7 @@ 66 | 'hotpluggable-cpus': 'bool', 'numa-mem-supported': 'bool', 67 | 'deprecated': 'bool', '*default-cpu-type': 'str', 68 | '*default-ram-id': 'str', 'acpi': 'bool', 69 | + '*pve-version': 'str', 70 | '*compat-props': { 'type': ['CompatProperty'], 71 | 'features': ['unstable'] } } } 72 | 73 | diff --git a/system/vl.c b/system/vl.c 74 | index 56f8900451..4d583d60b1 100644 75 | --- a/system/vl.c 76 | +++ b/system/vl.c 77 | @@ -1673,6 +1673,7 @@ static MachineClass *select_machine(QDict *qdict, Error **errp) 78 | { 79 | ERRP_GUARD(); 80 | const char *machine_type = qdict_get_try_str(qdict, "type"); 81 | + const char *pvever = qdict_get_try_str(qdict, "pvever"); 82 | g_autoptr(GSList) machines = object_class_get_list(TYPE_MACHINE, false); 83 | MachineClass *machine_class = NULL; 84 | 85 | @@ -1692,7 +1693,11 @@ static MachineClass *select_machine(QDict *qdict, Error **errp) 86 | if (!machine_class) { 87 | error_append_hint(errp, 88 | "Use -machine help to list supported machines\n"); 89 | + } else { 90 | + machine_class->pve_version = g_strdup(pvever); 91 | + qdict_del(qdict, "pvever"); 92 | } 93 | + 94 | return machine_class; 95 | } 96 | 97 | @@ -3411,12 +3416,31 @@ void qemu_init(int argc, char **argv) 98 | case QEMU_OPTION_machine: 99 | { 100 | bool help; 101 | + size_t pvever_index, name_len; 102 | + const gchar *name; 103 | + gchar *name_clean, *pvever; 104 | 105 | keyval_parse_into(machine_opts_dict, optarg, "type", &help, &error_fatal); 106 | if (help) { 107 | machine_help_func(machine_opts_dict); 108 | exit(EXIT_SUCCESS); 109 | } 110 | + 111 | + // PVE version is specified with '+' as seperator, e.g. pc-i440fx+pvever 112 | + name = qdict_get_try_str(machine_opts_dict, "type"); 113 | + if (name != NULL) { 114 | + name_len = strlen(name); 115 | + pvever_index = strcspn(name, "+"); 116 | + if (pvever_index < name_len) { 117 | + name_clean = g_strndup(name, pvever_index); 118 | + pvever = g_strndup(name + pvever_index + 1, name_len - pvever_index - 1); 119 | + qdict_put_str(machine_opts_dict, "pvever", pvever); 120 | + qdict_put_str(machine_opts_dict, "type", name_clean); 121 | + g_free(name_clean); 122 | + g_free(pvever); 123 | + } 124 | + } 125 | + 126 | break; 127 | } 128 | case QEMU_OPTION_accel: 129 | -------------------------------------------------------------------------------- /debian/patches/pve/0012-qemu-img-dd-add-l-option-for-loading-a-snapshot.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Fabian Ebner 3 | Date: Mon, 7 Feb 2022 14:21:01 +0100 4 | Subject: [PATCH] qemu-img dd: add -l option for loading a snapshot 5 | 6 | Signed-off-by: Fiona Ebner 7 | Signed-off-by: Thomas Lamprecht 8 | [FE: rebase for 10.1.0] 9 | Signed-off-by: Fiona Ebner 10 | --- 11 | docs/tools/qemu-img.rst | 6 +++--- 12 | qemu-img-cmds.hx | 4 ++-- 13 | qemu-img.c | 33 +++++++++++++++++++++++++++++++-- 14 | 3 files changed, 36 insertions(+), 7 deletions(-) 15 | 16 | diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst 17 | index 6249e01da9..0ea21e061f 100644 18 | --- a/docs/tools/qemu-img.rst 19 | +++ b/docs/tools/qemu-img.rst 20 | @@ -496,10 +496,10 @@ Command description: 21 | it doesn't need to be specified separately in this case. 22 | 23 | 24 | -.. option:: dd [--image-opts] [-U] [-f FMT] [-O OUTPUT_FMT] [-n] [bs=BLOCK_SIZE] [count=BLOCKS] [skip=BLOCKS] if=INPUT of=OUTPUT 25 | +.. option:: dd [--image-opts] [-U] [-f FMT] [-O OUTPUT_FMT] [-n] [-l SNAPSHOT_PARAM] [bs=BLOCK_SIZE] [count=BLOCKS] [skip=BLOCKS] if=INPUT of=OUTPUT 26 | 27 | - dd copies from *INPUT* file to *OUTPUT* file converting it from 28 | - *FMT* format to *OUTPUT_FMT* format. 29 | + dd copies from *INPUT* file or snapshot *SNAPSHOT_PARAM* to *OUTPUT* file 30 | + converting it from *FMT* format to *OUTPUT_FMT* format. 31 | 32 | The data is by default read and written using blocks of 512 bytes but can be 33 | modified by specifying *BLOCK_SIZE*. If count=\ *BLOCKS* is specified 34 | diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx 35 | index d584624f8e..be30905374 100644 36 | --- a/qemu-img-cmds.hx 37 | +++ b/qemu-img-cmds.hx 38 | @@ -60,9 +60,9 @@ SRST 39 | ERST 40 | 41 | DEF("dd", img_dd, 42 | - "dd [--image-opts] [-U] [-f fmt] [-O output_fmt] [-n] [bs=block_size] [count=blocks] [skip=blocks] [osize=output_size] if=input of=output") 43 | + "dd [--image-opts] [-U] [-f fmt] [-O output_fmt] [-n] [-l snapshot_param] [bs=block_size] [count=blocks] [skip=blocks] [osize=output_size] if=input of=output") 44 | SRST 45 | -.. option:: dd [--image-opts] [-U] [-f FMT] [-O OUTPUT_FMT] [-n] [bs=BLOCK_SIZE] [count=BLOCKS] [skip=BLOCKS] [osize=OUTPUT_SIZE] if=INPUT of=OUTPUT 46 | +.. option:: dd [--image-opts] [-U] [-f FMT] [-O OUTPUT_FMT] [-n] [-l SNAPSHOT_PARAM] [bs=BLOCK_SIZE] [count=BLOCKS] [skip=BLOCKS] [osize=OUTPUT_SIZE] if=INPUT of=OUTPUT 47 | ERST 48 | 49 | DEF("info", img_info, 50 | diff --git a/qemu-img.c b/qemu-img.c 51 | index 6e92a70254..e38317a445 100644 52 | --- a/qemu-img.c 53 | +++ b/qemu-img.c 54 | @@ -5370,6 +5370,7 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) 55 | BlockDriver *drv = NULL, *proto_drv = NULL; 56 | BlockBackend *blk1 = NULL, *blk2 = NULL; 57 | QemuOpts *opts = NULL; 58 | + QemuOpts *sn_opts = NULL; 59 | QemuOptsList *create_opts = NULL; 60 | Error *local_err = NULL; 61 | bool image_opts = false; 62 | @@ -5379,6 +5380,7 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) 63 | int64_t size = 0, readsize = 0; 64 | int64_t out_pos, in_pos; 65 | bool force_share = false, skip_create = false; 66 | + const char *snapshot_name = NULL; 67 | struct DdInfo dd = { 68 | .flags = 0, 69 | .count = 0, 70 | @@ -5418,7 +5420,7 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) 71 | { 0, 0, 0, 0 } 72 | }; 73 | 74 | - while ((c = getopt_long(argc, argv, "hf:O:Un", long_options, NULL))) { 75 | + while ((c = getopt_long(argc, argv, "hf:O:l:Un", long_options, NULL))) { 76 | if (c == EOF) { 77 | break; 78 | } 79 | @@ -5462,6 +5464,19 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) 80 | case 'n': 81 | skip_create = true; 82 | break; 83 | + case 'l': 84 | + if (strstart(optarg, SNAPSHOT_OPT_BASE, NULL)) { 85 | + sn_opts = qemu_opts_parse_noisily(&internal_snapshot_opts, 86 | + optarg, false); 87 | + if (!sn_opts) { 88 | + error_report("Failed in parsing snapshot param '%s'", 89 | + optarg); 90 | + goto out; 91 | + } 92 | + } else { 93 | + snapshot_name = optarg; 94 | + } 95 | + break; 96 | case 'U': 97 | force_share = true; 98 | break; 99 | @@ -5520,11 +5535,24 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) 100 | if (dd.flags & C_IF) { 101 | blk1 = img_open(image_opts, in.filename, fmt, 0, false, false, 102 | force_share); 103 | - 104 | if (!blk1) { 105 | ret = -1; 106 | goto out; 107 | } 108 | + if (sn_opts) { 109 | + bdrv_snapshot_load_tmp(blk_bs(blk1), 110 | + qemu_opt_get(sn_opts, SNAPSHOT_OPT_ID), 111 | + qemu_opt_get(sn_opts, SNAPSHOT_OPT_NAME), 112 | + &local_err); 113 | + } else if (snapshot_name != NULL) { 114 | + bdrv_snapshot_load_tmp_by_id_or_name(blk_bs(blk1), snapshot_name, 115 | + &local_err); 116 | + } 117 | + if (local_err) { 118 | + error_reportf_err(local_err, "Failed to load snapshot: "); 119 | + ret = -1; 120 | + goto out; 121 | + } 122 | } 123 | 124 | if (dd.flags & C_OSIZE) { 125 | @@ -5679,6 +5707,7 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) 126 | out: 127 | g_free(arg); 128 | qemu_opts_del(opts); 129 | + qemu_opts_del(sn_opts); 130 | qemu_opts_free(create_opts); 131 | blk_unref(blk1); 132 | blk_unref(blk2); 133 | -------------------------------------------------------------------------------- /debian/patches/pve/0022-PVE-Up-Config-file-posix-make-locking-optiono-on-cre.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Wolfgang Bumiller 3 | Date: Mon, 6 Apr 2020 12:16:50 +0200 4 | Subject: [PATCH] PVE: [Up+Config] file-posix: make locking optiono on create 5 | 6 | Otherwise creating images on nfs/cifs can be problematic. 7 | 8 | Signed-off-by: Wolfgang Bumiller 9 | Signed-off-by: Thomas Lamprecht 10 | --- 11 | block/file-posix.c | 59 ++++++++++++++++++++++++++++++-------------- 12 | qapi/block-core.json | 7 +++++- 13 | 2 files changed, 46 insertions(+), 20 deletions(-) 14 | 15 | diff --git a/block/file-posix.c b/block/file-posix.c 16 | index baac7653db..fc5cf223bc 100644 17 | --- a/block/file-posix.c 18 | +++ b/block/file-posix.c 19 | @@ -2993,6 +2993,7 @@ raw_co_create(BlockdevCreateOptions *options, Error **errp) 20 | int fd; 21 | uint64_t perm, shared; 22 | int result = 0; 23 | + bool locked = false; 24 | 25 | /* Validate options and set default values */ 26 | assert(options->driver == BLOCKDEV_DRIVER_FILE); 27 | @@ -3033,19 +3034,22 @@ raw_co_create(BlockdevCreateOptions *options, Error **errp) 28 | perm = BLK_PERM_WRITE | BLK_PERM_RESIZE; 29 | shared = BLK_PERM_ALL & ~BLK_PERM_RESIZE; 30 | 31 | - /* Step one: Take locks */ 32 | - result = raw_apply_lock_bytes(NULL, fd, perm, ~shared, false, errp); 33 | - if (result < 0) { 34 | - goto out_close; 35 | - } 36 | + if (file_opts->locking != ON_OFF_AUTO_OFF) { 37 | + /* Step one: Take locks */ 38 | + result = raw_apply_lock_bytes(NULL, fd, perm, ~shared, false, errp); 39 | + if (result < 0) { 40 | + goto out_close; 41 | + } 42 | + locked = true; 43 | 44 | - /* Step two: Check that nobody else has taken conflicting locks */ 45 | - result = raw_check_lock_bytes(fd, perm, shared, errp); 46 | - if (result < 0) { 47 | - error_append_hint(errp, 48 | - "Is another process using the image [%s]?\n", 49 | - file_opts->filename); 50 | - goto out_unlock; 51 | + /* Step two: Check that nobody else has taken conflicting locks */ 52 | + result = raw_check_lock_bytes(fd, perm, shared, errp); 53 | + if (result < 0) { 54 | + error_append_hint(errp, 55 | + "Is another process using the image [%s]?\n", 56 | + file_opts->filename); 57 | + goto out_unlock; 58 | + } 59 | } 60 | 61 | /* Clear the file by truncating it to 0 */ 62 | @@ -3099,13 +3103,15 @@ raw_co_create(BlockdevCreateOptions *options, Error **errp) 63 | } 64 | 65 | out_unlock: 66 | - raw_apply_lock_bytes(NULL, fd, 0, 0, true, &local_err); 67 | - if (local_err) { 68 | - /* The above call should not fail, and if it does, that does 69 | - * not mean the whole creation operation has failed. So 70 | - * report it the user for their convenience, but do not report 71 | - * it to the caller. */ 72 | - warn_report_err(local_err); 73 | + if (locked) { 74 | + raw_apply_lock_bytes(NULL, fd, 0, 0, true, &local_err); 75 | + if (local_err) { 76 | + /* The above call should not fail, and if it does, that does 77 | + * not mean the whole creation operation has failed. So 78 | + * report it the user for their convenience, but do not report 79 | + * it to the caller. */ 80 | + warn_report_err(local_err); 81 | + } 82 | } 83 | 84 | out_close: 85 | @@ -3129,6 +3135,7 @@ raw_co_create_opts(BlockDriver *drv, const char *filename, 86 | PreallocMode prealloc; 87 | char *buf = NULL; 88 | Error *local_err = NULL; 89 | + OnOffAuto locking; 90 | 91 | /* Skip file: protocol prefix */ 92 | strstart(filename, "file:", &filename); 93 | @@ -3151,6 +3158,18 @@ raw_co_create_opts(BlockDriver *drv, const char *filename, 94 | return -EINVAL; 95 | } 96 | 97 | + locking = qapi_enum_parse(&OnOffAuto_lookup, 98 | + qemu_opt_get(opts, "locking"), 99 | + ON_OFF_AUTO_AUTO, &local_err); 100 | + if (local_err) { 101 | + error_propagate(errp, local_err); 102 | + return -EINVAL; 103 | + } 104 | + 105 | + if (locking == ON_OFF_AUTO_AUTO) { 106 | + locking = ON_OFF_AUTO_OFF; 107 | + } 108 | + 109 | options = (BlockdevCreateOptions) { 110 | .driver = BLOCKDEV_DRIVER_FILE, 111 | .u.file = { 112 | @@ -3162,6 +3181,8 @@ raw_co_create_opts(BlockDriver *drv, const char *filename, 113 | .nocow = nocow, 114 | .has_extent_size_hint = has_extent_size_hint, 115 | .extent_size_hint = extent_size_hint, 116 | + .has_locking = true, 117 | + .locking = locking, 118 | }, 119 | }; 120 | return raw_co_create(&options, errp); 121 | diff --git a/qapi/block-core.json b/qapi/block-core.json 122 | index aa1dba4284..e17ef6abdf 100644 123 | --- a/qapi/block-core.json 124 | +++ b/qapi/block-core.json 125 | @@ -5081,6 +5081,10 @@ 126 | # @extent-size-hint: Extent size hint to add to the image file; 0 for 127 | # not adding an extent size hint (default: 1 MB, since 5.1) 128 | # 129 | +# @locking: whether to enable file locking. If set to 'auto', only 130 | +# enable when Open File Descriptor (OFD) locking API is available 131 | +# (default: auto). 132 | +# 133 | # Since: 2.12 134 | ## 135 | { 'struct': 'BlockdevCreateOptionsFile', 136 | @@ -5088,7 +5092,8 @@ 137 | 'size': 'size', 138 | '*preallocation': 'PreallocMode', 139 | '*nocow': 'bool', 140 | - '*extent-size-hint': 'size'} } 141 | + '*extent-size-hint': 'size', 142 | + '*locking': 'OnOffAuto' } } 143 | 144 | ## 145 | # @BlockdevCreateOptionsGluster: 146 | -------------------------------------------------------------------------------- /debian/patches/extra/0011-block-io_uring-avoid-potentially-getting-stuck-after.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Fiona Ebner 3 | Date: Mon, 24 Nov 2025 15:28:27 +0100 4 | Subject: [PATCH] block/io_uring: avoid potentially getting stuck after 5 | resubmit at the end of ioq_submit() 6 | 7 | Note that this issue seems already fixed as a consequence of the large 8 | io_uring rework with 047dabef97 ("block/io_uring: use aio_add_sqe()") 9 | in current master, so this is purely for QEMU stable branches. 10 | 11 | At the end of ioq_submit(), there is an opportunistic call to 12 | luring_process_completions(). This is the single caller of 13 | luring_process_completions() that doesn't use the 14 | luring_process_completions_and_submit() wrapper. 15 | 16 | Other callers use the wrapper, because luring_process_completions() 17 | might require a subsequent call to ioq_submit() after resubmitting a 18 | request. As noted for luring_resubmit(): 19 | 20 | > Resubmit a request by appending it to submit_queue. The caller must ensure 21 | > that ioq_submit() is called later so that submit_queue requests are started. 22 | 23 | So the caller at the end of ioq_submit() violates the contract and can 24 | in fact be problematic if no other requests come in later. In such a 25 | case, the request intended to be resubmitted will never be actually be 26 | submitted via io_uring_submit(). 27 | 28 | A reproducer exposing this issue is [0], which is based on user 29 | reports from [1]. Another reproducer is iotest 109 with '-i io_uring'. 30 | 31 | I had the most success to trigger the issue with [0] when using a 32 | BTRFS RAID 1 storage. With tmpfs, it can take quite a few iterations, 33 | but also triggers eventually on my machine. With iotest 109 with '-i 34 | io_uring' the issue triggers reliably on my ext4 file system. 35 | 36 | Have ioq_submit() submit any resubmitted requests after calling 37 | luring_process_completions(). The return value from io_uring_submit() 38 | is checked to be non-negative before the opportunistic processing of 39 | completions and going for the new resubmit logic, to ensure that a 40 | failure of io_uring_submit() is not missed. Also note that the return 41 | value already was not necessarily the total number of submissions, 42 | since the loop might've been iterated more than once even before the 43 | current change. 44 | 45 | Only trigger the resubmission logic if it is actually necessary to 46 | avoid changing behavior more than necessary. For example iotest 109 47 | would produce more 'mirror ready' events if always resubmitting after 48 | luring_process_completions() at the end of ioq_submit(). 49 | 50 | Note iotest 109 still does not pass as is when run with '-i io_uring', 51 | because of two offset values for BLOCK_JOB_COMPLETED events being zero 52 | instead of non-zero as in the expected output. Note that the two 53 | affected test cases are expected failures and still fail, so they just 54 | fail "faster". The test cases are actually not triggering the resubmit 55 | logic, so the reason seems to be different ordering of requests and 56 | completions of the current aio=io_uring implementation versus 57 | aio=threads. 58 | 59 | [0]: 60 | 61 | > #!/bin/bash -e 62 | > #file=/mnt/btrfs/disk.raw 63 | > file=/tmp/disk.raw 64 | > filesize=256 65 | > readsize=512 66 | > rm -f $file 67 | > truncate -s $filesize $file 68 | > ./qemu-system-x86_64 --trace '*uring*' --qmp stdio \ 69 | > --blockdev raw,node-name=node0,file.driver=file,file.cache.direct=off,file.filename=$file,file.aio=io_uring \ 70 | > < {"execute": "qmp_capabilities"} 72 | > {"execute": "human-monitor-command", "arguments": { "command-line": "qemu-io node0 \"read 0 $readsize \"" }} 73 | > {"execute": "quit"} 74 | > EOF 75 | 76 | [1]: https://forum.proxmox.com/threads/170045/ 77 | 78 | Cc: qemu-stable@nongnu.org 79 | Signed-off-by: Fiona Ebner 80 | --- 81 | block/io_uring.c | 16 +++++++++++++--- 82 | 1 file changed, 13 insertions(+), 3 deletions(-) 83 | 84 | diff --git a/block/io_uring.c b/block/io_uring.c 85 | index dd4f304910..5dbafc8f7b 100644 86 | --- a/block/io_uring.c 87 | +++ b/block/io_uring.c 88 | @@ -120,11 +120,14 @@ static void luring_resubmit_short_read(LuringState *s, LuringAIOCB *luringcb, 89 | * event loop. When there are no events left to complete the BH is being 90 | * canceled. 91 | * 92 | + * Returns whether ioq_submit() must be called again afterwards since requests 93 | + * were resubmitted via luring_resubmit(). 94 | */ 95 | -static void luring_process_completions(LuringState *s) 96 | +static bool luring_process_completions(LuringState *s) 97 | { 98 | struct io_uring_cqe *cqes; 99 | int total_bytes; 100 | + bool resubmit = false; 101 | 102 | defer_call_begin(); 103 | 104 | @@ -182,6 +185,7 @@ static void luring_process_completions(LuringState *s) 105 | */ 106 | if (ret == -EINTR || ret == -EAGAIN) { 107 | luring_resubmit(s, luringcb); 108 | + resubmit = true; 109 | continue; 110 | } 111 | } else if (!luringcb->qiov) { 112 | @@ -194,6 +198,7 @@ static void luring_process_completions(LuringState *s) 113 | if (luringcb->is_read) { 114 | if (ret > 0) { 115 | luring_resubmit_short_read(s, luringcb, ret); 116 | + resubmit = true; 117 | continue; 118 | } else { 119 | /* Pad with zeroes */ 120 | @@ -224,6 +229,8 @@ end: 121 | qemu_bh_cancel(s->completion_bh); 122 | 123 | defer_call_end(); 124 | + 125 | + return resubmit; 126 | } 127 | 128 | static int ioq_submit(LuringState *s) 129 | @@ -231,6 +238,7 @@ static int ioq_submit(LuringState *s) 130 | int ret = 0; 131 | LuringAIOCB *luringcb, *luringcb_next; 132 | 133 | +resubmit: 134 | while (s->io_q.in_queue > 0) { 135 | /* 136 | * Try to fetch sqes from the ring for requests waiting in 137 | @@ -260,12 +268,14 @@ static int ioq_submit(LuringState *s) 138 | } 139 | s->io_q.blocked = (s->io_q.in_queue > 0); 140 | 141 | - if (s->io_q.in_flight) { 142 | + if (ret >= 0 && s->io_q.in_flight) { 143 | /* 144 | * We can try to complete something just right away if there are 145 | * still requests in-flight. 146 | */ 147 | - luring_process_completions(s); 148 | + if (luring_process_completions(s)) { 149 | + goto resubmit; 150 | + } 151 | } 152 | return ret; 153 | } 154 | -------------------------------------------------------------------------------- /debian/patches/pve/0013-PVE-virtio-balloon-improve-query-balloon.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Wolfgang Bumiller 3 | Date: Mon, 6 Apr 2020 12:16:43 +0200 4 | Subject: [PATCH] PVE: virtio-balloon: improve query-balloon 5 | 6 | Actually provide memory information via the query-balloon 7 | command. 8 | 9 | Signed-off-by: Thomas Lamprecht 10 | [FE: add BalloonInfo to member name exceptions list 11 | rebase for 8.0 - moved to hw/core/machine-hmp-cmds.c] 12 | Signed-off-by: Fiona Ebner 13 | --- 14 | hw/core/machine-hmp-cmds.c | 30 +++++++++++++++++++++++++++++- 15 | hw/virtio/virtio-balloon.c | 33 +++++++++++++++++++++++++++++++-- 16 | qapi/machine.json | 22 +++++++++++++++++++++- 17 | qapi/pragma.json | 1 + 18 | 4 files changed, 82 insertions(+), 4 deletions(-) 19 | 20 | diff --git a/hw/core/machine-hmp-cmds.c b/hw/core/machine-hmp-cmds.c 21 | index 3a612e2232..036d87cc90 100644 22 | --- a/hw/core/machine-hmp-cmds.c 23 | +++ b/hw/core/machine-hmp-cmds.c 24 | @@ -182,7 +182,35 @@ void hmp_info_balloon(Monitor *mon, const QDict *qdict) 25 | return; 26 | } 27 | 28 | - monitor_printf(mon, "balloon: actual=%" PRId64 "\n", info->actual >> 20); 29 | + monitor_printf(mon, "balloon: actual=%" PRId64, info->actual >> 20); 30 | + monitor_printf(mon, " max_mem=%" PRId64, info->max_mem >> 20); 31 | + if (info->has_total_mem) { 32 | + monitor_printf(mon, " total_mem=%" PRId64, info->total_mem >> 20); 33 | + } 34 | + if (info->has_free_mem) { 35 | + monitor_printf(mon, " free_mem=%" PRId64, info->free_mem >> 20); 36 | + } 37 | + 38 | + if (info->has_mem_swapped_in) { 39 | + monitor_printf(mon, " mem_swapped_in=%" PRId64, info->mem_swapped_in); 40 | + } 41 | + if (info->has_mem_swapped_out) { 42 | + monitor_printf(mon, " mem_swapped_out=%" PRId64, info->mem_swapped_out); 43 | + } 44 | + if (info->has_major_page_faults) { 45 | + monitor_printf(mon, " major_page_faults=%" PRId64, 46 | + info->major_page_faults); 47 | + } 48 | + if (info->has_minor_page_faults) { 49 | + monitor_printf(mon, " minor_page_faults=%" PRId64, 50 | + info->minor_page_faults); 51 | + } 52 | + if (info->has_last_update) { 53 | + monitor_printf(mon, " last_update=%" PRId64, 54 | + info->last_update); 55 | + } 56 | + 57 | + monitor_printf(mon, "\n"); 58 | 59 | qapi_free_BalloonInfo(info); 60 | } 61 | diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c 62 | index db787d00b3..26ebf3a5ce 100644 63 | --- a/hw/virtio/virtio-balloon.c 64 | +++ b/hw/virtio/virtio-balloon.c 65 | @@ -795,8 +795,37 @@ static uint64_t virtio_balloon_get_features(VirtIODevice *vdev, uint64_t f, 66 | static void virtio_balloon_stat(void *opaque, BalloonInfo *info) 67 | { 68 | VirtIOBalloon *dev = opaque; 69 | - info->actual = get_current_ram_size() - ((uint64_t) dev->actual << 70 | - VIRTIO_BALLOON_PFN_SHIFT); 71 | + ram_addr_t ram_size = get_current_ram_size(); 72 | + info->actual = ram_size - ((uint64_t) dev->actual << 73 | + VIRTIO_BALLOON_PFN_SHIFT); 74 | + 75 | + info->max_mem = ram_size; 76 | + 77 | + if (!(balloon_stats_enabled(dev) && balloon_stats_supported(dev) && 78 | + dev->stats_last_update)) { 79 | + return; 80 | + } 81 | + 82 | + info->last_update = dev->stats_last_update; 83 | + info->has_last_update = true; 84 | + 85 | + info->mem_swapped_in = dev->stats[VIRTIO_BALLOON_S_SWAP_IN]; 86 | + info->has_mem_swapped_in = info->mem_swapped_in >= 0 ? true : false; 87 | + 88 | + info->mem_swapped_out = dev->stats[VIRTIO_BALLOON_S_SWAP_OUT]; 89 | + info->has_mem_swapped_out = info->mem_swapped_out >= 0 ? true : false; 90 | + 91 | + info->major_page_faults = dev->stats[VIRTIO_BALLOON_S_MAJFLT]; 92 | + info->has_major_page_faults = info->major_page_faults >= 0 ? true : false; 93 | + 94 | + info->minor_page_faults = dev->stats[VIRTIO_BALLOON_S_MINFLT]; 95 | + info->has_minor_page_faults = info->minor_page_faults >= 0 ? true : false; 96 | + 97 | + info->free_mem = dev->stats[VIRTIO_BALLOON_S_MEMFREE]; 98 | + info->has_free_mem = info->free_mem >= 0 ? true : false; 99 | + 100 | + info->total_mem = dev->stats[VIRTIO_BALLOON_S_MEMTOT]; 101 | + info->has_total_mem = info->total_mem >= 0 ? true : false; 102 | } 103 | 104 | static void virtio_balloon_to_target(void *opaque, ram_addr_t target) 105 | diff --git a/qapi/machine.json b/qapi/machine.json 106 | index 038eab281c..5f172ece18 100644 107 | --- a/qapi/machine.json 108 | +++ b/qapi/machine.json 109 | @@ -1125,9 +1125,29 @@ 110 | # @actual: the logical size of the VM in bytes. Formula used: 111 | # logical_vm_size = vm_ram_size - balloon_size 112 | # 113 | +# @last_update: time when stats got updated from guest 114 | +# 115 | +# @mem_swapped_in: number of pages swapped in within the guest 116 | +# 117 | +# @mem_swapped_out: number of pages swapped out within the guest 118 | +# 119 | +# @major_page_faults: number of major page faults within the guest 120 | +# 121 | +# @minor_page_faults: number of minor page faults within the guest 122 | +# 123 | +# @free_mem: amount of memory (in bytes) free in the guest 124 | +# 125 | +# @total_mem: amount of memory (in bytes) visible to the guest 126 | +# 127 | +# @max_mem: amount of memory (in bytes) assigned to the guest 128 | +# 129 | # Since: 0.14 130 | ## 131 | -{ 'struct': 'BalloonInfo', 'data': {'actual': 'int' } } 132 | +{ 'struct': 'BalloonInfo', 133 | + 'data': {'actual': 'int', '*last_update': 'int', '*mem_swapped_in': 'int', 134 | + '*mem_swapped_out': 'int', '*major_page_faults': 'int', 135 | + '*minor_page_faults': 'int', '*free_mem': 'int', 136 | + '*total_mem': 'int', 'max_mem': 'int' } } 137 | 138 | ## 139 | # @query-balloon: 140 | diff --git a/qapi/pragma.json b/qapi/pragma.json 141 | index 023a2ef7bc..6aaa9cb975 100644 142 | --- a/qapi/pragma.json 143 | +++ b/qapi/pragma.json 144 | @@ -81,6 +81,7 @@ 145 | 'member-name-exceptions': [ # visible in: 146 | 'ACPISlotType', # query-acpi-ospm-status 147 | 'AcpiTableOptions', # -acpitable 148 | + 'BalloonInfo', # query-balloon 149 | 'BlkdebugEvent', # blockdev-add, -blockdev 150 | 'BlkdebugSetStateOptions', # blockdev-add, -blockdev 151 | 'BlockDeviceInfo', # query-block 152 | -------------------------------------------------------------------------------- /debian/patches/pve/0047-savevm-async-reuse-migration-blocker-check-for-snaps.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Fiona Ebner 3 | Date: Wed, 18 Jun 2025 12:25:31 +0200 4 | Subject: [PATCH] savevm-async: reuse migration blocker check for 5 | snapshots/hibernation 6 | 7 | Same rationale as with upstream QEMU commit 5aaac46793 ("migration: 8 | savevm: consult migration blockers"), migration and (async) snapshot 9 | are essentially the same operation and thus snapshot also needs to 10 | check for migration blockers. For example, this catches passed-through 11 | PCI devices, where the driver does not support migration and VirtIO-GL 12 | display, which also does not support migration yet. 13 | 14 | In the case of VirtIO-GL, there were crashes [0]. 15 | 16 | However, the commit notes: 17 | 18 | > There is really no difference between live migration and savevm, except 19 | > that savevm does not require bdrv_invalidate_cache to be implemented 20 | > by all disks. However, it is unlikely that savevm is used with anything 21 | > except qcow2 disks, so the penalty is small and worth the improvement 22 | > in catching bad usage of savevm. 23 | 24 | and for Proxmox VE, suspend-to-disk with VMDK does use savevm-async 25 | and would be broken by simply using migration_is_blocked(). To keep 26 | this working, introduce a new helper that filters blockers with the 27 | prefix used by the VMDK migration blocker. 28 | 29 | The function qemu_savevm_state_blocked() is called as part of 30 | savevm_async_is_blocked() so no check is lost with this 31 | patch. The helper is declared in migration/migration.c to be able to 32 | access the 'migration_blockers'. 33 | 34 | The VMDK blocker message is declared via a '#define', because using a 35 | 'const char*' led to the linker to complain about multiple 36 | declarations. The message does not include the reference to the block 37 | node anymore, but users can still easily find a VMDK disk in the VM 38 | configuration. 39 | 40 | Note, this also "breaks" snapshot and hibernate with VNC clipboard by 41 | preventing it. Previously, this would "work", because the Proxmox VE 42 | API has no check yet, but the clipboard will be broken after rollback, 43 | in the sense that it cannot be used anymore, not just lost contents. 44 | So some users might consider adding the check here a breaking change 45 | even if it's technically correct to prevent snapshot and hibernate 46 | with VNC clipboard. But other users might rightfully complain about 47 | broken clipboard. And again, the check also prevents blockers from 48 | passed-through PCI devices, etc. so it seems worth tolerating that 49 | breakage. 50 | 51 | [0]: https://forum.proxmox.com/threads/136976/ 52 | 53 | Signed-off-by: Fiona Ebner 54 | Message-ID: <20250618102531.57444-1-f.ebner@proxmox.com> 55 | --- 56 | block/vmdk.c | 4 +--- 57 | include/migration/blocker.h | 2 ++ 58 | migration/migration.c | 24 ++++++++++++++++++++++++ 59 | migration/migration.h | 1 + 60 | migration/savevm-async.c | 2 +- 61 | 5 files changed, 29 insertions(+), 4 deletions(-) 62 | 63 | diff --git a/block/vmdk.c b/block/vmdk.c 64 | index 7b98debc2b..2af32f3d5d 100644 65 | --- a/block/vmdk.c 66 | +++ b/block/vmdk.c 67 | @@ -1404,9 +1404,7 @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags, 68 | qemu_co_mutex_init(&s->lock); 69 | 70 | /* Disable migration when VMDK images are used */ 71 | - error_setg(&s->migration_blocker, "The vmdk format used by node '%s' " 72 | - "does not support live migration", 73 | - bdrv_get_device_or_node_name(bs)); 74 | + error_setg(&s->migration_blocker, "%s", MIGRATION_BLOCKER_VMDK); 75 | ret = migrate_add_blocker_normal(&s->migration_blocker, errp); 76 | if (ret < 0) { 77 | goto fail; 78 | diff --git a/include/migration/blocker.h b/include/migration/blocker.h 79 | index a687ac0efe..f36bfb2df1 100644 80 | --- a/include/migration/blocker.h 81 | +++ b/include/migration/blocker.h 82 | @@ -18,6 +18,8 @@ 83 | 84 | #define MIG_MODE_ALL MIG_MODE__MAX 85 | 86 | +#define MIGRATION_BLOCKER_VMDK "The vmdk format used by a disk does not support live migration" 87 | + 88 | /** 89 | * @migrate_add_blocker - prevent all modes of migration from proceeding 90 | * 91 | diff --git a/migration/migration.c b/migration/migration.c 92 | index 60464d43c3..998a7f87b8 100644 93 | --- a/migration/migration.c 94 | +++ b/migration/migration.c 95 | @@ -2055,6 +2055,30 @@ bool migration_is_blocked(Error **errp) 96 | return false; 97 | } 98 | 99 | +bool savevm_async_is_blocked(Error **errp) 100 | +{ 101 | + GSList *blockers = migration_blockers[migrate_mode()]; 102 | + 103 | + if (qemu_savevm_state_blocked(errp)) { 104 | + return true; 105 | + } 106 | + 107 | + /* 108 | + * The limitation for VMDK images only applies to live-migration, not 109 | + * snapshots, see commit 5aaac46793 ("migration: savevm: consult migration 110 | + * blockers"). 111 | + */ 112 | + while (blockers) { 113 | + if (strcmp(error_get_pretty(blockers->data), MIGRATION_BLOCKER_VMDK)) { 114 | + error_propagate(errp, error_copy(blockers->data)); 115 | + return true; 116 | + } 117 | + blockers = g_slist_next(blockers); 118 | + } 119 | + 120 | + return false; 121 | +} 122 | + 123 | /* Returns true if continue to migrate, or false if error detected */ 124 | static bool migrate_prepare(MigrationState *s, bool resume, Error **errp) 125 | { 126 | diff --git a/migration/migration.h b/migration/migration.h 127 | index 01329bf824..a805e98a30 100644 128 | --- a/migration/migration.h 129 | +++ b/migration/migration.h 130 | @@ -531,6 +531,7 @@ int migration_call_notifiers(MigrationState *s, MigrationEventType type, 131 | 132 | int migrate_init(MigrationState *s, Error **errp); 133 | bool migration_is_blocked(Error **errp); 134 | +bool savevm_async_is_blocked(Error **errp); 135 | /* True if outgoing migration has entered postcopy phase */ 136 | bool migration_in_postcopy(void); 137 | bool migration_postcopy_is_alive(MigrationStatus state); 138 | diff --git a/migration/savevm-async.c b/migration/savevm-async.c 139 | index 730b815494..6cb91dca27 100644 140 | --- a/migration/savevm-async.c 141 | +++ b/migration/savevm-async.c 142 | @@ -375,7 +375,7 @@ void qmp_savevm_start(const char *statefile, Error **errp) 143 | return; 144 | } 145 | 146 | - if (qemu_savevm_state_blocked(errp)) { 147 | + if (savevm_async_is_blocked(errp)) { 148 | goto fail; 149 | } 150 | 151 | -------------------------------------------------------------------------------- /debian/patches/pve/0034-PVE-Migrate-dirty-bitmap-state-via-savevm.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Stefan Reiter 3 | Date: Thu, 22 Oct 2020 17:34:18 +0200 4 | Subject: [PATCH] PVE: Migrate dirty bitmap state via savevm 5 | 6 | QEMU provides 'savevm' registrations as a mechanism for arbitrary state 7 | to be migrated along with a VM. Use this to send a serialized version of 8 | dirty bitmap state data from proxmox-backup-qemu, and restore it on the 9 | target node. 10 | 11 | Also add a flag to query-proxmox-support so qemu-server can determine if 12 | safe migration is possible and makes sense. 13 | 14 | Signed-off-by: Stefan Reiter 15 | Signed-off-by: Thomas Lamprecht 16 | [FE: split up state_pending for 8.0] 17 | Signed-off-by: Fiona Ebner 18 | --- 19 | include/migration/misc.h | 3 ++ 20 | migration/meson.build | 2 + 21 | migration/migration.c | 1 + 22 | migration/pbs-state.c | 104 +++++++++++++++++++++++++++++++++++++++ 23 | pve-backup.c | 1 + 24 | qapi/block-core.json | 6 +++ 25 | 6 files changed, 117 insertions(+) 26 | create mode 100644 migration/pbs-state.c 27 | 28 | diff --git a/include/migration/misc.h b/include/migration/misc.h 29 | index a261f99d89..e8c6a87305 100644 30 | --- a/include/migration/misc.h 31 | +++ b/include/migration/misc.h 32 | @@ -140,4 +140,7 @@ bool multifd_device_state_save_thread_should_exit(void); 33 | void multifd_abort_device_state_save_threads(void); 34 | bool multifd_join_device_state_save_threads(void); 35 | 36 | +/* migration/pbs-state.c */ 37 | +void pbs_state_mig_init(void); 38 | + 39 | #endif 40 | diff --git a/migration/meson.build b/migration/meson.build 41 | index 409b748980..ca94e7e17b 100644 42 | --- a/migration/meson.build 43 | +++ b/migration/meson.build 44 | @@ -8,6 +8,7 @@ migration_files = files( 45 | 'qemu-file.c', 46 | 'yank_functions.c', 47 | ) 48 | +system_ss.add(libproxmox_backup_qemu) 49 | 50 | system_ss.add(files( 51 | 'block-dirty-bitmap.c', 52 | @@ -31,6 +32,7 @@ system_ss.add(files( 53 | 'multifd-zlib.c', 54 | 'multifd-zero-page.c', 55 | 'options.c', 56 | + 'pbs-state.c', 57 | 'postcopy-ram.c', 58 | 'savevm.c', 59 | 'savevm-async.c', 60 | diff --git a/migration/migration.c b/migration/migration.c 61 | index 32b8ce5613..60464d43c3 100644 62 | --- a/migration/migration.c 63 | +++ b/migration/migration.c 64 | @@ -340,6 +340,7 @@ void migration_object_init(void) 65 | 66 | /* Initialize cpu throttle timers */ 67 | cpu_throttle_init(); 68 | + pbs_state_mig_init(); 69 | } 70 | 71 | typedef struct { 72 | diff --git a/migration/pbs-state.c b/migration/pbs-state.c 73 | new file mode 100644 74 | index 0000000000..a97187e4d7 75 | --- /dev/null 76 | +++ b/migration/pbs-state.c 77 | @@ -0,0 +1,104 @@ 78 | +/* 79 | + * PBS (dirty-bitmap) state migration 80 | + */ 81 | + 82 | +#include "qemu/osdep.h" 83 | +#include "migration/misc.h" 84 | +#include "qemu-file.h" 85 | +#include "migration/vmstate.h" 86 | +#include "migration/register.h" 87 | +#include "proxmox-backup-qemu.h" 88 | + 89 | +typedef struct PBSState { 90 | + bool active; 91 | +} PBSState; 92 | + 93 | +/* state is accessed via this static variable directly, 'opaque' is NULL */ 94 | +static PBSState pbs_state; 95 | + 96 | +static void pbs_state_pending(void *opaque, uint64_t *must_precopy, 97 | + uint64_t *can_postcopy) 98 | +{ 99 | + /* we send everything in save_setup, so nothing is ever pending */ 100 | +} 101 | + 102 | +/* receive PBS state via f and deserialize, called on target */ 103 | +static int pbs_state_load(QEMUFile *f, void *opaque, int version_id) 104 | +{ 105 | + /* safe cast, we cannot migrate to target with less bits than source */ 106 | + size_t buf_size = (size_t)qemu_get_be64(f); 107 | + 108 | + uint8_t *buf = (uint8_t *)malloc(buf_size); 109 | + size_t read = qemu_get_buffer(f, buf, buf_size); 110 | + 111 | + if (read < buf_size) { 112 | + fprintf(stderr, "error receiving PBS state: not enough data\n"); 113 | + return -EIO; 114 | + } 115 | + 116 | + proxmox_import_state(buf, buf_size); 117 | + 118 | + free(buf); 119 | + return 0; 120 | +} 121 | + 122 | +/* serialize PBS state and send to target via f, called on source */ 123 | +static int pbs_state_save_setup(QEMUFile *f, void *opaque, Error **errp) 124 | +{ 125 | + size_t buf_size; 126 | + uint8_t *buf = proxmox_export_state(&buf_size); 127 | + 128 | + /* LV encoding */ 129 | + qemu_put_be64(f, buf_size); 130 | + qemu_put_buffer(f, buf, buf_size); 131 | + 132 | + proxmox_free_state_buf(buf); 133 | + pbs_state.active = false; 134 | + return 0; 135 | +} 136 | + 137 | +static bool pbs_state_is_active(void *opaque) 138 | +{ 139 | + /* we need to return active exactly once, else .save_setup is never called, 140 | + * but if we'd just return true the migration doesn't make progress since 141 | + * it'd be waiting for us */ 142 | + return pbs_state.active; 143 | +} 144 | + 145 | +static bool pbs_state_is_active_iterate(void *opaque) 146 | +{ 147 | + /* we don't iterate, everything is sent in save_setup */ 148 | + return pbs_state_is_active(opaque); 149 | +} 150 | + 151 | +static bool pbs_state_has_postcopy(void *opaque) 152 | +{ 153 | + /* PBS state can't change during a migration (since that's blocking any 154 | + * potential backups), so we can copy everything before the VM is stopped */ 155 | + return false; 156 | +} 157 | + 158 | +static void pbs_state_save_cleanup(void *opaque) 159 | +{ 160 | + /* reset active after migration succeeds or fails */ 161 | + pbs_state.active = false; 162 | +} 163 | + 164 | +static SaveVMHandlers savevm_pbs_state_handlers = { 165 | + .save_setup = pbs_state_save_setup, 166 | + .has_postcopy = pbs_state_has_postcopy, 167 | + .state_pending_exact = pbs_state_pending, 168 | + .state_pending_estimate = pbs_state_pending, 169 | + .is_active_iterate = pbs_state_is_active_iterate, 170 | + .load_state = pbs_state_load, 171 | + .is_active = pbs_state_is_active, 172 | + .save_cleanup = pbs_state_save_cleanup, 173 | +}; 174 | + 175 | +void pbs_state_mig_init(void) 176 | +{ 177 | + pbs_state.active = true; 178 | + register_savevm_live("pbs-state", 0, 1, 179 | + &savevm_pbs_state_handlers, 180 | + NULL); 181 | +} 182 | diff --git a/pve-backup.c b/pve-backup.c 183 | index 177fb851b4..7575abab7c 100644 184 | --- a/pve-backup.c 185 | +++ b/pve-backup.c 186 | @@ -1089,6 +1089,7 @@ ProxmoxSupportStatus *qmp_query_proxmox_support(Error **errp) 187 | ret->pbs_library_version = g_strdup(proxmox_backup_qemu_version()); 188 | ret->pbs_dirty_bitmap = true; 189 | ret->pbs_dirty_bitmap_savevm = true; 190 | + ret->pbs_dirty_bitmap_migration = true; 191 | ret->query_bitmap_info = true; 192 | ret->pbs_masterkey = true; 193 | ret->backup_max_workers = true; 194 | diff --git a/qapi/block-core.json b/qapi/block-core.json 195 | index e6b8ba49b2..be6bf25219 100644 196 | --- a/qapi/block-core.json 197 | +++ b/qapi/block-core.json 198 | @@ -1032,6 +1032,11 @@ 199 | # @pbs-dirty-bitmap-savevm: True if 'dirty-bitmaps' migration capability can 200 | # safely be set for savevm-async. 201 | # 202 | +# @pbs-dirty-bitmap-migration: True if safe migration of dirty-bitmaps including 203 | +# PBS state is supported. Enabling 'dirty-bitmaps' 204 | +# migration cap if this is false/unset may lead 205 | +# to crashes on migration! 206 | +# 207 | # @pbs-masterkey: True if the QMP backup call supports the 'master_keyfile' 208 | # parameter. 209 | # 210 | @@ -1045,6 +1050,7 @@ 211 | 'data': { 'pbs-dirty-bitmap': 'bool', 212 | 'query-bitmap-info': 'bool', 213 | 'pbs-dirty-bitmap-savevm': 'bool', 214 | + 'pbs-dirty-bitmap-migration': 'bool', 215 | 'pbs-masterkey': 'bool', 216 | 'pbs-library-version': 'str', 217 | 'backup-max-workers': 'bool' } } 218 | -------------------------------------------------------------------------------- /debian/patches/pve/0018-PVE-add-optional-buffer-size-to-QEMUFile.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Wolfgang Bumiller 3 | Date: Mon, 4 May 2020 11:05:08 +0200 4 | Subject: [PATCH] PVE: add optional buffer size to QEMUFile 5 | 6 | So we can use a 4M buffer for savevm-async which should 7 | increase performance storing the state onto ceph. 8 | 9 | Signed-off-by: Wolfgang Bumiller 10 | [increase max IOV count in QEMUFile to actually write more data] 11 | Signed-off-by: Stefan Reiter 12 | Signed-off-by: Thomas Lamprecht 13 | [FE: adapt to removal of QEMUFileOps] 14 | Signed-off-by: Fiona Ebner 15 | --- 16 | migration/qemu-file.c | 48 +++++++++++++++++++++++++++------------- 17 | migration/qemu-file.h | 2 ++ 18 | migration/savevm-async.c | 5 +++-- 19 | 3 files changed, 38 insertions(+), 17 deletions(-) 20 | 21 | diff --git a/migration/qemu-file.c b/migration/qemu-file.c 22 | index b6ac190034..46d899edb0 100644 23 | --- a/migration/qemu-file.c 24 | +++ b/migration/qemu-file.c 25 | @@ -34,8 +34,8 @@ 26 | #include "rdma.h" 27 | #include "io/channel-file.h" 28 | 29 | -#define IO_BUF_SIZE 32768 30 | -#define MAX_IOV_SIZE MIN_CONST(IOV_MAX, 64) 31 | +#define DEFAULT_IO_BUF_SIZE 32768 32 | +#define MAX_IOV_SIZE MIN_CONST(IOV_MAX, 256) 33 | 34 | typedef struct FdEntry { 35 | QTAILQ_ENTRY(FdEntry) entry; 36 | @@ -48,7 +48,8 @@ struct QEMUFile { 37 | 38 | int buf_index; 39 | int buf_size; /* 0 when writing */ 40 | - uint8_t buf[IO_BUF_SIZE]; 41 | + size_t buf_allocated_size; 42 | + uint8_t *buf; 43 | 44 | DECLARE_BITMAP(may_free, MAX_IOV_SIZE); 45 | struct iovec iov[MAX_IOV_SIZE]; 46 | @@ -108,7 +109,9 @@ int qemu_file_shutdown(QEMUFile *f) 47 | return 0; 48 | } 49 | 50 | -static QEMUFile *qemu_file_new_impl(QIOChannel *ioc, bool is_writable) 51 | +static QEMUFile *qemu_file_new_impl(QIOChannel *ioc, 52 | + bool is_writable, 53 | + size_t buffer_size) 54 | { 55 | QEMUFile *f; 56 | 57 | @@ -119,6 +122,8 @@ static QEMUFile *qemu_file_new_impl(QIOChannel *ioc, bool is_writable) 58 | f->is_writable = is_writable; 59 | f->can_pass_fd = qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_FD_PASS); 60 | QTAILQ_INIT(&f->fds); 61 | + f->buf_allocated_size = buffer_size; 62 | + f->buf = malloc(buffer_size); 63 | 64 | return f; 65 | } 66 | @@ -129,17 +134,27 @@ static QEMUFile *qemu_file_new_impl(QIOChannel *ioc, bool is_writable) 67 | */ 68 | QEMUFile *qemu_file_get_return_path(QEMUFile *f) 69 | { 70 | - return qemu_file_new_impl(f->ioc, !f->is_writable); 71 | + return qemu_file_new_impl(f->ioc, !f->is_writable, DEFAULT_IO_BUF_SIZE); 72 | } 73 | 74 | QEMUFile *qemu_file_new_output(QIOChannel *ioc) 75 | { 76 | - return qemu_file_new_impl(ioc, true); 77 | + return qemu_file_new_impl(ioc, true, DEFAULT_IO_BUF_SIZE); 78 | +} 79 | + 80 | +QEMUFile *qemu_file_new_output_sized(QIOChannel *ioc, size_t buffer_size) 81 | +{ 82 | + return qemu_file_new_impl(ioc, true, buffer_size); 83 | } 84 | 85 | QEMUFile *qemu_file_new_input(QIOChannel *ioc) 86 | { 87 | - return qemu_file_new_impl(ioc, false); 88 | + return qemu_file_new_impl(ioc, false, DEFAULT_IO_BUF_SIZE); 89 | +} 90 | + 91 | +QEMUFile *qemu_file_new_input_sized(QIOChannel *ioc, size_t buffer_size) 92 | +{ 93 | + return qemu_file_new_impl(ioc, false, buffer_size); 94 | } 95 | 96 | /* 97 | @@ -339,7 +354,7 @@ static ssize_t coroutine_mixed_fn qemu_fill_buffer(QEMUFile *f) 98 | } 99 | 100 | do { 101 | - struct iovec iov = { f->buf + pending, IO_BUF_SIZE - pending }; 102 | + struct iovec iov = { f->buf + pending, f->buf_allocated_size - pending }; 103 | len = qio_channel_readv_full(f->ioc, &iov, 1, pfds, pnfd, 0, 104 | &local_error); 105 | if (len == QIO_CHANNEL_ERR_BLOCK) { 106 | @@ -443,6 +458,9 @@ int qemu_fclose(QEMUFile *f) 107 | g_free(fde); 108 | } 109 | g_clear_pointer(&f->ioc, object_unref); 110 | + 111 | + free(f->buf); 112 | + 113 | error_free(f->last_error_obj); 114 | g_free(f); 115 | trace_qemu_file_fclose(); 116 | @@ -491,7 +509,7 @@ static void add_buf_to_iovec(QEMUFile *f, size_t len) 117 | { 118 | if (!add_to_iovec(f, f->buf + f->buf_index, len, false)) { 119 | f->buf_index += len; 120 | - if (f->buf_index == IO_BUF_SIZE) { 121 | + if (f->buf_index == f->buf_allocated_size) { 122 | qemu_fflush(f); 123 | } 124 | } 125 | @@ -516,7 +534,7 @@ void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, size_t size) 126 | } 127 | 128 | while (size > 0) { 129 | - l = IO_BUF_SIZE - f->buf_index; 130 | + l = f->buf_allocated_size - f->buf_index; 131 | if (l > size) { 132 | l = size; 133 | } 134 | @@ -660,8 +678,8 @@ size_t coroutine_mixed_fn qemu_peek_buffer(QEMUFile *f, uint8_t **buf, size_t si 135 | size_t index; 136 | 137 | assert(!qemu_file_is_writable(f)); 138 | - assert(offset < IO_BUF_SIZE); 139 | - assert(size <= IO_BUF_SIZE - offset); 140 | + assert(offset < f->buf_allocated_size); 141 | + assert(size <= f->buf_allocated_size - offset); 142 | 143 | /* The 1st byte to read from */ 144 | index = f->buf_index + offset; 145 | @@ -711,7 +729,7 @@ size_t coroutine_mixed_fn qemu_get_buffer(QEMUFile *f, uint8_t *buf, size_t size 146 | size_t res; 147 | uint8_t *src; 148 | 149 | - res = qemu_peek_buffer(f, &src, MIN(pending, IO_BUF_SIZE), 0); 150 | + res = qemu_peek_buffer(f, &src, MIN(pending, f->buf_allocated_size), 0); 151 | if (res == 0) { 152 | return done; 153 | } 154 | @@ -745,7 +763,7 @@ size_t coroutine_mixed_fn qemu_get_buffer(QEMUFile *f, uint8_t *buf, size_t size 155 | */ 156 | size_t coroutine_mixed_fn qemu_get_buffer_in_place(QEMUFile *f, uint8_t **buf, size_t size) 157 | { 158 | - if (size < IO_BUF_SIZE) { 159 | + if (size < f->buf_allocated_size) { 160 | size_t res; 161 | uint8_t *src = NULL; 162 | 163 | @@ -770,7 +788,7 @@ int coroutine_mixed_fn qemu_peek_byte(QEMUFile *f, int offset) 164 | int index = f->buf_index + offset; 165 | 166 | assert(!qemu_file_is_writable(f)); 167 | - assert(offset < IO_BUF_SIZE); 168 | + assert(offset < f->buf_allocated_size); 169 | 170 | if (index >= f->buf_size) { 171 | qemu_fill_buffer(f); 172 | diff --git a/migration/qemu-file.h b/migration/qemu-file.h 173 | index f5b9f430e0..0179b90698 100644 174 | --- a/migration/qemu-file.h 175 | +++ b/migration/qemu-file.h 176 | @@ -30,7 +30,9 @@ 177 | #include "io/channel.h" 178 | 179 | QEMUFile *qemu_file_new_input(QIOChannel *ioc); 180 | +QEMUFile *qemu_file_new_input_sized(QIOChannel *ioc, size_t buffer_size); 181 | QEMUFile *qemu_file_new_output(QIOChannel *ioc); 182 | +QEMUFile *qemu_file_new_output_sized(QIOChannel *ioc, size_t buffer_size); 183 | int qemu_fclose(QEMUFile *f); 184 | 185 | G_DEFINE_AUTOPTR_CLEANUP_FUNC(QEMUFile, qemu_fclose) 186 | diff --git a/migration/savevm-async.c b/migration/savevm-async.c 187 | index 56e0fa6c69..730b815494 100644 188 | --- a/migration/savevm-async.c 189 | +++ b/migration/savevm-async.c 190 | @@ -409,7 +409,7 @@ void qmp_savevm_start(const char *statefile, Error **errp) 191 | 192 | QIOChannel *ioc = QIO_CHANNEL(qio_channel_savevm_async_new(snap_state.target, 193 | &snap_state.bs_pos)); 194 | - snap_state.file = qemu_file_new_output(ioc); 195 | + snap_state.file = qemu_file_new_output_sized(ioc, 4 * 1024 * 1024); 196 | 197 | if (!snap_state.file) { 198 | error_setg(errp, "failed to open '%s'", statefile); 199 | @@ -544,7 +544,8 @@ int load_snapshot_from_blockdev(const char *filename, Error **errp) 200 | bdrv_op_block_all(bs, blocker); 201 | 202 | /* restore the VM state */ 203 | - f = qemu_file_new_input(QIO_CHANNEL(qio_channel_savevm_async_new(be, &bs_pos))); 204 | + f = qemu_file_new_input_sized(QIO_CHANNEL(qio_channel_savevm_async_new(be, &bs_pos)), 205 | + 4 * 1024 * 1024); 206 | if (!f) { 207 | error_setg(errp, "Could not open VM state file"); 208 | goto the_end; 209 | -------------------------------------------------------------------------------- /debian/patches/extra/0001-monitor-qmp-fix-race-with-clients-disconnecting-earl.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Stefan Reiter 3 | Date: Mon, 23 Aug 2021 11:28:32 +0200 4 | Subject: [PATCH] monitor/qmp: fix race with clients disconnecting early 5 | 6 | The following sequence can produce a race condition that results in 7 | responses meant for different clients being sent to the wrong one: 8 | 9 | (QMP, no OOB) 10 | 1) client A connects 11 | 2) client A sends 'qmp_capabilities' 12 | 3) 'qmp_dispatch' runs in coroutine, schedules out to 13 | 'do_qmp_dispatch_bh' and yields 14 | 4) client A disconnects (i.e. aborts, crashes, etc...) 15 | 5) client B connects 16 | 6) 'do_qmp_dispatch_bh' runs 'qmp_capabilities' and wakes calling coroutine 17 | 7) capabilities are now set and 'mon->commands' is set to '&qmp_commands' 18 | 8) 'qmp_dispatch' returns to 'monitor_qmp_dispatch' 19 | 9) success message is sent to client B *without it ever having sent 20 | 'qmp_capabilities' itself* 21 | 9a) even if client B ignores it, it will now presumably send it's own 22 | greeting, which will error because caps are already set 23 | 24 | The fix proposed here uses an atomic, sequential connection number 25 | stored in the MonitorQMP struct, which is incremented everytime a new 26 | client connects. Since it is not changed on CHR_EVENT_CLOSED, the 27 | behaviour of allowing a client to disconnect only one side of the 28 | connection is retained. 29 | 30 | The connection_nr needs to be exposed outside of the monitor subsystem, 31 | since qmp_dispatch lives in qapi code. It needs to be checked twice, 32 | once for actually running the command in the BH (fixes 7), and once for 33 | sending back a response (fixes 9). 34 | 35 | This satisfies my local reproducer - using multiple clients constantly 36 | looping to open a connection, send the greeting, then exiting no longer 37 | crashes other, normally behaving clients with unrelated responses. 38 | 39 | Signed-off-by: Stefan Reiter 40 | Signed-off-by: Thomas Lamprecht 41 | --- 42 | include/monitor/monitor.h | 1 + 43 | monitor/monitor-internal.h | 7 +++++++ 44 | monitor/monitor.c | 15 +++++++++++++++ 45 | monitor/qmp.c | 15 ++++++++++++++- 46 | qapi/qmp-dispatch.c | 21 +++++++++++++++++---- 47 | stubs/monitor-core.c | 5 +++++ 48 | 6 files changed, 59 insertions(+), 5 deletions(-) 49 | 50 | diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h 51 | index c3740ec616..7f38ce6b8b 100644 52 | --- a/include/monitor/monitor.h 53 | +++ b/include/monitor/monitor.h 54 | @@ -16,6 +16,7 @@ extern QemuOptsList qemu_mon_opts; 55 | Monitor *monitor_cur(void); 56 | Monitor *monitor_set_cur(Coroutine *co, Monitor *mon); 57 | bool monitor_cur_is_qmp(void); 58 | +int monitor_get_connection_nr(const Monitor *mon); 59 | 60 | void monitor_init_globals(void); 61 | void monitor_init_globals_core(void); 62 | diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h 63 | index 5676eb334e..4c452a6aeb 100644 64 | --- a/monitor/monitor-internal.h 65 | +++ b/monitor/monitor-internal.h 66 | @@ -151,6 +151,13 @@ typedef struct { 67 | QemuMutex qmp_queue_lock; 68 | /* Input queue that holds all the parsed QMP requests */ 69 | GQueue *qmp_requests; 70 | + 71 | + /* 72 | + * A sequential number that gets incremented on every new CHR_EVENT_OPENED. 73 | + * Used to avoid leftover responses in BHs from being sent to the wrong 74 | + * client. Access with atomics. 75 | + */ 76 | + int connection_nr; 77 | } MonitorQMP; 78 | 79 | /** 80 | diff --git a/monitor/monitor.c b/monitor/monitor.c 81 | index c5a5d30877..07775784d4 100644 82 | --- a/monitor/monitor.c 83 | +++ b/monitor/monitor.c 84 | @@ -116,6 +116,21 @@ bool monitor_cur_is_qmp(void) 85 | return cur_mon && monitor_is_qmp(cur_mon); 86 | } 87 | 88 | +/** 89 | + * If @mon is a QMP monitor, return the connection_nr, otherwise -1. 90 | + */ 91 | +int monitor_get_connection_nr(const Monitor *mon) 92 | +{ 93 | + MonitorQMP *qmp_mon; 94 | + 95 | + if (!monitor_is_qmp(mon)) { 96 | + return -1; 97 | + } 98 | + 99 | + qmp_mon = container_of(mon, MonitorQMP, common); 100 | + return qatomic_read(&qmp_mon->connection_nr); 101 | +} 102 | + 103 | /** 104 | * Is @mon is using readline? 105 | * Note: not all HMP monitors use readline, e.g., gdbserver has a 106 | diff --git a/monitor/qmp.c b/monitor/qmp.c 107 | index cb99a12d94..170fef4531 100644 108 | --- a/monitor/qmp.c 109 | +++ b/monitor/qmp.c 110 | @@ -165,6 +165,8 @@ static void monitor_qmp_dispatch(MonitorQMP *mon, QObject *req) 111 | QDict *rsp; 112 | QDict *error; 113 | 114 | + int conn_nr_before = qatomic_read(&mon->connection_nr); 115 | + 116 | rsp = qmp_dispatch(mon->commands, req, qmp_oob_enabled(mon), 117 | &mon->common); 118 | 119 | @@ -180,7 +182,17 @@ static void monitor_qmp_dispatch(MonitorQMP *mon, QObject *req) 120 | } 121 | } 122 | 123 | - monitor_qmp_respond(mon, rsp); 124 | + /* 125 | + * qmp_dispatch might have yielded and waited for a BH, in which case there 126 | + * is a chance a new client connected in the meantime - if this happened, 127 | + * the command will not have been executed, but we also need to ensure that 128 | + * we don't send back a corresponding response on a line that no longer 129 | + * belongs to this request. 130 | + */ 131 | + if (conn_nr_before == qatomic_read(&mon->connection_nr)) { 132 | + monitor_qmp_respond(mon, rsp); 133 | + } 134 | + 135 | qobject_unref(rsp); 136 | } 137 | 138 | @@ -462,6 +474,7 @@ static void monitor_qmp_event(void *opaque, QEMUChrEvent event) 139 | 140 | switch (event) { 141 | case CHR_EVENT_OPENED: 142 | + qatomic_inc_fetch(&mon->connection_nr); 143 | mon->commands = &qmp_cap_negotiation_commands; 144 | monitor_qmp_caps_reset(mon); 145 | data = qmp_greeting(mon); 146 | diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c 147 | index e569224eae..eb03782e91 100644 148 | --- a/qapi/qmp-dispatch.c 149 | +++ b/qapi/qmp-dispatch.c 150 | @@ -117,16 +117,28 @@ typedef struct QmpDispatchBH { 151 | QObject **ret; 152 | Error **errp; 153 | Coroutine *co; 154 | + int conn_nr; 155 | } QmpDispatchBH; 156 | 157 | static void do_qmp_dispatch_bh(void *opaque) 158 | { 159 | QmpDispatchBH *data = opaque; 160 | 161 | - assert(monitor_cur() == NULL); 162 | - monitor_set_cur(qemu_coroutine_self(), data->cur_mon); 163 | - data->cmd->fn(data->args, data->ret, data->errp); 164 | - monitor_set_cur(qemu_coroutine_self(), NULL); 165 | + /* 166 | + * A QMP monitor tracks it's client with a connection number, if this 167 | + * changes during the scheduling delay of this BH, we must not execute the 168 | + * command. Otherwise a badly placed 'qmp_capabilities' might affect the 169 | + * connection state of a client it was never meant for. 170 | + */ 171 | + if (data->conn_nr == monitor_get_connection_nr(data->cur_mon)) { 172 | + assert(monitor_cur() == NULL); 173 | + monitor_set_cur(qemu_coroutine_self(), data->cur_mon); 174 | + data->cmd->fn(data->args, data->ret, data->errp); 175 | + monitor_set_cur(qemu_coroutine_self(), NULL); 176 | + } else { 177 | + error_setg(data->errp, "active monitor connection changed"); 178 | + } 179 | + 180 | aio_co_wake(data->co); 181 | } 182 | 183 | @@ -253,6 +265,7 @@ QDict *coroutine_mixed_fn qmp_dispatch(const QmpCommandList *cmds, QObject *requ 184 | .ret = &ret, 185 | .errp = &err, 186 | .co = qemu_coroutine_self(), 187 | + .conn_nr = monitor_get_connection_nr(cur_mon), 188 | }; 189 | aio_bh_schedule_oneshot(iohandler_get_aio_context(), do_qmp_dispatch_bh, 190 | &data); 191 | diff --git a/stubs/monitor-core.c b/stubs/monitor-core.c 192 | index 1894cdfe1f..d74d0459f0 100644 193 | --- a/stubs/monitor-core.c 194 | +++ b/stubs/monitor-core.c 195 | @@ -12,6 +12,11 @@ Monitor *monitor_set_cur(Coroutine *co, Monitor *mon) 196 | return NULL; 197 | } 198 | 199 | +int monitor_get_connection_nr(const Monitor *mon) 200 | +{ 201 | + return -1; 202 | +} 203 | + 204 | void qapi_event_emit(QAPIEvent event, QDict *qdict) 205 | { 206 | } 207 | -------------------------------------------------------------------------------- /debian/patches/pve/0040-adapt-machine-version-deprecation-for-Proxmox-VE.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Fiona Ebner 3 | Date: Fri, 3 Jan 2025 14:03:12 +0100 4 | Subject: [PATCH] adapt machine version deprecation for Proxmox VE 5 | 6 | In commit a35f8577a0 ("include/hw: add macros for deprecation & 7 | removal of versioned machines"), a new machine version deprecation and 8 | removal policy was introduced. After only 3 years a machine version 9 | will be deprecated while being removed after 6 years. 10 | 11 | The deprecation is a bit early considering major PVE releases are 12 | approximately every 2 years. This means that a deprecation warning can 13 | already happen for a machine version that was introduced during the 14 | previous major release. This would scare users for no good reason, so 15 | avoid deprecating machine versions in PVE too early and define a 16 | baseline of machine versions that will be supported throughout a 17 | single major PVE release. 18 | 19 | Signed-off-by: Fiona Ebner 20 | --- 21 | include/hw/boards.h | 99 ++++++++++++++++++++++++++------------------- 22 | 1 file changed, 58 insertions(+), 41 deletions(-) 23 | 24 | diff --git a/include/hw/boards.h b/include/hw/boards.h 25 | index 7a389f6998..0595a569d2 100644 26 | --- a/include/hw/boards.h 27 | +++ b/include/hw/boards.h 28 | @@ -636,40 +636,57 @@ struct MachineState { 29 | 30 | 31 | /* 32 | - * How many years/major releases for each phase 33 | - * of the life cycle. Assumes use of versioning 34 | - * scheme where major is bumped each year. 35 | + * Baseline of machine versions that are still considered supported throughout 36 | + * current major Proxmox VE release. Machine versions older than this are 37 | + * considered to be deprecated in Proxmox VE. 38 | * 39 | - * These values must match the ver_machine_deprecation_version 40 | - * and ver_machine_deletion_version logic in docs/conf.py and 41 | - * the text in docs/about/deprecated.rst 42 | + * Machine versions older than 6 years are removed just like in upstream QEMU. 43 | + * (policy takes effect with QEMU 10.1). Assumes yearly major QEMU release. 44 | + * 45 | + * QEMU release cylce N.0 in ~April, N.1 in ~August, N.2 in ~December 46 | + * Debian/PVE release cylce ~every two years in summer 47 | + * 48 | + * PVE - last QEMU - machine versions dropped - baseline 49 | + * 8 9.2 2.3 and older 2.4 50 | + * 9 11.2 5.2 and older 6.0 51 | + * 10 13.2 7.2 and older 8.0 52 | + */ 53 | +#define MACHINE_VER_BASELINE_PVE_MAJOR 6 54 | +#define MACHINE_VER_BASELINE_PVE_MINOR 0 55 | +#define MACHINE_VER_DELETION_MAJOR (QEMU_VERSION_MAJOR - 6) 56 | +#define MACHINE_VER_DELETION_MINOR QEMU_VERSION_MINOR 57 | + 58 | +/* 59 | + * Proxmox VE needs to support the baseline throughout a major PVE release. So 60 | + * a QEMU release where the baseline is already deleted cannot be used. 61 | */ 62 | -#define MACHINE_VER_DELETION_MAJOR 6 63 | -#define MACHINE_VER_DEPRECATION_MAJOR 3 64 | +#if ((MACHINE_VER_BASELINE_PVE_MAJOR < MACHINE_VER_DELETION_MAJOR) || \ 65 | + ((MACHINE_VER_BASELINE_PVE_MAJOR == MACHINE_VER_DELETION_MAJOR) && \ 66 | + (MACHINE_VER_BASELINE_PVE_MINOR < MACHINE_VER_DELETION_MINOR))) 67 | +#error "Baseline machine version needed by Proxmox VE not supported anymore by this QEMU release" 68 | +#endif 69 | 70 | /* 71 | * Expands to a static string containing a deprecation 72 | * message for a versioned machine type 73 | */ 74 | #define MACHINE_VER_DEPRECATION_MSG \ 75 | - "machines more than " stringify(MACHINE_VER_DEPRECATION_MAJOR) \ 76 | - " years old are subject to deletion after " \ 77 | - stringify(MACHINE_VER_DELETION_MAJOR) " years" 78 | + "old machine version is subject to deletion during current major Proxmox VE release" 79 | 80 | -#define _MACHINE_VER_IS_CURRENT_EXPIRED(cutoff, major, minor) \ 81 | - (((QEMU_VERSION_MAJOR - major) > cutoff) || \ 82 | - (((QEMU_VERSION_MAJOR - major) == cutoff) && \ 83 | - (QEMU_VERSION_MINOR - minor) >= 0)) 84 | +#define _MACHINE_VER_IS_CURRENT_EXPIRED(baseline_major, baseline_minor, major, minor) \ 85 | + ((major < baseline_major) || \ 86 | + ((major == baseline_major) && \ 87 | + (minor < baseline_minor))) 88 | 89 | -#define _MACHINE_VER_IS_NEXT_MINOR_EXPIRED(cutoff, major, minor) \ 90 | - (((QEMU_VERSION_MAJOR - major) > cutoff) || \ 91 | - (((QEMU_VERSION_MAJOR - major) == cutoff) && \ 92 | - ((QEMU_VERSION_MINOR + 1) - minor) >= 0)) 93 | +#define _MACHINE_VER_IS_NEXT_MINOR_EXPIRED(baseline_major, baseline_minor, major, minor) \ 94 | + ((major < baseline_major) || \ 95 | + ((major == baseline_major) && \ 96 | + ((minor + 1) < baseline_minor))) 97 | 98 | -#define _MACHINE_VER_IS_NEXT_MAJOR_EXPIRED(cutoff, major, minor) \ 99 | - ((((QEMU_VERSION_MAJOR + 1) - major) > cutoff) || \ 100 | - ((((QEMU_VERSION_MAJOR + 1) - major) == cutoff) && \ 101 | - (0 - minor) >= 0)) 102 | +#define _MACHINE_VER_IS_NEXT_MAJOR_EXPIRED(baseline_major, baseline_minor, major, minor) \ 103 | + (((major + 1) < baseline_major) || \ 104 | + (((major + 1) == baseline_major) && \ 105 | + (minor < baseline_minor))) 106 | 107 | /* 108 | * - The first check applies to formal releases 109 | @@ -684,29 +701,29 @@ struct MachineState { 110 | * and dev snapshots / release candidates are numbered with micro >= 50 111 | * If this ever changes the logic below will need modifying.... 112 | */ 113 | -#define _MACHINE_VER_IS_EXPIRED_IMPL(cutoff, major, minor) \ 114 | +#define _MACHINE_VER_IS_EXPIRED_IMPL(baseline_major, baseline_minor, major, minor) \ 115 | ((QEMU_VERSION_MICRO < 50 && \ 116 | - _MACHINE_VER_IS_CURRENT_EXPIRED(cutoff, major, minor)) || \ 117 | + _MACHINE_VER_IS_CURRENT_EXPIRED(baseline_major, baseline_minor, major, minor)) || \ 118 | (QEMU_VERSION_MICRO >= 50 && QEMU_VERSION_MINOR < 2 && \ 119 | - _MACHINE_VER_IS_NEXT_MINOR_EXPIRED(cutoff, major, minor)) || \ 120 | + _MACHINE_VER_IS_NEXT_MINOR_EXPIRED(baseline_major, baseline_minor, major, minor)) || \ 121 | (QEMU_VERSION_MICRO >= 50 && QEMU_VERSION_MINOR == 2 && \ 122 | - _MACHINE_VER_IS_NEXT_MAJOR_EXPIRED(cutoff, major, minor))) 123 | - 124 | -#define _MACHINE_VER_IS_EXPIRED2(cutoff, major, minor) \ 125 | - _MACHINE_VER_IS_EXPIRED_IMPL(cutoff, major, minor) 126 | -#define _MACHINE_VER_IS_EXPIRED3(cutoff, major, minor, micro) \ 127 | - _MACHINE_VER_IS_EXPIRED_IMPL(cutoff, major, minor) 128 | -#define _MACHINE_VER_IS_EXPIRED4(cutoff, major, minor, _unused, tag) \ 129 | - _MACHINE_VER_IS_EXPIRED_IMPL(cutoff, major, minor) 130 | -#define _MACHINE_VER_IS_EXPIRED5(cutoff, major, minor, micro, _unused, tag) \ 131 | - _MACHINE_VER_IS_EXPIRED_IMPL(cutoff, major, minor) 132 | - 133 | -#define _MACHINE_IS_EXPIRED(cutoff, ...) \ 134 | + _MACHINE_VER_IS_NEXT_MAJOR_EXPIRED(baseline_major, baseline_minor, major, minor))) 135 | + 136 | +#define _MACHINE_VER_IS_EXPIRED2(baseline_major, baseline_minor, major, minor) \ 137 | + _MACHINE_VER_IS_EXPIRED_IMPL(baseline_major, baseline_minor, major, minor) 138 | +#define _MACHINE_VER_IS_EXPIRED3(baseline_major, baseline_minor, major, minor, micro) \ 139 | + _MACHINE_VER_IS_EXPIRED_IMPL(baseline_major, baseline_minor, major, minor) 140 | +#define _MACHINE_VER_IS_EXPIRED4(baseline_major, baseline_minor, major, minor, _unused, tag) \ 141 | + _MACHINE_VER_IS_EXPIRED_IMPL(baseline_major, baseline_minor, major, minor) 142 | +#define _MACHINE_VER_IS_EXPIRED5(baseline_major, baseline_minor, major, minor, micro, _unused, tag) \ 143 | + _MACHINE_VER_IS_EXPIRED_IMPL(baseline_major, baseline_minor, major, minor) 144 | + 145 | +#define _MACHINE_IS_EXPIRED(baseline_major, baseline_minor, ...) \ 146 | _MACHINE_VER_PICK(__VA_ARGS__, \ 147 | _MACHINE_VER_IS_EXPIRED5, \ 148 | _MACHINE_VER_IS_EXPIRED4, \ 149 | _MACHINE_VER_IS_EXPIRED3, \ 150 | - _MACHINE_VER_IS_EXPIRED2) (cutoff, __VA_ARGS__) 151 | + _MACHINE_VER_IS_EXPIRED2) (baseline_major, baseline_minor, __VA_ARGS__) 152 | 153 | /* 154 | * Evaluates true when a machine type with (major, minor) 155 | @@ -715,7 +732,7 @@ struct MachineState { 156 | * lifecycle rules 157 | */ 158 | #define MACHINE_VER_IS_DEPRECATED(...) \ 159 | - _MACHINE_IS_EXPIRED(MACHINE_VER_DEPRECATION_MAJOR, __VA_ARGS__) 160 | + _MACHINE_IS_EXPIRED(MACHINE_VER_BASELINE_PVE_MAJOR, MACHINE_VER_BASELINE_PVE_MINOR, __VA_ARGS__) 161 | 162 | /* 163 | * Evaluates true when a machine type with (major, minor) 164 | @@ -724,7 +741,7 @@ struct MachineState { 165 | * lifecycle rules 166 | */ 167 | #define MACHINE_VER_SHOULD_DELETE(...) \ 168 | - _MACHINE_IS_EXPIRED(MACHINE_VER_DELETION_MAJOR, __VA_ARGS__) 169 | + _MACHINE_IS_EXPIRED(MACHINE_VER_DELETION_MAJOR, MACHINE_VER_DELETION_MINOR, __VA_ARGS__) 170 | 171 | /* 172 | * Sets the deprecation reason for a versioned machine based 173 | -------------------------------------------------------------------------------- /debian/patches/pve/0031-PVE-Backup-pbs-restore-new-command-to-restore-from-p.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Dietmar Maurer 3 | Date: Mon, 6 Apr 2020 12:17:01 +0200 4 | Subject: [PATCH] PVE-Backup: pbs-restore - new command to restore from proxmox 5 | backup server 6 | 7 | Signed-off-by: Thomas Lamprecht 8 | [WB: add namespace support] 9 | Signed-off-by: Wolfgang Bumiller 10 | --- 11 | meson.build | 4 + 12 | pbs-restore.c | 236 ++++++++++++++++++++++++++++++++++++++++++++++++++ 13 | 2 files changed, 240 insertions(+) 14 | create mode 100644 pbs-restore.c 15 | 16 | diff --git a/meson.build b/meson.build 17 | index 3bb206ce4d..9eba919450 100644 18 | --- a/meson.build 19 | +++ b/meson.build 20 | @@ -4538,6 +4538,10 @@ if have_tools 21 | vma = executable('vma', files('vma.c', 'vma-reader.c') + genh, 22 | dependencies: [authz, block, crypto, io, qemuutil, qom], install: true) 23 | 24 | + pbs_restore = executable('pbs-restore', files('pbs-restore.c') + genh, 25 | + dependencies: [authz, block, crypto, io, qemuutil, qom, 26 | + libproxmox_backup_qemu], install: true) 27 | + 28 | subdir('storage-daemon') 29 | 30 | foreach exe: [ 'qemu-img', 'qemu-io', 'qemu-nbd', 'qemu-storage-daemon'] 31 | diff --git a/pbs-restore.c b/pbs-restore.c 32 | new file mode 100644 33 | index 0000000000..f165f418af 34 | --- /dev/null 35 | +++ b/pbs-restore.c 36 | @@ -0,0 +1,236 @@ 37 | +/* 38 | + * Qemu image restore helper for Proxmox Backup 39 | + * 40 | + * Copyright (C) 2019 Proxmox Server Solutions 41 | + * 42 | + * Authors: 43 | + * Dietmar Maurer (dietmar@proxmox.com) 44 | + * 45 | + * This work is licensed under the terms of the GNU GPL, version 2 or later. 46 | + * See the COPYING file in the top-level directory. 47 | + * 48 | + */ 49 | + 50 | +#include "qemu/osdep.h" 51 | +#include 52 | +#include 53 | +#include 54 | + 55 | +#include "qemu/module.h" 56 | +#include "qemu/error-report.h" 57 | +#include "qemu/main-loop.h" 58 | +#include "qemu/cutils.h" 59 | +#include "qapi/error.h" 60 | +#include "qobject/qdict.h" 61 | +#include "system/block-backend.h" 62 | + 63 | +#include 64 | + 65 | +static void help(void) 66 | +{ 67 | + const char *help_msg = 68 | + "usage: pbs-restore [--repository ] [--ns namespace] snapshot archive-name target [command options]\n" 69 | + ; 70 | + 71 | + printf("%s", help_msg); 72 | + exit(1); 73 | +} 74 | + 75 | +typedef struct CallbackData { 76 | + BlockBackend *target; 77 | + uint64_t last_offset; 78 | + bool skip_zero; 79 | +} CallbackData; 80 | + 81 | +static int write_callback( 82 | + void *callback_data_ptr, 83 | + uint64_t offset, 84 | + const unsigned char *data, 85 | + uint64_t data_len) 86 | +{ 87 | + int res = -1; 88 | + 89 | + CallbackData *callback_data = (CallbackData *)callback_data_ptr; 90 | + 91 | + uint64_t last_offset = callback_data->last_offset; 92 | + if (offset > last_offset) callback_data->last_offset = offset; 93 | + 94 | + if (data == NULL) { 95 | + if (callback_data->skip_zero && offset > last_offset) { 96 | + return 0; 97 | + } 98 | + res = blk_pwrite_zeroes(callback_data->target, offset, data_len, 0); 99 | + } else { 100 | + res = blk_pwrite(callback_data->target, offset, data_len, data, 0); 101 | + } 102 | + 103 | + if (res < 0) { 104 | + fprintf(stderr, "blk_pwrite failed at offset %ld length %ld (%d) - %s\n", offset, data_len, res, strerror(-res)); 105 | + return res; 106 | + } 107 | + 108 | + return 0; 109 | +} 110 | + 111 | +int main(int argc, char **argv) 112 | +{ 113 | + Error *main_loop_err = NULL; 114 | + const char *format = "raw"; 115 | + const char *repository = NULL; 116 | + const char *backup_ns = NULL; 117 | + const char *keyfile = NULL; 118 | + int verbose = false; 119 | + bool skip_zero = false; 120 | + 121 | + error_init(argv[0]); 122 | + 123 | + for (;;) { 124 | + static const struct option long_options[] = { 125 | + {"help", no_argument, 0, 'h'}, 126 | + {"skip-zero", no_argument, 0, 'S'}, 127 | + {"verbose", no_argument, 0, 'v'}, 128 | + {"format", required_argument, 0, 'f'}, 129 | + {"repository", required_argument, 0, 'r'}, 130 | + {"ns", required_argument, 0, 'n'}, 131 | + {"keyfile", required_argument, 0, 'k'}, 132 | + {0, 0, 0, 0} 133 | + }; 134 | + int c = getopt_long(argc, argv, "hvf:r:k:", long_options, NULL); 135 | + if (c == -1) { 136 | + break; 137 | + } 138 | + switch (c) { 139 | + case ':': 140 | + fprintf(stderr, "missing argument for option '%s'\n", argv[optind - 1]); 141 | + return -1; 142 | + case '?': 143 | + fprintf(stderr, "unrecognized option '%s'\n", argv[optind - 1]); 144 | + return -1; 145 | + case 'f': 146 | + format = g_strdup(argv[optind - 1]); 147 | + break; 148 | + case 'r': 149 | + repository = g_strdup(argv[optind - 1]); 150 | + break; 151 | + case 'n': 152 | + backup_ns = g_strdup(argv[optind - 1]); 153 | + break; 154 | + case 'k': 155 | + keyfile = g_strdup(argv[optind - 1]); 156 | + break; 157 | + case 'v': 158 | + verbose = true; 159 | + break; 160 | + case 'S': 161 | + skip_zero = true; 162 | + break; 163 | + case 'h': 164 | + help(); 165 | + return 0; 166 | + } 167 | + } 168 | + 169 | + if (optind >= argc - 2) { 170 | + fprintf(stderr, "missing arguments\n"); 171 | + help(); 172 | + return -1; 173 | + } 174 | + 175 | + if (repository == NULL) { 176 | + repository = getenv("PBS_REPOSITORY"); 177 | + } 178 | + 179 | + if (repository == NULL) { 180 | + fprintf(stderr, "no repository specified\n"); 181 | + help(); 182 | + return -1; 183 | + } 184 | + 185 | + char *snapshot = argv[optind++]; 186 | + char *archive_name = argv[optind++]; 187 | + char *target = argv[optind++]; 188 | + 189 | + const char *password = getenv("PBS_PASSWORD"); 190 | + const char *fingerprint = getenv("PBS_FINGERPRINT"); 191 | + const char *key_password = getenv("PBS_ENCRYPTION_PASSWORD"); 192 | + 193 | + if (qemu_init_main_loop(&main_loop_err)) { 194 | + g_error("%s", error_get_pretty(main_loop_err)); 195 | + } 196 | + 197 | + bdrv_init(); 198 | + module_call_init(MODULE_INIT_QOM); 199 | + 200 | + if (verbose) { 201 | + fprintf(stderr, "connecting to repository '%s'\n", repository); 202 | + } 203 | + char *pbs_error = NULL; 204 | + ProxmoxRestoreHandle *conn = proxmox_restore_new_ns( 205 | + repository, 206 | + snapshot, 207 | + backup_ns, 208 | + password, 209 | + keyfile, 210 | + key_password, 211 | + fingerprint, 212 | + &pbs_error 213 | + ); 214 | + if (conn == NULL) { 215 | + fprintf(stderr, "restore failed: %s\n", pbs_error); 216 | + return -1; 217 | + } 218 | + 219 | + int res = proxmox_restore_connect(conn, &pbs_error); 220 | + if (res < 0 || pbs_error) { 221 | + fprintf(stderr, "restore failed (connection error): %s\n", pbs_error); 222 | + return -1; 223 | + } 224 | + 225 | + QDict *options = qdict_new(); 226 | + 227 | + if (format) { 228 | + qdict_put_str(options, "driver", format); 229 | + } 230 | + 231 | + 232 | + if (verbose) { 233 | + fprintf(stderr, "open block backend for target '%s'\n", target); 234 | + } 235 | + Error *local_err = NULL; 236 | + int flags = BDRV_O_RDWR; 237 | + BlockBackend *blk = blk_new_open(target, NULL, options, flags, &local_err); 238 | + if (!blk) { 239 | + fprintf(stderr, "%s\n", error_get_pretty(local_err)); 240 | + return -1; 241 | + } 242 | + 243 | + CallbackData *callback_data = calloc(sizeof(CallbackData), 1); 244 | + 245 | + callback_data->target = blk; 246 | + callback_data->skip_zero = skip_zero; 247 | + callback_data->last_offset = 0; 248 | + 249 | + // blk_set_enable_write_cache(blk, !writethrough); 250 | + 251 | + if (verbose) { 252 | + fprintf(stderr, "starting to restore snapshot '%s'\n", snapshot); 253 | + fflush(stderr); // ensure we do not get printed after the progress log 254 | + } 255 | + res = proxmox_restore_image( 256 | + conn, 257 | + archive_name, 258 | + write_callback, 259 | + callback_data, 260 | + &pbs_error, 261 | + verbose); 262 | + 263 | + proxmox_restore_disconnect(conn); 264 | + blk_unref(blk); 265 | + 266 | + if (res < 0) { 267 | + fprintf(stderr, "restore failed: %s\n", pbs_error); 268 | + return -1; 269 | + } 270 | + 271 | + return 0; 272 | +} 273 | -------------------------------------------------------------------------------- /debian/patches/pve/0019-PVE-block-add-the-zeroinit-block-driver-filter.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Wolfgang Bumiller 3 | Date: Mon, 6 Apr 2020 12:16:47 +0200 4 | Subject: [PATCH] PVE: block: add the zeroinit block driver filter 5 | 6 | Signed-off-by: Thomas Lamprecht 7 | [FE: adapt to changed function signatures 8 | adhere to block graph lock requirements 9 | use dedicated function to open file child] 10 | Signed-off-by: Fiona Ebner 11 | --- 12 | block/meson.build | 1 + 13 | block/zeroinit.c | 213 +++++++++++++++++++++++++++++++++++++++++++ 14 | qapi/block-core.json | 5 +- 15 | 3 files changed, 217 insertions(+), 2 deletions(-) 16 | create mode 100644 block/zeroinit.c 17 | 18 | diff --git a/block/meson.build b/block/meson.build 19 | index 34b1b2a306..a21d9a5411 100644 20 | --- a/block/meson.build 21 | +++ b/block/meson.build 22 | @@ -39,6 +39,7 @@ block_ss.add(files( 23 | 'throttle.c', 24 | 'throttle-groups.c', 25 | 'write-threshold.c', 26 | + 'zeroinit.c', 27 | ), zstd, zlib) 28 | 29 | system_ss.add(when: 'CONFIG_TCG', if_true: files('blkreplay.c')) 30 | diff --git a/block/zeroinit.c b/block/zeroinit.c 31 | new file mode 100644 32 | index 0000000000..036edb17f5 33 | --- /dev/null 34 | +++ b/block/zeroinit.c 35 | @@ -0,0 +1,213 @@ 36 | +/* 37 | + * Filter to fake a zero-initialized block device. 38 | + * 39 | + * Copyright (c) 2016 Wolfgang Bumiller 40 | + * Copyright (c) 2016 Proxmox Server Solutions GmbH 41 | + * 42 | + * This work is licensed under the terms of the GNU GPL, version 2 or later. 43 | + * See the COPYING file in the top-level directory. 44 | + */ 45 | + 46 | +#include "qemu/osdep.h" 47 | +#include "qapi/error.h" 48 | +#include "block/block_int.h" 49 | +#include "block/block-io.h" 50 | +#include "block/graph-lock.h" 51 | +#include "qobject/qdict.h" 52 | +#include "qobject/qstring.h" 53 | +#include "qemu/cutils.h" 54 | +#include "qemu/option.h" 55 | +#include "qemu/module.h" 56 | + 57 | +typedef struct { 58 | + bool has_zero_init; 59 | + int64_t extents; 60 | +} BDRVZeroinitState; 61 | + 62 | +/* Valid blkverify filenames look like blkverify:path/to/raw_image:path/to/image */ 63 | +static void zeroinit_parse_filename(const char *filename, QDict *options, 64 | + Error **errp) 65 | +{ 66 | + QString *raw_path; 67 | + 68 | + /* Parse the blkverify: prefix */ 69 | + if (!strstart(filename, "zeroinit:", &filename)) { 70 | + /* There was no prefix; therefore, all options have to be already 71 | + present in the QDict (except for the filename) */ 72 | + return; 73 | + } 74 | + 75 | + raw_path = qstring_from_str(filename); 76 | + qdict_put(options, "x-next", raw_path); 77 | +} 78 | + 79 | +static QemuOptsList runtime_opts = { 80 | + .name = "zeroinit", 81 | + .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head), 82 | + .desc = { 83 | + { 84 | + .name = "x-next", 85 | + .type = QEMU_OPT_STRING, 86 | + .help = "[internal use only, will be removed]", 87 | + }, 88 | + { 89 | + .name = "x-zeroinit", 90 | + .type = QEMU_OPT_BOOL, 91 | + .help = "set has_initialized_zero flag", 92 | + }, 93 | + { /* end of list */ } 94 | + }, 95 | +}; 96 | + 97 | +static int zeroinit_open(BlockDriverState *bs, QDict *options, int flags, 98 | + Error **errp) 99 | +{ 100 | + BDRVZeroinitState *s = bs->opaque; 101 | + QemuOpts *opts; 102 | + Error *local_err = NULL; 103 | + int ret; 104 | + const char *next = NULL; 105 | + 106 | + s->extents = 0; 107 | + 108 | + opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); 109 | + qemu_opts_absorb_qdict(opts, options, &local_err); 110 | + if (local_err) { 111 | + error_propagate(errp, local_err); 112 | + ret = -EINVAL; 113 | + goto fail; 114 | + } 115 | + 116 | + 117 | + next = qemu_opt_get(opts, "x-next"); 118 | + 119 | + if (next) { 120 | + ret = bdrv_open_file_child(next, options, "next", bs, &local_err); 121 | + } else { /* when opened as a blockdev, there is no 'next' option */ 122 | + ret = bdrv_open_file_child(NULL, options, "file", bs, &local_err); 123 | + } 124 | + if (ret < 0) { 125 | + error_propagate(errp, local_err); 126 | + goto fail; 127 | + } 128 | + 129 | + /* set the options */ 130 | + s->has_zero_init = qemu_opt_get_bool(opts, "x-zeroinit", true); 131 | + 132 | + ret = 0; 133 | +fail: 134 | + if (ret < 0) { 135 | + bdrv_graph_wrlock(); 136 | + bdrv_unref_child(bs, bs->file); 137 | + bdrv_graph_wrunlock(); 138 | + } 139 | + qemu_opts_del(opts); 140 | + return ret; 141 | +} 142 | + 143 | +static void zeroinit_close(BlockDriverState *bs) 144 | +{ 145 | + BDRVZeroinitState *s = bs->opaque; 146 | + (void)s; 147 | +} 148 | + 149 | +static coroutine_fn int64_t GRAPH_RDLOCK 150 | +zeroinit_co_getlength(BlockDriverState *bs) 151 | +{ 152 | + return bdrv_co_getlength(bs->file->bs); 153 | +} 154 | + 155 | +static int coroutine_fn GRAPH_RDLOCK 156 | +zeroinit_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, 157 | + QEMUIOVector *qiov, BdrvRequestFlags flags) 158 | +{ 159 | + return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags); 160 | +} 161 | + 162 | +static int coroutine_fn GRAPH_RDLOCK 163 | +zeroinit_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes, 164 | + BdrvRequestFlags flags) 165 | +{ 166 | + BDRVZeroinitState *s = bs->opaque; 167 | + if (offset >= s->extents) 168 | + return 0; 169 | + return bdrv_pwrite_zeroes(bs->file, offset, bytes, flags); 170 | +} 171 | + 172 | +static int coroutine_fn GRAPH_RDLOCK 173 | +zeroinit_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, 174 | + QEMUIOVector *qiov, BdrvRequestFlags flags) 175 | +{ 176 | + BDRVZeroinitState *s = bs->opaque; 177 | + int64_t extents = offset + bytes; 178 | + if (extents > s->extents) 179 | + s->extents = extents; 180 | + return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags); 181 | +} 182 | + 183 | +static coroutine_fn int GRAPH_RDLOCK 184 | +zeroinit_co_flush(BlockDriverState *bs) 185 | +{ 186 | + return bdrv_co_flush(bs->file->bs); 187 | +} 188 | + 189 | +static int GRAPH_RDLOCK 190 | +zeroinit_has_zero_init(BlockDriverState *bs) 191 | +{ 192 | + BDRVZeroinitState *s = bs->opaque; 193 | + return s->has_zero_init; 194 | +} 195 | + 196 | +static int coroutine_fn GRAPH_RDLOCK 197 | +zeroinit_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes) 198 | +{ 199 | + return bdrv_co_pdiscard(bs->file, offset, bytes); 200 | +} 201 | + 202 | +static int GRAPH_RDLOCK 203 | +zeroinit_co_truncate(BlockDriverState *bs, int64_t offset, _Bool exact, 204 | + PreallocMode prealloc, BdrvRequestFlags req_flags, 205 | + Error **errp) 206 | +{ 207 | + return bdrv_co_truncate(bs->file, offset, exact, prealloc, req_flags, errp); 208 | +} 209 | + 210 | +static coroutine_fn int GRAPH_RDLOCK 211 | +zeroinit_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) 212 | +{ 213 | + return bdrv_co_get_info(bs->file->bs, bdi); 214 | +} 215 | + 216 | +static BlockDriver bdrv_zeroinit = { 217 | + .format_name = "zeroinit", 218 | + .protocol_name = "zeroinit", 219 | + .instance_size = sizeof(BDRVZeroinitState), 220 | + 221 | + .bdrv_parse_filename = zeroinit_parse_filename, 222 | + .bdrv_open = zeroinit_open, 223 | + .bdrv_close = zeroinit_close, 224 | + .bdrv_co_getlength = zeroinit_co_getlength, 225 | + .bdrv_child_perm = bdrv_default_perms, 226 | + .bdrv_co_flush_to_disk = zeroinit_co_flush, 227 | + 228 | + .bdrv_co_pwrite_zeroes = zeroinit_co_pwrite_zeroes, 229 | + .bdrv_co_pwritev = zeroinit_co_pwritev, 230 | + .bdrv_co_preadv = zeroinit_co_preadv, 231 | + .bdrv_co_flush = zeroinit_co_flush, 232 | + 233 | + .is_filter = true, 234 | + 235 | + .bdrv_has_zero_init = zeroinit_has_zero_init, 236 | + 237 | + .bdrv_co_pdiscard = zeroinit_co_pdiscard, 238 | + 239 | + .bdrv_co_truncate = zeroinit_co_truncate, 240 | + .bdrv_co_get_info = zeroinit_co_get_info, 241 | +}; 242 | + 243 | +static void bdrv_zeroinit_init(void) 244 | +{ 245 | + bdrv_register(&bdrv_zeroinit); 246 | +} 247 | + 248 | +block_init(bdrv_zeroinit_init); 249 | diff --git a/qapi/block-core.json b/qapi/block-core.json 250 | index 7d281ab7ae..aa1dba4284 100644 251 | --- a/qapi/block-core.json 252 | +++ b/qapi/block-core.json 253 | @@ -3305,7 +3305,7 @@ 254 | { 'name': 'virtio-blk-vfio-pci', 'if': 'CONFIG_BLKIO' }, 255 | { 'name': 'virtio-blk-vhost-user', 'if': 'CONFIG_BLKIO' }, 256 | { 'name': 'virtio-blk-vhost-vdpa', 'if': 'CONFIG_BLKIO' }, 257 | - 'vmdk', 'vpc', 'vvfat' ] } 258 | + 'vmdk', 'vpc', 'vvfat', 'zeroinit' ] } 259 | 260 | ## 261 | # @BlockdevOptionsFile: 262 | @@ -4863,7 +4863,8 @@ 263 | 'if': 'CONFIG_BLKIO' }, 264 | 'vmdk': 'BlockdevOptionsGenericCOWFormat', 265 | 'vpc': 'BlockdevOptionsGenericFormat', 266 | - 'vvfat': 'BlockdevOptionsVVFAT' 267 | + 'vvfat': 'BlockdevOptionsVVFAT', 268 | + 'zeroinit': 'BlockdevOptionsGenericFormat' 269 | } } 270 | 271 | ## 272 | --------------------------------------------------------------------------------