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