From 3499c5b45a30a3489ca0d688d2d391fdfe899861 Mon Sep 17 00:00:00 2001 From: Thomas Lamprecht Date: Thu, 9 Jul 2020 13:15:49 +0200 Subject: [PATCH] PBS patches: block driver, adapat encrypt/compress param, add query-proxmox-support QMP cmd Signed-off-by: Thomas Lamprecht --- ...ckup-add-compress-and-encrypt-option.patch | 103 +++++ ...k-driver-to-map-backup-archives-into.patch | 398 ++++++++++++++++++ ...dd-query_proxmox_support-QMP-command.patch | 63 +++ debian/patches/series | 3 + 4 files changed, 567 insertions(+) create mode 100644 debian/patches/pve/0043-PVE-fixup-pbs-backup-add-compress-and-encrypt-option.patch create mode 100644 debian/patches/pve/0044-PVE-Add-PBS-block-driver-to-map-backup-archives-into.patch create mode 100644 debian/patches/pve/0045-PVE-add-query_proxmox_support-QMP-command.patch diff --git a/debian/patches/pve/0043-PVE-fixup-pbs-backup-add-compress-and-encrypt-option.patch b/debian/patches/pve/0043-PVE-fixup-pbs-backup-add-compress-and-encrypt-option.patch new file mode 100644 index 0000000..4ebe10d --- /dev/null +++ b/debian/patches/pve/0043-PVE-fixup-pbs-backup-add-compress-and-encrypt-option.patch @@ -0,0 +1,103 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Dietmar Maurer +Date: Thu, 9 Jul 2020 12:53:08 +0200 +Subject: [PATCH] PVE: fixup pbs backup, add compress and encrypt options + +--- + block/monitor/block-hmp-cmds.c | 4 +++- + pve-backup.c | 13 ++++++++++++- + qapi/block-core.json | 6 ++++++ + 3 files changed, 21 insertions(+), 2 deletions(-) + +diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c +index fdc85a5c0e..43aa87487b 100644 +--- a/block/monitor/block-hmp-cmds.c ++++ b/block/monitor/block-hmp-cmds.c +@@ -1038,7 +1038,9 @@ void hmp_backup(Monitor *mon, const QDict *qdict) + false, NULL, // PBS fingerprint + false, NULL, // PBS backup-id + false, 0, // PBS backup-time +- false, false, // PBS incremental ++ false, false, // PBS use-dirty-bitmap ++ false, false, // PBS compress ++ false, false, // PBS encrypt + true, dir ? BACKUP_FORMAT_DIR : BACKUP_FORMAT_VMA, + false, NULL, false, NULL, !!devlist, + devlist, qdict_haskey(qdict, "speed"), speed, &error); +diff --git a/pve-backup.c b/pve-backup.c +index 46191bb328..3323b195a4 100644 +--- a/pve-backup.c ++++ b/pve-backup.c +@@ -567,6 +567,10 @@ typedef struct QmpBackupTask { + const char *firewall_file; + bool has_devlist; + const char *devlist; ++ bool has_compress; ++ bool compress; ++ bool has_encrypt; ++ bool encrypt; + bool has_speed; + int64_t speed; + Error **errp; +@@ -694,6 +698,7 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque) + + bool use_dirty_bitmap = task->has_use_dirty_bitmap && task->use_dirty_bitmap; + ++ + char *pbs_err = NULL; + pbs = proxmox_backup_new( + task->backup_file, +@@ -703,8 +708,10 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque) + task->has_password ? task->password : NULL, + task->has_keyfile ? task->keyfile : NULL, + task->has_key_password ? task->key_password : NULL, ++ task->has_compress ? task->compress : true, ++ task->has_encrypt ? task->encrypt : task->has_keyfile, + task->has_fingerprint ? task->fingerprint : NULL, +- &pbs_err); ++ &pbs_err); + + if (!pbs) { + error_set(task->errp, ERROR_CLASS_GENERIC_ERROR, +@@ -943,6 +950,8 @@ UuidInfo *qmp_backup( + bool has_backup_id, const char *backup_id, + bool has_backup_time, int64_t backup_time, + bool has_use_dirty_bitmap, bool use_dirty_bitmap, ++ bool has_compress, bool compress, ++ bool has_encrypt, bool encrypt, + bool has_format, BackupFormat format, + bool has_config_file, const char *config_file, + bool has_firewall_file, const char *firewall_file, +@@ -971,6 +980,8 @@ UuidInfo *qmp_backup( + .firewall_file = firewall_file, + .has_devlist = has_devlist, + .devlist = devlist, ++ .has_compress = has_compress, ++ .has_encrypt = has_encrypt, + .has_speed = has_speed, + .speed = speed, + .errp = errp, +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 4fe3d6f751..0bc15a5098 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -822,6 +822,10 @@ + # + # @use-dirty-bitmap: use dirty bitmap to detect incremental changes since last job (optional for format 'pbs') + # ++# @compress: use compression (optional for format 'pbs', defaults to true) ++# ++# @encrypt: use encryption ((optional for format 'pbs', defaults to true if there is a keyfile) ++# + # Returns: the uuid of the backup job + # + ## +@@ -833,6 +837,8 @@ + '*backup-id': 'str', + '*backup-time': 'int', + '*use-dirty-bitmap': 'bool', ++ '*compress': 'bool', ++ '*encrypt': 'bool', + '*format': 'BackupFormat', + '*config-file': 'str', + '*firewall-file': 'str', diff --git a/debian/patches/pve/0044-PVE-Add-PBS-block-driver-to-map-backup-archives-into.patch b/debian/patches/pve/0044-PVE-Add-PBS-block-driver-to-map-backup-archives-into.patch new file mode 100644 index 0000000..855cc22 --- /dev/null +++ b/debian/patches/pve/0044-PVE-Add-PBS-block-driver-to-map-backup-archives-into.patch @@ -0,0 +1,398 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Stefan Reiter +Date: Wed, 8 Jul 2020 09:50:54 +0200 +Subject: [PATCH] PVE: Add PBS block driver to map backup archives into VMs + +Signed-off-by: Stefan Reiter +[error cleanups, file_open implementation] +Signed-off-by: Dietmar Maurer +--- + block/Makefile.objs | 2 + + block/pbs.c | 271 +++++++++++++++++++++++++++++++++++++++++++ + configure | 10 ++ + qapi/block-core.json | 14 ++- + 4 files changed, 296 insertions(+), 1 deletion(-) + create mode 100644 block/pbs.c + +diff --git a/block/Makefile.objs b/block/Makefile.objs +index 8af7073c83..9785e4431d 100644 +--- a/block/Makefile.objs ++++ b/block/Makefile.objs +@@ -5,6 +5,7 @@ block-obj-$(CONFIG_CLOOP) += cloop.o + block-obj-$(CONFIG_BOCHS) += bochs.o + block-obj-$(CONFIG_VVFAT) += vvfat.o + block-obj-$(CONFIG_DMG) += dmg.o ++block-obj-$(CONFIG_PBS_BDRV) += pbs.o + + block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o qcow2-bitmap.o qcow2-threads.o + block-obj-$(CONFIG_QED) += qed.o qed-l2-cache.o qed-table.o qed-cluster.o +@@ -76,3 +77,4 @@ io_uring.o-cflags := $(LINUX_IO_URING_CFLAGS) + io_uring.o-libs := $(LINUX_IO_URING_LIBS) + parallels.o-cflags := $(LIBXML2_CFLAGS) + parallels.o-libs := $(LIBXML2_LIBS) ++pbs.o-libs := -lproxmox_backup_qemu +diff --git a/block/pbs.c b/block/pbs.c +new file mode 100644 +index 0000000000..1481a2bfd1 +--- /dev/null ++++ b/block/pbs.c +@@ -0,0 +1,271 @@ ++/* ++ * Proxmox Backup Server read-only block driver ++ */ ++ ++#include "qemu/osdep.h" ++#include "qapi/error.h" ++#include "qapi/qmp/qdict.h" ++#include "qapi/qmp/qstring.h" ++#include "qemu/module.h" ++#include "qemu/option.h" ++#include "qemu/cutils.h" ++#include "block/block_int.h" ++ ++#include ++ ++#define PBS_OPT_REPOSITORY "repository" ++#define PBS_OPT_SNAPSHOT "snapshot" ++#define PBS_OPT_ARCHIVE "archive" ++#define PBS_OPT_KEYFILE "keyfile" ++#define PBS_OPT_PASSWORD "password" ++#define PBS_OPT_FINGERPRINT "fingerprint" ++#define PBS_OPT_ENCRYPTION_PASSWORD "key_password" ++ ++typedef struct { ++ ProxmoxRestoreHandle *conn; ++ char aid; ++ int64_t length; ++ ++ char *repository; ++ char *snapshot; ++ char *archive; ++} BDRVPBSState; ++ ++static QemuOptsList runtime_opts = { ++ .name = "pbs", ++ .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head), ++ .desc = { ++ { ++ .name = PBS_OPT_REPOSITORY, ++ .type = QEMU_OPT_STRING, ++ .help = "The server address and repository to connect to.", ++ }, ++ { ++ .name = PBS_OPT_SNAPSHOT, ++ .type = QEMU_OPT_STRING, ++ .help = "The snapshot to read.", ++ }, ++ { ++ .name = PBS_OPT_ARCHIVE, ++ .type = QEMU_OPT_STRING, ++ .help = "Which archive within the snapshot should be accessed.", ++ }, ++ { ++ .name = PBS_OPT_PASSWORD, ++ .type = QEMU_OPT_STRING, ++ .help = "Server password. Can be passed as env var 'PBS_PASSWORD'.", ++ }, ++ { ++ .name = PBS_OPT_FINGERPRINT, ++ .type = QEMU_OPT_STRING, ++ .help = "Server fingerprint. Can be passed as env var 'PBS_FINGERPRINT'.", ++ }, ++ { ++ .name = PBS_OPT_ENCRYPTION_PASSWORD, ++ .type = QEMU_OPT_STRING, ++ .help = "Optional: Key password. Can be passed as env var 'PBS_ENCRYPTION_PASSWORD'.", ++ }, ++ { ++ .name = PBS_OPT_KEYFILE, ++ .type = QEMU_OPT_STRING, ++ .help = "Optional: The path to the keyfile to use.", ++ }, ++ { /* end of list */ } ++ }, ++}; ++ ++ ++// filename format: ++// pbs:repository=,snapshot=,password=,key_password=,fingerprint=,archive= ++static void pbs_parse_filename(const char *filename, QDict *options, ++ Error **errp) ++{ ++ ++ if (!strstart(filename, "pbs:", &filename)) { ++ if (errp) error_setg(errp, "pbs_parse_filename failed - missing 'pbs:' prefix"); ++ } ++ ++ ++ QemuOpts *opts = qemu_opts_parse_noisily(&runtime_opts, filename, false); ++ if (!opts) { ++ if (errp) error_setg(errp, "pbs_parse_filename failed"); ++ return; ++ } ++ ++ qemu_opts_to_qdict(opts, options); ++ ++ qemu_opts_del(opts); ++} ++ ++static int pbs_open(BlockDriverState *bs, QDict *options, int flags, ++ Error **errp) ++{ ++ QemuOpts *opts; ++ BDRVPBSState *s = bs->opaque; ++ char *pbs_error = NULL; ++ ++ opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); ++ qemu_opts_absorb_qdict(opts, options, &error_abort); ++ ++ s->repository = g_strdup(qemu_opt_get(opts, PBS_OPT_REPOSITORY)); ++ s->snapshot = g_strdup(qemu_opt_get(opts, PBS_OPT_SNAPSHOT)); ++ s->archive = g_strdup(qemu_opt_get(opts, PBS_OPT_ARCHIVE)); ++ const char *keyfile = qemu_opt_get(opts, PBS_OPT_KEYFILE); ++ const char *password = qemu_opt_get(opts, PBS_OPT_PASSWORD); ++ const char *fingerprint = qemu_opt_get(opts, PBS_OPT_FINGERPRINT); ++ const char *key_password = qemu_opt_get(opts, PBS_OPT_ENCRYPTION_PASSWORD); ++ ++ if (!password) { ++ password = getenv("PBS_PASSWORD"); ++ } ++ if (!fingerprint) { ++ fingerprint = getenv("PBS_FINGERPRINT"); ++ } ++ if (!key_password) { ++ key_password = getenv("PBS_ENCRYPTION_PASSWORD"); ++ } ++ ++ /* connect to PBS server in read mode */ ++ s->conn = proxmox_restore_new(s->repository, s->snapshot, password, ++ keyfile, key_password, fingerprint, &pbs_error); ++ ++ /* invalidates qemu_opt_get char pointers from above */ ++ qemu_opts_del(opts); ++ ++ if (!s->conn) { ++ if (pbs_error && errp) error_setg(errp, "PBS restore_new failed: %s", pbs_error); ++ if (pbs_error) proxmox_backup_free_error(pbs_error); ++ return -ENOMEM; ++ } ++ ++ int ret = proxmox_restore_connect(s->conn, &pbs_error); ++ if (ret < 0) { ++ if (pbs_error && errp) error_setg(errp, "PBS connect failed: %s", pbs_error); ++ if (pbs_error) proxmox_backup_free_error(pbs_error); ++ return -ECONNREFUSED; ++ } ++ ++ /* acquire handle and length */ ++ s->aid = proxmox_restore_open_image(s->conn, s->archive, &pbs_error); ++ if (s->aid < 0) { ++ if (pbs_error && errp) error_setg(errp, "PBS open_image failed: %s", pbs_error); ++ if (pbs_error) proxmox_backup_free_error(pbs_error); ++ return -ENODEV; ++ } ++ s->length = proxmox_restore_get_image_length(s->conn, s->aid, &pbs_error); ++ if (s->length < 0) { ++ if (pbs_error && errp) error_setg(errp, "PBS get_image_length failed: %s", pbs_error); ++ if (pbs_error) proxmox_backup_free_error(pbs_error); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int pbs_file_open(BlockDriverState *bs, QDict *options, int flags, ++ Error **errp) ++{ ++ return pbs_open(bs, options, flags, errp); ++} ++ ++static void pbs_close(BlockDriverState *bs) { ++ BDRVPBSState *s = bs->opaque; ++ g_free(s->repository); ++ g_free(s->snapshot); ++ g_free(s->archive); ++ proxmox_restore_disconnect(s->conn); ++} ++ ++static int64_t pbs_getlength(BlockDriverState *bs) ++{ ++ BDRVPBSState *s = bs->opaque; ++ return s->length; ++} ++ ++typedef struct ReadCallbackData { ++ Coroutine *co; ++ AioContext *ctx; ++} ReadCallbackData; ++ ++static void read_callback(void *callback_data) ++{ ++ ReadCallbackData *rcb = callback_data; ++ aio_co_schedule(rcb->ctx, rcb->co); ++} ++ ++static coroutine_fn int pbs_co_preadv(BlockDriverState *bs, ++ uint64_t offset, uint64_t bytes, ++ QEMUIOVector *qiov, int flags) ++{ ++ BDRVPBSState *s = bs->opaque; ++ int ret; ++ char *pbs_error = NULL; ++ uint8_t *buf = malloc(bytes); ++ ++ ReadCallbackData rcb = { ++ .co = qemu_coroutine_self(), ++ .ctx = qemu_get_current_aio_context(), ++ }; ++ ++ proxmox_restore_read_image_at_async(s->conn, s->aid, buf, offset, bytes, ++ read_callback, (void *) &rcb, &ret, &pbs_error); ++ ++ qemu_coroutine_yield(); ++ ++ if (ret < 0) { ++ fprintf(stderr, "error during PBS read: %s\n", pbs_error ? pbs_error : "unknown error"); ++ if (pbs_error) proxmox_backup_free_error(pbs_error); ++ return -EIO; ++ } ++ ++ qemu_iovec_from_buf(qiov, 0, buf, bytes); ++ free(buf); ++ ++ return ret; ++} ++ ++static coroutine_fn int pbs_co_pwritev(BlockDriverState *bs, ++ uint64_t offset, uint64_t bytes, ++ QEMUIOVector *qiov, int flags) ++{ ++ fprintf(stderr, "pbs-bdrv: cannot write to backup file, make sure " ++ "any attached disk devices are set to read-only!\n"); ++ return -EPERM; ++} ++ ++static void pbs_refresh_filename(BlockDriverState *bs) ++{ ++ BDRVPBSState *s = bs->opaque; ++ snprintf(bs->exact_filename, sizeof(bs->exact_filename), "%s/%s(%s)", ++ s->repository, s->snapshot, s->archive); ++} ++ ++static const char *const pbs_strong_runtime_opts[] = { ++ NULL ++}; ++ ++static BlockDriver bdrv_pbs_co = { ++ .format_name = "pbs", ++ .protocol_name = "pbs", ++ .instance_size = sizeof(BDRVPBSState), ++ ++ .bdrv_parse_filename = pbs_parse_filename, ++ ++ .bdrv_file_open = pbs_file_open, ++ .bdrv_open = pbs_open, ++ .bdrv_close = pbs_close, ++ .bdrv_getlength = pbs_getlength, ++ ++ .bdrv_co_preadv = pbs_co_preadv, ++ .bdrv_co_pwritev = pbs_co_pwritev, ++ ++ .bdrv_refresh_filename = pbs_refresh_filename, ++ .strong_runtime_opts = pbs_strong_runtime_opts, ++}; ++ ++static void bdrv_pbs_init(void) ++{ ++ bdrv_register(&bdrv_pbs_co); ++} ++ ++block_init(bdrv_pbs_init); +diff --git a/configure b/configure +index 23b5e93752..67054b5795 100755 +--- a/configure ++++ b/configure +@@ -503,6 +503,7 @@ vvfat="yes" + qed="yes" + parallels="yes" + sheepdog="yes" ++pbs_bdrv="yes" + libxml2="" + debug_mutex="no" + libpmem="" +@@ -1553,6 +1554,10 @@ for opt do + ;; + --enable-sheepdog) sheepdog="yes" + ;; ++ --disable-pbs-bdrv) pbs_bdrv="no" ++ ;; ++ --enable-pbs-bdrv) pbs_bdrv="yes" ++ ;; + --disable-vhost-user) vhost_user="no" + ;; + --enable-vhost-user) vhost_user="yes" +@@ -1889,6 +1894,7 @@ disabled with --disable-FEATURE, default is enabled if available: + qed qed image format support + parallels parallels image format support + sheepdog sheepdog block driver support ++ pbs-bdrv Proxmox backup server read-only block driver support + crypto-afalg Linux AF_ALG crypto backend driver + capstone capstone disassembler support + debug-mutex mutex debugging support +@@ -6726,6 +6732,7 @@ echo "vvfat support $vvfat" + echo "qed support $qed" + echo "parallels support $parallels" + echo "sheepdog support $sheepdog" ++echo "pbs-bdrv support $pbs_bdrv" + echo "capstone $capstone" + echo "libpmem support $libpmem" + echo "libudev $libudev" +@@ -7578,6 +7585,9 @@ fi + if test "$sheepdog" = "yes" ; then + echo "CONFIG_SHEEPDOG=y" >> $config_host_mak + fi ++if test "$pbs_bdrv" = "yes" ; then ++ echo "CONFIG_PBS_BDRV=y" >> $config_host_mak ++fi + if test "$fuzzing" = "yes" ; then + if test "$have_fuzzer" = "yes"; then + FUZZ_LDFLAGS=" -fsanitize=address,fuzzer" +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 0bc15a5098..13c63d8e6a 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -2942,7 +2942,7 @@ + 'luks', 'nbd', 'nfs', 'null-aio', 'null-co', 'nvme', 'parallels', + 'qcow', 'qcow2', 'qed', 'quorum', 'raw', 'rbd', + { 'name': 'replication', 'if': 'defined(CONFIG_REPLICATION)' }, +- 'sheepdog', ++ 'sheepdog', 'pbs', + 'ssh', 'throttle', 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] } + + ## +@@ -3006,6 +3006,17 @@ + { 'struct': 'BlockdevOptionsNull', + 'data': { '*size': 'int', '*latency-ns': 'uint64', '*read-zeroes': 'bool' } } + ++## ++# @BlockdevOptionsPbs: ++# ++# Driver specific block device options for the PBS backend. ++# ++## ++{ 'struct': 'BlockdevOptionsPbs', ++ 'data': { 'repository': 'str', 'snapshot': 'str', 'archive': 'str', ++ '*keyfile': 'str', '*password': 'str', '*fingerprint': 'str', ++ '*key_password': 'str' } } ++ + ## + # @BlockdevOptionsNVMe: + # +@@ -4128,6 +4139,7 @@ + 'nfs': 'BlockdevOptionsNfs', + 'null-aio': 'BlockdevOptionsNull', + 'null-co': 'BlockdevOptionsNull', ++ 'pbs': 'BlockdevOptionsPbs', + 'nvme': 'BlockdevOptionsNVMe', + 'parallels': 'BlockdevOptionsGenericFormat', + 'qcow2': 'BlockdevOptionsQcow2', diff --git a/debian/patches/pve/0045-PVE-add-query_proxmox_support-QMP-command.patch b/debian/patches/pve/0045-PVE-add-query_proxmox_support-QMP-command.patch new file mode 100644 index 0000000..8858203 --- /dev/null +++ b/debian/patches/pve/0045-PVE-add-query_proxmox_support-QMP-command.patch @@ -0,0 +1,63 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Stefan Reiter +Date: Wed, 8 Jul 2020 11:57:53 +0200 +Subject: [PATCH] PVE: add query_proxmox_support QMP command + +Generic interface for future use, currently used for PBS dirty-bitmap +backup support. + +Signed-off-by: Stefan Reiter +Signed-off-by: Thomas Lamprecht +--- + pve-backup.c | 7 +++++++ + qapi/block-core.json | 22 ++++++++++++++++++++++ + 2 files changed, 29 insertions(+) + +diff --git a/pve-backup.c b/pve-backup.c +index 3323b195a4..5bdfd1fedd 100644 +--- a/pve-backup.c ++++ b/pve-backup.c +@@ -1055,3 +1055,10 @@ BackupStatus *qmp_query_backup(Error **errp) + + return info; + } ++ ++ProxmoxSupportStatus *qmp_query_proxmox_support(Error **errp) ++{ ++ ProxmoxSupportStatus *ret = g_malloc0(sizeof(*ret)); ++ ret->pbs_dirty_bitmap = true; ++ return ret; ++} +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 13c63d8e6a..355a184ea8 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -867,6 +867,28 @@ + ## + { 'command': 'backup-cancel' } + ++## ++# @ProxmoxSupportStatus: ++# ++# Contains info about supported features added by Proxmox. ++# ++# @pbs-dirty-bitmap: True if dirty-bitmap-incremental backups to PBS are ++# supported. ++# ++## ++{ 'struct': 'ProxmoxSupportStatus', ++ 'data': { 'pbs-dirty-bitmap': 'bool' } } ++ ++## ++# @query-proxmox-support: ++# ++# Returns information about supported features added by Proxmox. ++# ++# Returns: @ProxmoxSupportStatus ++# ++## ++{ 'command': 'query-proxmox-support', 'returns': 'ProxmoxSupportStatus' } ++ + ## + # @BlockDeviceTimedStats: + # diff --git a/debian/patches/series b/debian/patches/series index dbd7de7..f3bd61a 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -41,3 +41,6 @@ pve/0039-PVE-backup-rename-incremental-to-use-dirty-bitmap.patch pve/0040-PVE-fixup-pbs-restore-API.patch pve/0041-PVE-always-set-dirty-counter-for-non-incremental-bac.patch pve/0042-PVE-use-proxmox_backup_check_incremental.patch +pve/0043-PVE-fixup-pbs-backup-add-compress-and-encrypt-option.patch +pve/0044-PVE-Add-PBS-block-driver-to-map-backup-archives-into.patch +pve/0045-PVE-add-query_proxmox_support-QMP-command.patch -- 2.39.2