From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Dietmar Maurer <dietmar@proxmox.com>
Date: Thu, 9 Jul 2020 12:53:08 +0200
Subject: [PATCH] PVE: various PBS fixes

pbs: fix crypt and compress parameters
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>

PVE: handle PBS write callback with big blocks correctly
Signed-off-by: Stefan Reiter <s.reiter@proxmox.com>

PVE: add zero block handling to PBS dump callback
Signed-off-by: Stefan Reiter <s.reiter@proxmox.com>
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
---
 block/monitor/block-hmp-cmds.c |  4 ++-
 pve-backup.c                   | 57 +++++++++++++++++++++++++++-------
 qapi/block-core.json           |  6 ++++
 3 files changed, 54 insertions(+), 13 deletions(-)

diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c
index 556af25861..a09f722fea 100644
--- a/block/monitor/block-hmp-cmds.c
+++ b/block/monitor/block-hmp-cmds.c
@@ -1042,7 +1042,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 abd7062afe..e113ab61b9 100644
--- a/pve-backup.c
+++ b/pve-backup.c
@@ -8,6 +8,7 @@
 #include "block/blockjob.h"
 #include "qapi/qapi-commands-block.h"
 #include "qapi/qmp/qerror.h"
+#include "qemu/cutils.h"
 
 /* PVE backup state and related function */
 
@@ -67,6 +68,7 @@ opts_init(pvebackup_init);
 typedef struct PVEBackupDevInfo {
     BlockDriverState *bs;
     size_t size;
+    uint64_t block_size;
     uint8_t dev_id;
     bool completed;
     char targetfile[PATH_MAX];
@@ -137,10 +139,13 @@ pvebackup_co_dump_pbs_cb(
     PVEBackupDevInfo *di = opaque;
 
     assert(backup_state.pbs);
+    assert(buf);
 
     Error *local_err = NULL;
     int pbs_res = -1;
 
+    bool is_zero_block = size == di->block_size && buffer_is_zero(buf, size);
+
     qemu_co_mutex_lock(&backup_state.dump_callback_mutex);
 
     // avoid deadlock if job is cancelled
@@ -149,17 +154,29 @@ pvebackup_co_dump_pbs_cb(
         return -1;
     }
 
-    pbs_res = proxmox_backup_co_write_data(backup_state.pbs, di->dev_id, buf, start, size, &local_err);
-    qemu_co_mutex_unlock(&backup_state.dump_callback_mutex);
+    uint64_t transferred = 0;
+    uint64_t reused = 0;
+    while (transferred < size) {
+        uint64_t left = size - transferred;
+        uint64_t to_transfer = left < di->block_size ? left : di->block_size;
 
-    if (pbs_res < 0) {
-        pvebackup_propagate_error(local_err);
-        return pbs_res;
-    } else {
-        size_t reused = (pbs_res == 0) ? size : 0;
-        pvebackup_add_transfered_bytes(size, !buf ? size : 0, reused);
+        pbs_res = proxmox_backup_co_write_data(backup_state.pbs, di->dev_id,
+            is_zero_block ? NULL : buf + transferred, start + transferred,
+            to_transfer, &local_err);
+        transferred += to_transfer;
+
+        if (pbs_res < 0) {
+            pvebackup_propagate_error(local_err);
+            qemu_co_mutex_unlock(&backup_state.dump_callback_mutex);
+            return pbs_res;
+        }
+
+        reused += pbs_res == 0 ? to_transfer : 0;
     }
 
+    qemu_co_mutex_unlock(&backup_state.dump_callback_mutex);
+    pvebackup_add_transfered_bytes(size, is_zero_block ? size : 0, reused);
+
     return size;
 }
 
@@ -180,6 +197,7 @@ pvebackup_co_dump_vma_cb(
     int ret = -1;
 
     assert(backup_state.vmaw);
+    assert(buf);
 
     uint64_t remaining = size;
 
@@ -206,9 +224,7 @@ pvebackup_co_dump_vma_cb(
         qemu_co_mutex_unlock(&backup_state.dump_callback_mutex);
 
         ++cluster_num;
-        if (buf) {
-            buf += VMA_CLUSTER_SIZE;
-        }
+        buf += VMA_CLUSTER_SIZE;
         if (ret < 0) {
             Error *local_err = NULL;
             vma_writer_error_propagate(backup_state.vmaw, &local_err);
@@ -566,6 +582,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;
@@ -689,6 +709,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,
@@ -698,8 +719,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,
@@ -718,6 +741,8 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
             PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
             l = g_list_next(l);
 
+            di->block_size = dump_cb_block_size;
+
             const char *devname = bdrv_get_device_name(di->bs);
 
             BdrvDirtyBitmap *bitmap = bdrv_find_dirty_bitmap(di->bs, PBS_BITMAP_NAME);
@@ -938,6 +963,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,
@@ -948,6 +975,8 @@ UuidInfo *qmp_backup(
         .backup_file = backup_file,
         .has_password = has_password,
         .password = password,
+        .has_keyfile = has_keyfile,
+        .keyfile = keyfile,
         .has_key_password = has_key_password,
         .key_password = key_password,
         .has_fingerprint = has_fingerprint,
@@ -958,6 +987,10 @@ UuidInfo *qmp_backup(
         .backup_time = backup_time,
         .has_use_dirty_bitmap = has_use_dirty_bitmap,
         .use_dirty_bitmap = use_dirty_bitmap,
+        .has_compress = has_compress,
+        .compress = compress,
+        .has_encrypt = has_encrypt,
+        .encrypt = encrypt,
         .has_format = has_format,
         .format = format,
         .has_config_file = has_config_file,
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 992e6c1e3f..5ac6276dc1 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -818,6 +818,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
 #
 ##
@@ -829,6 +833,8 @@
                                     '*backup-id': 'str',
                                     '*backup-time': 'int',
                                     '*use-dirty-bitmap': 'bool',
+                                    '*compress': 'bool',
+                                    '*encrypt': 'bool',
                                     '*format': 'BackupFormat',
                                     '*config-file': 'str',
                                     '*firewall-file': 'str',
