]> git.proxmox.com Git - pve-qemu-kvm.git/blame - debian/patches/backup-add-pve-monitor-commands.patch
refer to public git server
[pve-qemu-kvm.git] / debian / patches / backup-add-pve-monitor-commands.patch
CommitLineData
cbf9030a
DM
1Index: new/blockdev.c
2===================================================================
d1bb3152 3--- new.orig/blockdev.c 2013-12-03 07:34:22.000000000 +0100
b07588bd 4+++ new/blockdev.c 2013-12-03 08:50:24.000000000 +0100
cbf9030a
DM
5@@ -45,6 +45,7 @@
6 #include "qmp-commands.h"
7 #include "trace.h"
8 #include "sysemu/arch_init.h"
9+#include "vma.h"
10
11 static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives);
12
b07588bd 13@@ -1438,6 +1439,419 @@
cbf9030a
DM
14 }
15 }
16
17+/* PVE backup related function */
18+
19+static struct PVEBackupState {
20+ Error *error;
21+ bool cancel;
22+ uuid_t uuid;
23+ char uuid_str[37];
24+ int64_t speed;
25+ time_t start_time;
26+ time_t end_time;
27+ char *backup_file;
28+ VmaWriter *vmaw;
29+ GList *di_list;
30+ size_t total;
31+ size_t transferred;
32+ size_t zero_bytes;
33+} backup_state;
34+
35+typedef struct PVEBackupDevInfo {
36+ BlockDriverState *bs;
37+ uint8_t dev_id;
38+ //bool started;
39+ bool completed;
40+} PVEBackupDevInfo;
41+
42+static void pvebackup_run_next_job(void);
43+
44+static int pvebackup_dump_cb(void *opaque, BlockDriverState *bs,
45+ int64_t cluster_num, unsigned char *buf)
46+{
47+ PVEBackupDevInfo *di = opaque;
48+
49+ assert(backup_state.vmaw);
50+
51+ size_t zero_bytes = 0;
52+ return vma_writer_write(backup_state.vmaw, di->dev_id, cluster_num,
53+ buf, &zero_bytes);
54+}
55+
56+static void pvebackup_update_status(void)
57+{
58+ g_assert(backup_state.vmaw);
59+
60+ VmaStatus vmastat;
61+
62+ vma_writer_get_status(backup_state.vmaw, &vmastat);
63+
64+ uint64_t total = 0;
65+ uint64_t transferred = 0;
66+ uint64_t zero_bytes = 0;
67+
68+ int i;
69+ for (i = 0; i < 256; i++) {
70+ if (vmastat.stream_info[i].size) {
71+ total += vmastat.stream_info[i].size;
72+ transferred += vmastat.stream_info[i].transferred;
73+ zero_bytes += vmastat.stream_info[i].zero_bytes;
74+ }
75+ }
76+
77+ backup_state.total = total;
78+ backup_state.transferred = transferred;
79+ backup_state.zero_bytes = zero_bytes;
80+}
81+
82+static void pvebackup_cleanup(void)
83+{
84+ if (backup_state.vmaw) {
85+ backup_state.end_time = time(NULL);
86+ Error *local_err = NULL;
87+ pvebackup_update_status();
88+ vma_writer_close(backup_state.vmaw, &local_err);
89+ error_propagate(&backup_state.error, local_err);
90+ backup_state.vmaw = NULL;
91+ }
92+
93+ if (backup_state.di_list) {
94+ GList *l = backup_state.di_list;
95+ while (l) {
96+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
97+ l = g_list_next(l);
98+ g_free(di);
99+ }
100+ g_list_free(backup_state.di_list);
101+ backup_state.di_list = NULL;
102+ }
103+}
104+
105+static void pvebackup_complete_cb(void *opaque, int ret)
106+{
107+ PVEBackupDevInfo *di = opaque;
108+
109+ assert(backup_state.vmaw);
110+
111+ di->completed = true;
b07588bd 112+ di->bs = NULL;
cbf9030a
DM
113+
114+ vma_writer_close_stream(backup_state.vmaw, di->dev_id);
115+
116+ if (!backup_state.cancel) {
117+ pvebackup_run_next_job();
118+ }
119+}
120+
0c5f6a91 121+static void pvebackup_cancel(void *opaque)
cbf9030a
DM
122+{
123+ backup_state.cancel = true;
124+
125+ if (!backup_state.error) {
126+ error_setg(&backup_state.error, "backup cancelled");
127+ }
128+
129+ /* drain all i/o (awake jobs waiting for aio) */
130+ bdrv_drain_all();
131+
cbf9030a
DM
132+ GList *l = backup_state.di_list;
133+ while (l) {
134+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
135+ l = g_list_next(l);
b07588bd
DM
136+ if (!di->completed && di->bs) {
137+ BlockJob *job = di->bs->job;
138+ if (job) {
139+ if (!di->completed) {
140+ block_job_cancel_sync(job);
141+ }
cbf9030a
DM
142+ }
143+ }
144+ }
145+
146+ pvebackup_cleanup();
147+}
148+
149+void qmp_backup_cancel(Error **errp)
150+{
0c5f6a91
DM
151+ Coroutine *co = qemu_coroutine_create(pvebackup_cancel);
152+ qemu_coroutine_enter(co, NULL);
153+
154+ while (backup_state.vmaw) {
155+ qemu_aio_wait();
156+ }
cbf9030a
DM
157+}
158+
159+static void pvebackup_run_next_job(void)
160+{
161+ GList *l = backup_state.di_list;
162+ while (l) {
163+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
164+ l = g_list_next(l);
b07588bd
DM
165+ if (!di->completed && di->bs && di->bs->job) {
166+ BlockJob *job = di->bs->job;
bd240f3b 167+ if (block_job_is_paused(job)) {
cbf9030a
DM
168+ bool cancel = backup_state.error || backup_state.cancel;
169+ if (cancel) {
bd240f3b 170+ block_job_cancel(job);
cbf9030a 171+ } else {
bd240f3b 172+ block_job_resume(job);
cbf9030a
DM
173+ }
174+ }
175+ return;
176+ }
177+ }
178+
179+ pvebackup_cleanup();
180+}
181+
182+char *qmp_backup(const char *backup_file, bool has_format,
183+ BackupFormat format,
184+ bool has_config_file, const char *config_file,
185+ bool has_devlist, const char *devlist,
186+ bool has_speed, int64_t speed, Error **errp)
187+{
188+ BlockDriverState *bs;
189+ Error *local_err = NULL;
190+ uuid_t uuid;
191+ VmaWriter *vmaw = NULL;
192+ gchar **devs = NULL;
193+ GList *di_list = NULL;
194+ GList *l;
195+
196+ if (backup_state.di_list) {
197+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
198+ "previous backup not finished");
199+ return NULL;
200+ }
201+
202+ /* Todo: try to auto-detect format based on file name */
203+ format = has_format ? format : BACKUP_FORMAT_VMA;
204+
205+ if (format != BACKUP_FORMAT_VMA) {
206+ error_set(errp, ERROR_CLASS_GENERIC_ERROR, "unknown backup format");
207+ return NULL;
208+ }
209+
210+ if (has_devlist) {
211+ devs = g_strsplit_set(devlist, ",;:", -1);
212+
213+ gchar **d = devs;
214+ while (d && *d) {
215+ bs = bdrv_find(*d);
216+ if (bs) {
217+ if (bdrv_is_read_only(bs)) {
218+ error_set(errp, QERR_DEVICE_IS_READ_ONLY, *d);
219+ goto err;
220+ }
221+ if (!bdrv_is_inserted(bs)) {
222+ error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, *d);
223+ goto err;
224+ }
225+ PVEBackupDevInfo *di = g_new0(PVEBackupDevInfo, 1);
226+ di->bs = bs;
227+ di_list = g_list_append(di_list, di);
228+ } else {
229+ error_set(errp, QERR_DEVICE_NOT_FOUND, *d);
230+ goto err;
231+ }
232+ d++;
233+ }
234+
235+ } else {
236+
237+ bs = NULL;
238+ while ((bs = bdrv_next(bs))) {
239+
240+ if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) {
241+ continue;
242+ }
243+
244+ PVEBackupDevInfo *di = g_new0(PVEBackupDevInfo, 1);
245+ di->bs = bs;
246+ di_list = g_list_append(di_list, di);
247+ }
248+ }
249+
250+ if (!di_list) {
251+ error_set(errp, ERROR_CLASS_GENERIC_ERROR, "empty device list");
252+ goto err;
253+ }
254+
255+ l = di_list;
256+ while (l) {
257+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
258+ l = g_list_next(l);
259+ if (di->bs->job) {
260+ error_set(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(di->bs));
261+ goto err;
262+ }
263+ }
264+
265+ uuid_generate(uuid);
266+
267+ vmaw = vma_writer_create(backup_file, uuid, &local_err);
268+ if (!vmaw) {
269+ if (error_is_set(&local_err)) {
270+ error_propagate(errp, local_err);
271+ }
272+ goto err;
273+ }
274+
275+ /* register all devices for vma writer */
276+ l = di_list;
277+ while (l) {
278+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
279+ l = g_list_next(l);
280+
281+ int64_t size = bdrv_getlength(di->bs);
282+ const char *devname = bdrv_get_device_name(di->bs);
283+ di->dev_id = vma_writer_register_stream(vmaw, devname, size);
284+ if (di->dev_id <= 0) {
285+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
286+ "register_stream failed");
287+ goto err;
288+ }
289+ }
290+
291+ /* add configuration file to archive */
292+ if (has_config_file) {
293+ char *cdata = NULL;
294+ gsize clen = 0;
295+ GError *err = NULL;
296+ if (!g_file_get_contents(config_file, &cdata, &clen, &err)) {
297+ error_setg(errp, "unable to read file '%s'", config_file);
298+ goto err;
299+ }
300+
301+ const char *basename = g_path_get_basename(config_file);
302+ if (vma_writer_add_config(vmaw, basename, cdata, clen) != 0) {
303+ error_setg(errp, "unable to add config data to vma archive");
304+ g_free(cdata);
305+ goto err;
306+ }
307+ g_free(cdata);
308+ }
309+
310+ /* initialize global backup_state now */
311+
312+ backup_state.cancel = false;
313+
314+ if (backup_state.error) {
315+ error_free(backup_state.error);
316+ backup_state.error = NULL;
317+ }
318+
319+ backup_state.speed = (has_speed && speed > 0) ? speed : 0;
320+
321+ backup_state.start_time = time(NULL);
322+ backup_state.end_time = 0;
323+
324+ if (backup_state.backup_file) {
325+ g_free(backup_state.backup_file);
326+ }
327+ backup_state.backup_file = g_strdup(backup_file);
328+
329+ backup_state.vmaw = vmaw;
330+
331+ uuid_copy(backup_state.uuid, uuid);
332+ uuid_unparse_lower(uuid, backup_state.uuid_str);
333+
334+ backup_state.di_list = di_list;
335+
336+ pvebackup_update_status();
337+
338+ /* start all jobs (paused state) */
339+ l = di_list;
340+ while (l) {
341+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
342+ l = g_list_next(l);
343+
344+ backup_start(di->bs, NULL, speed, MIRROR_SYNC_MODE_FULL,
345+ BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT,
bd240f3b
DM
346+ pvebackup_dump_cb, pvebackup_complete_cb, di,
347+ true, &local_err);
cbf9030a
DM
348+ if (local_err != NULL) {
349+ error_setg(&backup_state.error, "backup_job_create failed");
0c5f6a91 350+ pvebackup_cancel(NULL);
cbf9030a
DM
351+ }
352+ }
353+
354+ if (!backup_state.error) {
355+ pvebackup_run_next_job(); // run one job
356+ }
357+
358+ return g_strdup(backup_state.uuid_str);
359+
360+err:
361+
362+ l = di_list;
363+ while (l) {
364+ g_free(l->data);
365+ l = g_list_next(l);
366+ }
367+ g_list_free(di_list);
368+
369+ if (devs) {
370+ g_strfreev(devs);
371+ }
372+
373+ if (vmaw) {
374+ Error *err = NULL;
375+ vma_writer_close(vmaw, &err);
376+ unlink(backup_file);
377+ }
378+
379+ return NULL;
380+}
381+
382+BackupStatus *qmp_query_backup(Error **errp)
383+{
384+ BackupStatus *info = g_malloc0(sizeof(*info));
385+
386+ if (!backup_state.start_time) {
387+ /* not started, return {} */
388+ return info;
389+ }
390+
391+ info->has_status = true;
392+ info->has_start_time = true;
393+ info->start_time = backup_state.start_time;
394+
395+ if (backup_state.backup_file) {
396+ info->has_backup_file = true;
397+ info->backup_file = g_strdup(backup_state.backup_file);
398+ }
399+
400+ info->has_uuid = true;
401+ info->uuid = g_strdup(backup_state.uuid_str);
402+
403+ if (backup_state.end_time) {
404+ if (backup_state.error) {
405+ info->status = g_strdup("error");
406+ info->has_errmsg = true;
407+ info->errmsg = g_strdup(error_get_pretty(backup_state.error));
408+ } else {
409+ info->status = g_strdup("done");
410+ }
411+ info->has_end_time = true;
412+ info->end_time = backup_state.end_time;
413+ } else {
414+ info->status = g_strdup("active");
415+ }
416+
417+ if (backup_state.vmaw) {
418+ pvebackup_update_status();
419+ }
420+
421+ info->has_total = true;
422+ info->total = backup_state.total;
423+ info->has_zero_bytes = true;
424+ info->zero_bytes = backup_state.zero_bytes;
425+ info->has_transferred = true;
426+ info->transferred = backup_state.transferred;
427+
428+ return info;
429+}
430
431 static void eject_device(BlockDriverState *bs, int force, Error **errp)
432 {
433Index: new/hmp-commands.hx
434===================================================================
d1bb3152
DM
435--- new.orig/hmp-commands.hx 2013-12-03 06:36:18.000000000 +0100
436+++ new/hmp-commands.hx 2013-12-03 07:34:22.000000000 +0100
cbf9030a
DM
437@@ -83,6 +83,35 @@
438 Copy data from a backing file into a block device.
439 ETEXI
440
441+ {
442+ .name = "backup",
443+ .args_type = "backupfile:s,speed:o?,devlist:s?",
444+ .params = "backupfile [speed [devlist]]",
445+ .help = "create a VM Backup.",
446+ .mhandler.cmd = hmp_backup,
447+ },
448+
449+STEXI
450+@item backup
451+@findex backup
452+Create a VM backup.
453+ETEXI
454+
455+ {
456+ .name = "backup_cancel",
457+ .args_type = "",
458+ .params = "",
459+ .help = "cancel the current VM backup",
460+ .mhandler.cmd = hmp_backup_cancel,
461+ },
462+
463+STEXI
464+@item backup_cancel
465+@findex backup_cancel
466+Cancel the current VM backup.
467+
468+ETEXI
469+
470 {
471 .name = "block_job_set_speed",
472 .args_type = "device:B,speed:o",
473@@ -1692,6 +1721,8 @@
474 show CPU statistics
475 @item info usernet
476 show user network stack connection states
477+@item info backup
478+show backup status
479 @item info migrate
480 show migration status
481 @item info migrate_capabilities
482Index: new/hmp.c
483===================================================================
d1bb3152
DM
484--- new.orig/hmp.c 2013-12-03 07:34:22.000000000 +0100
485+++ new/hmp.c 2013-12-03 07:34:22.000000000 +0100
cbf9030a
DM
486@@ -133,6 +133,38 @@
487 qapi_free_MouseInfoList(mice_list);
488 }
489
490+void hmp_info_backup(Monitor *mon, const QDict *qdict)
491+{
492+ BackupStatus *info;
493+
494+ info = qmp_query_backup(NULL);
495+ if (info->has_status) {
496+ if (info->has_errmsg) {
497+ monitor_printf(mon, "Backup status: %s - %s\n",
498+ info->status, info->errmsg);
499+ } else {
500+ monitor_printf(mon, "Backup status: %s\n", info->status);
501+ }
502+ }
503+ if (info->has_backup_file) {
504+ int per = (info->has_total && info->total &&
505+ info->has_transferred && info->transferred) ?
506+ (info->transferred * 100)/info->total : 0;
507+ int zero_per = (info->has_total && info->total &&
508+ info->has_zero_bytes && info->zero_bytes) ?
509+ (info->zero_bytes * 100)/info->total : 0;
510+ monitor_printf(mon, "Backup file: %s\n", info->backup_file);
511+ monitor_printf(mon, "Backup uuid: %s\n", info->uuid);
512+ monitor_printf(mon, "Total size: %zd\n", info->total);
513+ monitor_printf(mon, "Transferred bytes: %zd (%d%%)\n",
514+ info->transferred, per);
515+ monitor_printf(mon, "Zero bytes: %zd (%d%%)\n",
516+ info->zero_bytes, zero_per);
517+ }
518+
519+ qapi_free_BackupStatus(info);
520+}
521+
522 void hmp_info_migrate(Monitor *mon, const QDict *qdict)
523 {
524 MigrationInfo *info;
525@@ -1194,6 +1226,37 @@
526 hmp_handle_error(mon, &error);
527 }
528
529+void hmp_backup_cancel(Monitor *mon, const QDict *qdict)
530+{
531+ Error *errp = NULL;
532+
533+ qmp_backup_cancel(&errp);
534+
535+ if (error_is_set(&errp)) {
536+ monitor_printf(mon, "%s\n", error_get_pretty(errp));
537+ error_free(errp);
538+ return;
539+ }
540+}
541+
542+void hmp_backup(Monitor *mon, const QDict *qdict)
543+{
544+ const char *backup_file = qdict_get_str(qdict, "backup-file");
545+ const char *devlist = qdict_get_try_str(qdict, "devlist");
546+ int64_t speed = qdict_get_try_int(qdict, "speed", 0);
547+
548+ Error *errp = NULL;
549+
550+ qmp_backup(backup_file, true, BACKUP_FORMAT_VMA, false, NULL, !!devlist,
551+ devlist, qdict_haskey(qdict, "speed"), speed, &errp);
552+
553+ if (error_is_set(&errp)) {
554+ monitor_printf(mon, "%s\n", error_get_pretty(errp));
555+ error_free(errp);
556+ return;
557+ }
558+}
559+
560 void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict)
561 {
562 Error *error = NULL;
563Index: new/hmp.h
564===================================================================
d1bb3152
DM
565--- new.orig/hmp.h 2013-12-03 06:36:18.000000000 +0100
566+++ new/hmp.h 2013-12-03 07:34:22.000000000 +0100
cbf9030a
DM
567@@ -28,6 +28,7 @@
568 void hmp_info_migrate(Monitor *mon, const QDict *qdict);
569 void hmp_info_migrate_capabilities(Monitor *mon, const QDict *qdict);
570 void hmp_info_migrate_cache_size(Monitor *mon, const QDict *qdict);
571+void hmp_info_backup(Monitor *mon, const QDict *qdict);
572 void hmp_info_cpus(Monitor *mon, const QDict *qdict);
573 void hmp_info_block(Monitor *mon, const QDict *qdict);
574 void hmp_info_blockstats(Monitor *mon, const QDict *qdict);
575@@ -69,6 +70,8 @@
576 void hmp_change(Monitor *mon, const QDict *qdict);
577 void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict);
578 void hmp_block_stream(Monitor *mon, const QDict *qdict);
579+void hmp_backup(Monitor *mon, const QDict *qdict);
580+void hmp_backup_cancel(Monitor *mon, const QDict *qdict);
581 void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict);
582 void hmp_block_job_cancel(Monitor *mon, const QDict *qdict);
583 void hmp_block_job_pause(Monitor *mon, const QDict *qdict);
584Index: new/monitor.c
585===================================================================
d1bb3152
DM
586--- new.orig/monitor.c 2013-12-03 06:36:18.000000000 +0100
587+++ new/monitor.c 2013-12-03 07:34:22.000000000 +0100
cbf9030a
DM
588@@ -2880,6 +2880,13 @@
589 },
590 #endif
591 {
592+ .name = "backup",
593+ .args_type = "",
594+ .params = "",
595+ .help = "show backup status",
596+ .mhandler.cmd = hmp_info_backup,
597+ },
598+ {
599 .name = "migrate",
600 .args_type = "",
601 .params = "",
602Index: new/qapi-schema.json
603===================================================================
d1bb3152
DM
604--- new.orig/qapi-schema.json 2013-12-03 07:34:22.000000000 +0100
605+++ new/qapi-schema.json 2013-12-03 07:34:22.000000000 +0100
cbf9030a
DM
606@@ -547,6 +547,95 @@
607 ##
608 { 'command': 'query-events', 'returns': ['EventInfo'] }
609
610+# @BackupStatus:
611+#
612+# Detailed backup status.
613+#
614+# @status: #optional string describing the current backup status.
615+# This can be 'active', 'done', 'error'. If this field is not
616+# returned, no backup process has been initiated
617+#
618+# @errmsg: #optional error message (only returned if status is 'error')
619+#
620+# @total: #optional total amount of bytes involved in the backup process
621+#
622+# @transferred: #optional amount of bytes already backed up.
623+#
624+# @zero-bytes: #optional amount of 'zero' bytes detected.
625+#
626+# @start-time: #optional time (epoch) when backup job started.
627+#
628+# @end-time: #optional time (epoch) when backup job finished.
629+#
630+# @backupfile: #optional backup file name
631+#
632+# @uuid: #optional uuid for this backup job
633+#
634+##
635+{ 'type': 'BackupStatus',
636+ 'data': {'*status': 'str', '*errmsg': 'str', '*total': 'int',
637+ '*transferred': 'int', '*zero-bytes': 'int',
638+ '*start-time': 'int', '*end-time': 'int',
639+ '*backup-file': 'str', '*uuid': 'str' } }
640+
641+##
642+# @BackupFormat
643+#
644+# An enumeration of supported backup formats.
645+#
646+# @vma: Proxmox vma backup format
647+##
648+{ 'enum': 'BackupFormat',
649+ 'data': [ 'vma' ] }
650+
651+##
652+# @backup:
653+#
654+# Starts a VM backup.
655+#
656+# @backup-file: the backup file name
657+#
658+# @format: format of the backup file
659+#
660+# @config-filename: #optional name of a configuration file to include into
661+# the backup archive.
662+#
663+# @speed: #optional the maximum speed, in bytes per second
664+#
665+# @devlist: #optional list of block device names (separated by ',', ';'
666+# or ':'). By default the backup includes all writable block devices.
667+#
668+# Returns: the uuid of the backup job
669+#
670+##
671+{ 'command': 'backup', 'data': { 'backup-file': 'str',
672+ '*format': 'BackupFormat',
673+ '*config-file': 'str',
674+ '*devlist': 'str', '*speed': 'int' },
675+ 'returns': 'str' }
676+
677+##
678+# @query-backup
679+#
680+# Returns information about current/last backup task.
681+#
682+# Returns: @BackupStatus
683+#
684+##
685+{ 'command': 'query-backup', 'returns': 'BackupStatus' }
686+
687+##
688+# @backup-cancel
689+#
690+# Cancel the current executing backup process.
691+#
692+# Returns: nothing on success
693+#
694+# Notes: This command succeeds even if there is no backup process running.
695+#
696+##
697+{ 'command': 'backup-cancel' }
698+
699 ##
700 # @MigrationStats
701 #
702Index: new/qmp-commands.hx
703===================================================================
d1bb3152
DM
704--- new.orig/qmp-commands.hx 2013-12-03 07:34:22.000000000 +0100
705+++ new/qmp-commands.hx 2013-12-03 07:34:22.000000000 +0100
cbf9030a
DM
706@@ -966,6 +966,24 @@
707 EQMP
708
709 {
710+ .name = "backup",
711+ .args_type = "backup-file:s,format:s?,config-file:F?,speed:o?,devlist:s?",
712+ .mhandler.cmd_new = qmp_marshal_input_backup,
713+ },
714+
715+ {
716+ .name = "backup-cancel",
717+ .args_type = "",
718+ .mhandler.cmd_new = qmp_marshal_input_backup_cancel,
719+ },
720+
721+ {
722+ .name = "query-backup",
723+ .args_type = "",
724+ .mhandler.cmd_new = qmp_marshal_input_query_backup,
725+ },
726+
727+ {
728 .name = "block-job-set-speed",
729 .args_type = "device:B,speed:o",
730 .mhandler.cmd_new = qmp_marshal_input_block_job_set_speed,