bf251437e9
Many changes were necessary this time around: * QAPI was changed to avoid redundant has_* variables, see commit 44ea9d9be3 ("qapi: Start to elide redundant has_FOO in generated C") for details. This affected many QMP commands added by Proxmox too. * Pending querying for migration got split into two functions, one to estimate, one for exact value, see commit c8df4a7aef ("migration: Split save_live_pending() into state_pending_*") for details. Relevant for savevm-async and PBS dirty bitmap. * Some block (driver) functions got converted to coroutines, so the Proxmox block drivers needed to be adapted. * Alloc track auto-detaching during PBS live restore got broken by AioContext-related changes resulting in a deadlock. The current, hacky method was replaced by a simpler one. Stefan apparently ran into a problem with that when he wrote the driver, but there were improvements in the stream job code since then and I didn't manage to reproduce the issue. It's a separate patch "alloc-track: fix deadlock during drop" for now, you can find the details there. * Async snapshot-related changes: - The pending querying got adapted to the above-mentioned split and a patch is added to optimize it/make it more similar to what upstream code does. - Added initialization of the compression counters (for future-proofing). - It's necessary the hold the BQL (big QEMU lock = iothread mutex) during the setup phase, because block layer functions are used there and not doing so leads to racy, hard-to-debug crashes or hangs. It's necessary to change some upstream code too for this, a version of the patch "migration: for snapshots, hold the BQL during setup callbacks" is intended to be upstreamed. - Need to take the bdrv graph read lock before flushing. * hmp_info_balloon was moved to a different file. * Needed to include a new headers from time to time to still get the correct functions. Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
596 lines
21 KiB
Diff
596 lines
21 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Stefan Reiter <s.reiter@proxmox.com>
|
|
Date: Tue, 26 Jan 2021 15:45:30 +0100
|
|
Subject: [PATCH] PVE: Use coroutine QMP for backup/cancel_backup
|
|
|
|
Finally turn backup QMP calls into coroutines, now that it's possible.
|
|
This has the benefit that calls are asynchronous to the main loop, i.e.
|
|
long running operations like connecting to a PBS server will no longer
|
|
hang the VM.
|
|
|
|
Additionally, it allows us to get rid of block_on_coroutine_fn, which
|
|
was always a hacky workaround.
|
|
|
|
While we're already spring cleaning, also remove the QmpBackupTask
|
|
struct, since we can now put the 'prepare' function directly into
|
|
qmp_backup and thus no longer need those giant walls of text.
|
|
|
|
(Note that for our patches to work with 5.2.0 this change is actually
|
|
required, otherwise monitor_get_fd() fails as we're not in a QMP
|
|
coroutine, but one we start ourselves - we could of course set the
|
|
monitor for that coroutine ourselves, but let's just fix it the right
|
|
way instead)
|
|
|
|
Signed-off-by: Stefan Reiter <s.reiter@proxmox.com>
|
|
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
|
|
[FE: adapt to QAPI changes
|
|
call coroutine version of is_inserted()]
|
|
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
|
|
---
|
|
block/monitor/block-hmp-cmds.c | 4 +-
|
|
hmp-commands.hx | 2 +
|
|
proxmox-backup-client.c | 31 -----
|
|
pve-backup.c | 220 +++++++++++----------------------
|
|
qapi/block-core.json | 4 +-
|
|
5 files changed, 79 insertions(+), 182 deletions(-)
|
|
|
|
diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c
|
|
index 6a6ed6d0e7..bcf5849196 100644
|
|
--- a/block/monitor/block-hmp-cmds.c
|
|
+++ b/block/monitor/block-hmp-cmds.c
|
|
@@ -1028,7 +1028,7 @@ void hmp_change_medium(Monitor *mon, const char *device, const char *target,
|
|
!!read_only, read_only_mode, errp);
|
|
}
|
|
|
|
-void hmp_backup_cancel(Monitor *mon, const QDict *qdict)
|
|
+void coroutine_fn hmp_backup_cancel(Monitor *mon, const QDict *qdict)
|
|
{
|
|
Error *error = NULL;
|
|
|
|
@@ -1037,7 +1037,7 @@ void hmp_backup_cancel(Monitor *mon, const QDict *qdict)
|
|
hmp_handle_error(mon, error);
|
|
}
|
|
|
|
-void hmp_backup(Monitor *mon, const QDict *qdict)
|
|
+void coroutine_fn hmp_backup(Monitor *mon, const QDict *qdict)
|
|
{
|
|
Error *error = NULL;
|
|
|
|
diff --git a/hmp-commands.hx b/hmp-commands.hx
|
|
index 9b6b8e2e9c..896430dae8 100644
|
|
--- a/hmp-commands.hx
|
|
+++ b/hmp-commands.hx
|
|
@@ -111,6 +111,7 @@ ERST
|
|
"\n\t\t\t Use -d to dump data into a directory instead"
|
|
"\n\t\t\t of using VMA format.",
|
|
.cmd = hmp_backup,
|
|
+ .coroutine = true,
|
|
},
|
|
|
|
SRST
|
|
@@ -124,6 +125,7 @@ ERST
|
|
.params = "",
|
|
.help = "cancel the current VM backup",
|
|
.cmd = hmp_backup_cancel,
|
|
+ .coroutine = true,
|
|
},
|
|
|
|
SRST
|
|
diff --git a/proxmox-backup-client.c b/proxmox-backup-client.c
|
|
index 4ce7bc0b5e..0923037dec 100644
|
|
--- a/proxmox-backup-client.c
|
|
+++ b/proxmox-backup-client.c
|
|
@@ -5,37 +5,6 @@
|
|
|
|
/* Proxmox Backup Server client bindings using coroutines */
|
|
|
|
-typedef struct BlockOnCoroutineWrapper {
|
|
- AioContext *ctx;
|
|
- CoroutineEntry *entry;
|
|
- void *entry_arg;
|
|
- bool finished;
|
|
-} BlockOnCoroutineWrapper;
|
|
-
|
|
-static void coroutine_fn block_on_coroutine_wrapper(void *opaque)
|
|
-{
|
|
- BlockOnCoroutineWrapper *wrapper = opaque;
|
|
- wrapper->entry(wrapper->entry_arg);
|
|
- wrapper->finished = true;
|
|
- aio_wait_kick();
|
|
-}
|
|
-
|
|
-void block_on_coroutine_fn(CoroutineEntry *entry, void *entry_arg)
|
|
-{
|
|
- assert(!qemu_in_coroutine());
|
|
-
|
|
- AioContext *ctx = qemu_get_current_aio_context();
|
|
- BlockOnCoroutineWrapper wrapper = {
|
|
- .finished = false,
|
|
- .entry = entry,
|
|
- .entry_arg = entry_arg,
|
|
- .ctx = ctx,
|
|
- };
|
|
- Coroutine *wrapper_co = qemu_coroutine_create(block_on_coroutine_wrapper, &wrapper);
|
|
- aio_co_enter(ctx, wrapper_co);
|
|
- AIO_WAIT_WHILE(ctx, !wrapper.finished);
|
|
-}
|
|
-
|
|
// This is called from another thread, so we use aio_co_schedule()
|
|
static void proxmox_backup_schedule_wake(void *data) {
|
|
CoCtxData *waker = (CoCtxData *)data;
|
|
diff --git a/pve-backup.c b/pve-backup.c
|
|
index 5c9c153e31..378e4a9a63 100644
|
|
--- a/pve-backup.c
|
|
+++ b/pve-backup.c
|
|
@@ -356,7 +356,7 @@ static void job_cancel_bh(void *opaque) {
|
|
aio_co_enter(data->ctx, data->co);
|
|
}
|
|
|
|
-static void coroutine_fn pvebackup_co_cancel(void *opaque)
|
|
+void coroutine_fn qmp_backup_cancel(Error **errp)
|
|
{
|
|
Error *cancel_err = NULL;
|
|
error_setg(&cancel_err, "backup canceled");
|
|
@@ -393,11 +393,6 @@ static void coroutine_fn pvebackup_co_cancel(void *opaque)
|
|
qemu_co_mutex_unlock(&backup_state.backup_mutex);
|
|
}
|
|
|
|
-void qmp_backup_cancel(Error **errp)
|
|
-{
|
|
- block_on_coroutine_fn(pvebackup_co_cancel, NULL);
|
|
-}
|
|
-
|
|
// assumes the caller holds backup_mutex
|
|
static int coroutine_fn pvebackup_co_add_config(
|
|
const char *file,
|
|
@@ -531,42 +526,27 @@ static void create_backup_jobs_bh(void *opaque) {
|
|
aio_co_enter(data->ctx, data->co);
|
|
}
|
|
|
|
-typedef struct QmpBackupTask {
|
|
- const char *backup_file;
|
|
- const char *password;
|
|
- const char *keyfile;
|
|
- const char *key_password;
|
|
- const char *backup_id;
|
|
- bool has_backup_time;
|
|
- const char *fingerprint;
|
|
- int64_t backup_time;
|
|
- bool has_use_dirty_bitmap;
|
|
- bool use_dirty_bitmap;
|
|
- bool has_format;
|
|
- BackupFormat format;
|
|
- const char *config_file;
|
|
- const char *firewall_file;
|
|
- const char *devlist;
|
|
- bool has_compress;
|
|
- bool compress;
|
|
- bool has_encrypt;
|
|
- bool encrypt;
|
|
- bool has_speed;
|
|
- int64_t speed;
|
|
- Error **errp;
|
|
- UuidInfo *result;
|
|
-} QmpBackupTask;
|
|
-
|
|
-static void coroutine_fn pvebackup_co_prepare(void *opaque)
|
|
+UuidInfo coroutine_fn *qmp_backup(
|
|
+ const char *backup_file,
|
|
+ const char *password,
|
|
+ const char *keyfile,
|
|
+ const char *key_password,
|
|
+ const char *fingerprint,
|
|
+ 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,
|
|
+ const char *config_file,
|
|
+ const char *firewall_file,
|
|
+ const char *devlist,
|
|
+ bool has_speed, int64_t speed, Error **errp)
|
|
{
|
|
assert(qemu_in_coroutine());
|
|
|
|
qemu_co_mutex_lock(&backup_state.backup_mutex);
|
|
|
|
- QmpBackupTask *task = opaque;
|
|
-
|
|
- task->result = NULL; // just to be sure
|
|
-
|
|
BlockBackend *blk;
|
|
BlockDriverState *bs = NULL;
|
|
const char *backup_dir = NULL;
|
|
@@ -583,32 +563,32 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
|
|
const char *firewall_name = "qemu-server.fw";
|
|
|
|
if (backup_state.di_list) {
|
|
- error_set(task->errp, ERROR_CLASS_GENERIC_ERROR,
|
|
+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
|
|
"previous backup not finished");
|
|
qemu_co_mutex_unlock(&backup_state.backup_mutex);
|
|
- return;
|
|
+ return NULL;
|
|
}
|
|
|
|
/* Todo: try to auto-detect format based on file name */
|
|
- BackupFormat format = task->has_format ? task->format : BACKUP_FORMAT_VMA;
|
|
+ format = has_format ? format : BACKUP_FORMAT_VMA;
|
|
|
|
- if (task->devlist) {
|
|
- devs = g_strsplit_set(task->devlist, ",;:", -1);
|
|
+ if (devlist) {
|
|
+ devs = g_strsplit_set(devlist, ",;:", -1);
|
|
|
|
gchar **d = devs;
|
|
while (d && *d) {
|
|
blk = blk_by_name(*d);
|
|
if (blk) {
|
|
bs = blk_bs(blk);
|
|
- if (!bdrv_is_inserted(bs)) {
|
|
- error_setg(task->errp, QERR_DEVICE_HAS_NO_MEDIUM, *d);
|
|
+ if (!bdrv_co_is_inserted(bs)) {
|
|
+ error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, *d);
|
|
goto err;
|
|
}
|
|
PVEBackupDevInfo *di = g_new0(PVEBackupDevInfo, 1);
|
|
di->bs = bs;
|
|
di_list = g_list_append(di_list, di);
|
|
} else {
|
|
- error_set(task->errp, ERROR_CLASS_DEVICE_NOT_FOUND,
|
|
+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
|
|
"Device '%s' not found", *d);
|
|
goto err;
|
|
}
|
|
@@ -620,7 +600,7 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
|
|
|
|
bs = NULL;
|
|
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
|
|
- if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) {
|
|
+ if (!bdrv_co_is_inserted(bs) || bdrv_is_read_only(bs)) {
|
|
continue;
|
|
}
|
|
|
|
@@ -631,7 +611,7 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
|
|
}
|
|
|
|
if (!di_list) {
|
|
- error_set(task->errp, ERROR_CLASS_GENERIC_ERROR, "empty device list");
|
|
+ error_set(errp, ERROR_CLASS_GENERIC_ERROR, "empty device list");
|
|
goto err;
|
|
}
|
|
|
|
@@ -641,13 +621,13 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
|
|
while (l) {
|
|
PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
|
|
l = g_list_next(l);
|
|
- if (bdrv_op_is_blocked(di->bs, BLOCK_OP_TYPE_BACKUP_SOURCE, task->errp)) {
|
|
+ if (bdrv_op_is_blocked(di->bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
|
|
goto err;
|
|
}
|
|
|
|
ssize_t size = bdrv_getlength(di->bs);
|
|
if (size < 0) {
|
|
- error_setg_errno(task->errp, -size, "bdrv_getlength failed");
|
|
+ error_setg_errno(errp, -size, "bdrv_getlength failed");
|
|
goto err;
|
|
}
|
|
di->size = size;
|
|
@@ -674,47 +654,44 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
|
|
}
|
|
|
|
if (format == BACKUP_FORMAT_PBS) {
|
|
- if (!task->password) {
|
|
- error_set(task->errp, ERROR_CLASS_GENERIC_ERROR, "missing parameter 'password'");
|
|
+ if (!password) {
|
|
+ error_set(errp, ERROR_CLASS_GENERIC_ERROR, "missing parameter 'password'");
|
|
goto err_mutex;
|
|
}
|
|
- if (!task->backup_id) {
|
|
- error_set(task->errp, ERROR_CLASS_GENERIC_ERROR, "missing parameter 'backup-id'");
|
|
+ if (!backup_id) {
|
|
+ error_set(errp, ERROR_CLASS_GENERIC_ERROR, "missing parameter 'backup-id'");
|
|
goto err_mutex;
|
|
}
|
|
- if (!task->has_backup_time) {
|
|
- error_set(task->errp, ERROR_CLASS_GENERIC_ERROR, "missing parameter 'backup-time'");
|
|
+ if (!has_backup_time) {
|
|
+ error_set(errp, ERROR_CLASS_GENERIC_ERROR, "missing parameter 'backup-time'");
|
|
goto err_mutex;
|
|
}
|
|
|
|
int dump_cb_block_size = PROXMOX_BACKUP_DEFAULT_CHUNK_SIZE; // Hardcoded (4M)
|
|
firewall_name = "fw.conf";
|
|
|
|
- bool use_dirty_bitmap = task->has_use_dirty_bitmap && task->use_dirty_bitmap;
|
|
-
|
|
-
|
|
char *pbs_err = NULL;
|
|
pbs = proxmox_backup_new(
|
|
- task->backup_file,
|
|
- task->backup_id,
|
|
- task->backup_time,
|
|
+ backup_file,
|
|
+ backup_id,
|
|
+ backup_time,
|
|
dump_cb_block_size,
|
|
- task->password,
|
|
- task->keyfile,
|
|
- task->key_password,
|
|
- task->has_compress ? task->compress : true,
|
|
- task->has_encrypt ? task->encrypt : !!task->keyfile,
|
|
- task->fingerprint,
|
|
+ password,
|
|
+ keyfile,
|
|
+ key_password,
|
|
+ has_compress ? compress : true,
|
|
+ has_encrypt ? encrypt : !!keyfile,
|
|
+ fingerprint,
|
|
&pbs_err);
|
|
|
|
if (!pbs) {
|
|
- error_set(task->errp, ERROR_CLASS_GENERIC_ERROR,
|
|
+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
|
|
"proxmox_backup_new failed: %s", pbs_err);
|
|
proxmox_backup_free_error(pbs_err);
|
|
goto err_mutex;
|
|
}
|
|
|
|
- int connect_result = proxmox_backup_co_connect(pbs, task->errp);
|
|
+ int connect_result = proxmox_backup_co_connect(pbs, errp);
|
|
if (connect_result < 0)
|
|
goto err_mutex;
|
|
|
|
@@ -733,9 +710,9 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
|
|
BdrvDirtyBitmap *bitmap = bdrv_find_dirty_bitmap(di->bs, PBS_BITMAP_NAME);
|
|
bool expect_only_dirty = false;
|
|
|
|
- if (use_dirty_bitmap) {
|
|
+ if (has_use_dirty_bitmap && use_dirty_bitmap) {
|
|
if (bitmap == NULL) {
|
|
- bitmap = bdrv_create_dirty_bitmap(di->bs, dump_cb_block_size, PBS_BITMAP_NAME, task->errp);
|
|
+ bitmap = bdrv_create_dirty_bitmap(di->bs, dump_cb_block_size, PBS_BITMAP_NAME, errp);
|
|
if (!bitmap) {
|
|
goto err_mutex;
|
|
}
|
|
@@ -765,12 +742,12 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
|
|
}
|
|
}
|
|
|
|
- int dev_id = proxmox_backup_co_register_image(pbs, devname, di->size, expect_only_dirty, task->errp);
|
|
+ int dev_id = proxmox_backup_co_register_image(pbs, devname, di->size, expect_only_dirty, errp);
|
|
if (dev_id < 0) {
|
|
goto err_mutex;
|
|
}
|
|
|
|
- if (!(di->target = bdrv_backup_dump_create(dump_cb_block_size, di->size, pvebackup_co_dump_pbs_cb, di, task->errp))) {
|
|
+ if (!(di->target = bdrv_backup_dump_create(dump_cb_block_size, di->size, pvebackup_co_dump_pbs_cb, di, errp))) {
|
|
goto err_mutex;
|
|
}
|
|
|
|
@@ -784,10 +761,10 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
|
|
backup_state.stat.bitmap_list = g_list_append(backup_state.stat.bitmap_list, info);
|
|
}
|
|
} else if (format == BACKUP_FORMAT_VMA) {
|
|
- vmaw = vma_writer_create(task->backup_file, uuid, &local_err);
|
|
+ vmaw = vma_writer_create(backup_file, uuid, &local_err);
|
|
if (!vmaw) {
|
|
if (local_err) {
|
|
- error_propagate(task->errp, local_err);
|
|
+ error_propagate(errp, local_err);
|
|
}
|
|
goto err_mutex;
|
|
}
|
|
@@ -798,25 +775,25 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
|
|
PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
|
|
l = g_list_next(l);
|
|
|
|
- if (!(di->target = bdrv_backup_dump_create(VMA_CLUSTER_SIZE, di->size, pvebackup_co_dump_vma_cb, di, task->errp))) {
|
|
+ if (!(di->target = bdrv_backup_dump_create(VMA_CLUSTER_SIZE, di->size, pvebackup_co_dump_vma_cb, di, errp))) {
|
|
goto err_mutex;
|
|
}
|
|
|
|
const char *devname = bdrv_get_device_name(di->bs);
|
|
di->dev_id = vma_writer_register_stream(vmaw, devname, di->size);
|
|
if (di->dev_id <= 0) {
|
|
- error_set(task->errp, ERROR_CLASS_GENERIC_ERROR,
|
|
+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
|
|
"register_stream failed");
|
|
goto err_mutex;
|
|
}
|
|
}
|
|
} else if (format == BACKUP_FORMAT_DIR) {
|
|
- if (mkdir(task->backup_file, 0640) != 0) {
|
|
- error_setg_errno(task->errp, errno, "can't create directory '%s'\n",
|
|
- task->backup_file);
|
|
+ if (mkdir(backup_file, 0640) != 0) {
|
|
+ error_setg_errno(errp, errno, "can't create directory '%s'\n",
|
|
+ backup_file);
|
|
goto err_mutex;
|
|
}
|
|
- backup_dir = task->backup_file;
|
|
+ backup_dir = backup_file;
|
|
|
|
l = di_list;
|
|
while (l) {
|
|
@@ -830,34 +807,34 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
|
|
bdrv_img_create(di->targetfile, "raw", NULL, NULL, NULL,
|
|
di->size, flags, false, &local_err);
|
|
if (local_err) {
|
|
- error_propagate(task->errp, local_err);
|
|
+ error_propagate(errp, local_err);
|
|
goto err_mutex;
|
|
}
|
|
|
|
di->target = bdrv_open(di->targetfile, NULL, NULL, flags, &local_err);
|
|
if (!di->target) {
|
|
- error_propagate(task->errp, local_err);
|
|
+ error_propagate(errp, local_err);
|
|
goto err_mutex;
|
|
}
|
|
}
|
|
} else {
|
|
- error_set(task->errp, ERROR_CLASS_GENERIC_ERROR, "unknown backup format");
|
|
+ error_set(errp, ERROR_CLASS_GENERIC_ERROR, "unknown backup format");
|
|
goto err_mutex;
|
|
}
|
|
|
|
|
|
/* add configuration file to archive */
|
|
- if (task->config_file) {
|
|
- if (pvebackup_co_add_config(task->config_file, config_name, format, backup_dir,
|
|
- vmaw, pbs, task->errp) != 0) {
|
|
+ if (config_file) {
|
|
+ if (pvebackup_co_add_config(config_file, config_name, format, backup_dir,
|
|
+ vmaw, pbs, errp) != 0) {
|
|
goto err_mutex;
|
|
}
|
|
}
|
|
|
|
/* add firewall file to archive */
|
|
- if (task->firewall_file) {
|
|
- if (pvebackup_co_add_config(task->firewall_file, firewall_name, format, backup_dir,
|
|
- vmaw, pbs, task->errp) != 0) {
|
|
+ if (firewall_file) {
|
|
+ if (pvebackup_co_add_config(firewall_file, firewall_name, format, backup_dir,
|
|
+ vmaw, pbs, errp) != 0) {
|
|
goto err_mutex;
|
|
}
|
|
}
|
|
@@ -875,7 +852,7 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
|
|
if (backup_state.stat.backup_file) {
|
|
g_free(backup_state.stat.backup_file);
|
|
}
|
|
- backup_state.stat.backup_file = g_strdup(task->backup_file);
|
|
+ backup_state.stat.backup_file = g_strdup(backup_file);
|
|
|
|
uuid_copy(backup_state.stat.uuid, uuid);
|
|
uuid_unparse_lower(uuid, backup_state.stat.uuid_str);
|
|
@@ -890,7 +867,7 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
|
|
|
|
qemu_mutex_unlock(&backup_state.stat.lock);
|
|
|
|
- backup_state.speed = (task->has_speed && task->speed > 0) ? task->speed : 0;
|
|
+ backup_state.speed = (has_speed && speed > 0) ? speed : 0;
|
|
|
|
backup_state.vmaw = vmaw;
|
|
backup_state.pbs = pbs;
|
|
@@ -900,8 +877,6 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
|
|
uuid_info = g_malloc0(sizeof(*uuid_info));
|
|
uuid_info->UUID = uuid_str;
|
|
|
|
- task->result = uuid_info;
|
|
-
|
|
/* Run create_backup_jobs_bh outside of coroutine (in BH) but keep
|
|
* backup_mutex locked. This is fine, a CoMutex can be held across yield
|
|
* points, and we'll release it as soon as the BH reschedules us.
|
|
@@ -915,7 +890,7 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
|
|
qemu_coroutine_yield();
|
|
|
|
if (local_err) {
|
|
- error_propagate(task->errp, local_err);
|
|
+ error_propagate(errp, local_err);
|
|
goto err;
|
|
}
|
|
|
|
@@ -928,7 +903,7 @@ static void coroutine_fn pvebackup_co_prepare(void *opaque)
|
|
/* start the first job in the transaction */
|
|
job_txn_start_seq(backup_state.txn);
|
|
|
|
- return;
|
|
+ return uuid_info;
|
|
|
|
err_mutex:
|
|
qemu_mutex_unlock(&backup_state.stat.lock);
|
|
@@ -959,7 +934,7 @@ err:
|
|
if (vmaw) {
|
|
Error *err = NULL;
|
|
vma_writer_close(vmaw, &err);
|
|
- unlink(task->backup_file);
|
|
+ unlink(backup_file);
|
|
}
|
|
|
|
if (pbs) {
|
|
@@ -970,57 +945,8 @@ err:
|
|
rmdir(backup_dir);
|
|
}
|
|
|
|
- task->result = NULL;
|
|
-
|
|
qemu_co_mutex_unlock(&backup_state.backup_mutex);
|
|
- return;
|
|
-}
|
|
-
|
|
-UuidInfo *qmp_backup(
|
|
- const char *backup_file,
|
|
- const char *password,
|
|
- const char *keyfile,
|
|
- const char *key_password,
|
|
- const char *fingerprint,
|
|
- 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,
|
|
- const char *config_file,
|
|
- const char *firewall_file,
|
|
- const char *devlist,
|
|
- bool has_speed, int64_t speed, Error **errp)
|
|
-{
|
|
- QmpBackupTask task = {
|
|
- .backup_file = backup_file,
|
|
- .password = password,
|
|
- .keyfile = keyfile,
|
|
- .key_password = key_password,
|
|
- .fingerprint = fingerprint,
|
|
- .backup_id = backup_id,
|
|
- .has_backup_time = has_backup_time,
|
|
- .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,
|
|
- .config_file = config_file,
|
|
- .firewall_file = firewall_file,
|
|
- .devlist = devlist,
|
|
- .has_speed = has_speed,
|
|
- .speed = speed,
|
|
- .errp = errp,
|
|
- };
|
|
-
|
|
- block_on_coroutine_fn(pvebackup_co_prepare, &task);
|
|
-
|
|
- return task.result;
|
|
+ return NULL;
|
|
}
|
|
|
|
BackupStatus *qmp_query_backup(Error **errp)
|
|
diff --git a/qapi/block-core.json b/qapi/block-core.json
|
|
index e7412f6322..93d924ef79 100644
|
|
--- a/qapi/block-core.json
|
|
+++ b/qapi/block-core.json
|
|
@@ -937,7 +937,7 @@
|
|
'*config-file': 'str',
|
|
'*firewall-file': 'str',
|
|
'*devlist': 'str', '*speed': 'int' },
|
|
- 'returns': 'UuidInfo' }
|
|
+ 'returns': 'UuidInfo', 'coroutine': true }
|
|
|
|
##
|
|
# @query-backup:
|
|
@@ -959,7 +959,7 @@
|
|
# Notes: This command succeeds even if there is no backup process running.
|
|
#
|
|
##
|
|
-{ 'command': 'backup-cancel' }
|
|
+{ 'command': 'backup-cancel', 'coroutine': true }
|
|
|
|
##
|
|
# @ProxmoxSupportStatus:
|