198d2c6f2SDietmar Maurer /*
298d2c6f2SDietmar Maurer * QEMU backup
398d2c6f2SDietmar Maurer *
498d2c6f2SDietmar Maurer * Copyright (C) 2013 Proxmox Server Solutions
500e30f05SVladimir Sementsov-Ogievskiy * Copyright (c) 2019 Virtuozzo International GmbH.
698d2c6f2SDietmar Maurer *
798d2c6f2SDietmar Maurer * Authors:
898d2c6f2SDietmar Maurer * Dietmar Maurer (dietmar@proxmox.com)
998d2c6f2SDietmar Maurer *
1098d2c6f2SDietmar Maurer * This work is licensed under the terms of the GNU GPL, version 2 or later.
1198d2c6f2SDietmar Maurer * See the COPYING file in the top-level directory.
1298d2c6f2SDietmar Maurer *
1398d2c6f2SDietmar Maurer */
1498d2c6f2SDietmar Maurer
1580c71a24SPeter Maydell #include "qemu/osdep.h"
1698d2c6f2SDietmar Maurer
1798d2c6f2SDietmar Maurer #include "trace.h"
1898d2c6f2SDietmar Maurer #include "block/block.h"
1998d2c6f2SDietmar Maurer #include "block/block_int.h"
20c87621eaSJohn Snow #include "block/blockjob_int.h"
2149d3e828SWen Congyang #include "block/block_backup.h"
22beb5f545SVladimir Sementsov-Ogievskiy #include "block/block-copy.h"
23e2c1c34fSMarkus Armbruster #include "block/dirty-bitmap.h"
24da34e65cSMarkus Armbruster #include "qapi/error.h"
25f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
26373340b2SMax Reitz #include "sysemu/block-backend.h"
27b2f56462SFam Zheng #include "qemu/bitmap.h"
28a410a7f1SVladimir Sementsov-Ogievskiy #include "qemu/error-report.h"
2998d2c6f2SDietmar Maurer
30d003e0aeSVladimir Sementsov-Ogievskiy #include "block/copy-before-write.h"
3100e30f05SVladimir Sementsov-Ogievskiy
3298d2c6f2SDietmar Maurer typedef struct BackupBlockJob {
3398d2c6f2SDietmar Maurer BlockJob common;
34d003e0aeSVladimir Sementsov-Ogievskiy BlockDriverState *cbw;
352c8074c4SVladimir Sementsov-Ogievskiy BlockDriverState *source_bs;
36ff789bf5SVladimir Sementsov-Ogievskiy BlockDriverState *target_bs;
3762aa1fbeSJohn Snow
38d58d8453SJohn Snow BdrvDirtyBitmap *sync_bitmap;
3962aa1fbeSJohn Snow
40fc5d3f84SIan Main MirrorSyncMode sync_mode;
41c8b56501SJohn Snow BitmapSyncMode bitmap_mode;
4298d2c6f2SDietmar Maurer BlockdevOnError on_source_error;
4398d2c6f2SDietmar Maurer BlockdevOnError on_target_error;
4405df8a6aSKevin Wolf uint64_t len;
4516096a4dSJohn Snow int64_t cluster_size;
4686c6a3b6SVladimir Sementsov-Ogievskiy BackupPerf perf;
47a193b0f0SVladimir Sementsov-Ogievskiy
482c8074c4SVladimir Sementsov-Ogievskiy BlockCopyState *bcs;
4971eed4ceSVladimir Sementsov-Ogievskiy
5071eed4ceSVladimir Sementsov-Ogievskiy bool wait;
5171eed4ceSVladimir Sementsov-Ogievskiy BlockCopyCallState *bg_bcs_call;
5298d2c6f2SDietmar Maurer } BackupBlockJob;
5398d2c6f2SDietmar Maurer
54bd21935bSKevin Wolf static const BlockJobDriver backup_job_driver;
55bd21935bSKevin Wolf
backup_cleanup_sync_bitmap(BackupBlockJob * job,int ret)56b976ea3cSFam Zheng static void backup_cleanup_sync_bitmap(BackupBlockJob *job, int ret)
57b976ea3cSFam Zheng {
58b976ea3cSFam Zheng BdrvDirtyBitmap *bm;
59c23909e5SJohn Snow bool sync = (((ret == 0) || (job->bitmap_mode == BITMAP_SYNC_MODE_ALWAYS)) \
60c23909e5SJohn Snow && (job->bitmap_mode != BITMAP_SYNC_MODE_NEVER));
61b976ea3cSFam Zheng
62c23909e5SJohn Snow if (sync) {
63cf0cd293SJohn Snow /*
64c23909e5SJohn Snow * We succeeded, or we always intended to sync the bitmap.
65c23909e5SJohn Snow * Delete this bitmap and install the child.
66c23909e5SJohn Snow */
675deb6cbdSVladimir Sementsov-Ogievskiy bm = bdrv_dirty_bitmap_abdicate(job->sync_bitmap, NULL);
68c23909e5SJohn Snow } else {
69c23909e5SJohn Snow /*
70c23909e5SJohn Snow * We failed, or we never intended to sync the bitmap anyway.
71c23909e5SJohn Snow * Merge the successor back into the parent, keeping all data.
72cf0cd293SJohn Snow */
735deb6cbdSVladimir Sementsov-Ogievskiy bm = bdrv_reclaim_dirty_bitmap(job->sync_bitmap, NULL);
74c23909e5SJohn Snow }
75c23909e5SJohn Snow
76b976ea3cSFam Zheng assert(bm);
77c23909e5SJohn Snow
78c23909e5SJohn Snow if (ret < 0 && job->bitmap_mode == BITMAP_SYNC_MODE_ALWAYS) {
79c23909e5SJohn Snow /* If we failed and synced, merge in the bits we didn't copy: */
80397f4e9dSVladimir Sementsov-Ogievskiy bdrv_dirty_bitmap_merge_internal(bm, block_copy_dirty_bitmap(job->bcs),
81c23909e5SJohn Snow NULL, true);
82b976ea3cSFam Zheng }
83b976ea3cSFam Zheng }
84b976ea3cSFam Zheng
backup_commit(Job * job)854ad35181SKevin Wolf static void backup_commit(Job *job)
86c347b2c6SJohn Snow {
874ad35181SKevin Wolf BackupBlockJob *s = container_of(job, BackupBlockJob, common.job);
88c347b2c6SJohn Snow if (s->sync_bitmap) {
89c347b2c6SJohn Snow backup_cleanup_sync_bitmap(s, 0);
90c347b2c6SJohn Snow }
91c347b2c6SJohn Snow }
92c347b2c6SJohn Snow
backup_abort(Job * job)934ad35181SKevin Wolf static void backup_abort(Job *job)
94c347b2c6SJohn Snow {
954ad35181SKevin Wolf BackupBlockJob *s = container_of(job, BackupBlockJob, common.job);
96c347b2c6SJohn Snow if (s->sync_bitmap) {
97c347b2c6SJohn Snow backup_cleanup_sync_bitmap(s, -1);
98c347b2c6SJohn Snow }
99c347b2c6SJohn Snow }
100c347b2c6SJohn Snow
backup_clean(Job * job)1014ad35181SKevin Wolf static void backup_clean(Job *job)
102e8a40bf7SJohn Snow {
1034ad35181SKevin Wolf BackupBlockJob *s = container_of(job, BackupBlockJob, common.job);
104bdc4c4c5SMax Reitz block_job_remove_all_bdrv(&s->common);
105d003e0aeSVladimir Sementsov-Ogievskiy bdrv_cbw_drop(s->cbw);
106e8a40bf7SJohn Snow }
107e8a40bf7SJohn Snow
backup_do_checkpoint(BlockJob * job,Error ** errp)10849d3e828SWen Congyang void backup_do_checkpoint(BlockJob *job, Error **errp)
10949d3e828SWen Congyang {
11049d3e828SWen Congyang BackupBlockJob *backup_job = container_of(job, BackupBlockJob, common);
11149d3e828SWen Congyang
112bd21935bSKevin Wolf assert(block_job_driver(job) == &backup_job_driver);
11349d3e828SWen Congyang
11449d3e828SWen Congyang if (backup_job->sync_mode != MIRROR_SYNC_MODE_NONE) {
11549d3e828SWen Congyang error_setg(errp, "The backup job only supports block checkpoint in"
11649d3e828SWen Congyang " sync=none mode");
11749d3e828SWen Congyang return;
11849d3e828SWen Congyang }
11949d3e828SWen Congyang
120397f4e9dSVladimir Sementsov-Ogievskiy bdrv_set_dirty_bitmap(block_copy_dirty_bitmap(backup_job->bcs), 0,
121397f4e9dSVladimir Sementsov-Ogievskiy backup_job->len);
12249d3e828SWen Congyang }
12349d3e828SWen Congyang
backup_error_action(BackupBlockJob * job,bool read,int error)12498d2c6f2SDietmar Maurer static BlockErrorAction backup_error_action(BackupBlockJob *job,
12598d2c6f2SDietmar Maurer bool read, int error)
12698d2c6f2SDietmar Maurer {
12798d2c6f2SDietmar Maurer if (read) {
12881e254dcSKevin Wolf return block_job_error_action(&job->common, job->on_source_error,
12981e254dcSKevin Wolf true, error);
13098d2c6f2SDietmar Maurer } else {
13181e254dcSKevin Wolf return block_job_error_action(&job->common, job->on_target_error,
13281e254dcSKevin Wolf false, error);
13398d2c6f2SDietmar Maurer }
13498d2c6f2SDietmar Maurer }
13598d2c6f2SDietmar Maurer
backup_block_copy_callback(void * opaque)13671eed4ceSVladimir Sementsov-Ogievskiy static void coroutine_fn backup_block_copy_callback(void *opaque)
137d58d8453SJohn Snow {
13871eed4ceSVladimir Sementsov-Ogievskiy BackupBlockJob *s = opaque;
139dee81d51SKevin Wolf
14071eed4ceSVladimir Sementsov-Ogievskiy if (s->wait) {
14171eed4ceSVladimir Sementsov-Ogievskiy s->wait = false;
14271eed4ceSVladimir Sementsov-Ogievskiy aio_co_wake(s->common.job.co);
14371eed4ceSVladimir Sementsov-Ogievskiy } else {
14471eed4ceSVladimir Sementsov-Ogievskiy job_enter(&s->common.job);
145d58d8453SJohn Snow }
146d58d8453SJohn Snow }
147d58d8453SJohn Snow
backup_loop(BackupBlockJob * job)148c334e897SVladimir Sementsov-Ogievskiy static int coroutine_fn backup_loop(BackupBlockJob *job)
149d58d8453SJohn Snow {
15071eed4ceSVladimir Sementsov-Ogievskiy BlockCopyCallState *s = NULL;
15162aa1fbeSJohn Snow int ret = 0;
15271eed4ceSVladimir Sementsov-Ogievskiy bool error_is_read;
15371eed4ceSVladimir Sementsov-Ogievskiy BlockErrorAction act;
154d58d8453SJohn Snow
15571eed4ceSVladimir Sementsov-Ogievskiy while (true) { /* retry loop */
15671eed4ceSVladimir Sementsov-Ogievskiy job->bg_bcs_call = s = block_copy_async(job->bcs, 0,
15771eed4ceSVladimir Sementsov-Ogievskiy QEMU_ALIGN_UP(job->len, job->cluster_size),
15871eed4ceSVladimir Sementsov-Ogievskiy job->perf.max_workers, job->perf.max_chunk,
15971eed4ceSVladimir Sementsov-Ogievskiy backup_block_copy_callback, job);
16071eed4ceSVladimir Sementsov-Ogievskiy
16171eed4ceSVladimir Sementsov-Ogievskiy while (!block_copy_call_finished(s) &&
16271eed4ceSVladimir Sementsov-Ogievskiy !job_is_cancelled(&job->common.job))
16353f1c879SVladimir Sementsov-Ogievskiy {
16471eed4ceSVladimir Sementsov-Ogievskiy job_yield(&job->common.job);
16571eed4ceSVladimir Sementsov-Ogievskiy }
16671eed4ceSVladimir Sementsov-Ogievskiy
16771eed4ceSVladimir Sementsov-Ogievskiy if (!block_copy_call_finished(s)) {
16871eed4ceSVladimir Sementsov-Ogievskiy assert(job_is_cancelled(&job->common.job));
16971eed4ceSVladimir Sementsov-Ogievskiy /*
17071eed4ceSVladimir Sementsov-Ogievskiy * Note that we can't use job_yield() here, as it doesn't work for
17171eed4ceSVladimir Sementsov-Ogievskiy * cancelled job.
17271eed4ceSVladimir Sementsov-Ogievskiy */
17371eed4ceSVladimir Sementsov-Ogievskiy block_copy_call_cancel(s);
17471eed4ceSVladimir Sementsov-Ogievskiy job->wait = true;
17571eed4ceSVladimir Sementsov-Ogievskiy qemu_coroutine_yield();
17671eed4ceSVladimir Sementsov-Ogievskiy assert(block_copy_call_finished(s));
17771eed4ceSVladimir Sementsov-Ogievskiy ret = 0;
17862aa1fbeSJohn Snow goto out;
179d58d8453SJohn Snow }
18071eed4ceSVladimir Sementsov-Ogievskiy
18171eed4ceSVladimir Sementsov-Ogievskiy if (job_is_cancelled(&job->common.job) ||
18271eed4ceSVladimir Sementsov-Ogievskiy block_copy_call_succeeded(s))
18371eed4ceSVladimir Sementsov-Ogievskiy {
18471eed4ceSVladimir Sementsov-Ogievskiy ret = 0;
18571eed4ceSVladimir Sementsov-Ogievskiy goto out;
18671eed4ceSVladimir Sementsov-Ogievskiy }
18771eed4ceSVladimir Sementsov-Ogievskiy
18871eed4ceSVladimir Sementsov-Ogievskiy if (block_copy_call_cancelled(s)) {
18971eed4ceSVladimir Sementsov-Ogievskiy /*
19071eed4ceSVladimir Sementsov-Ogievskiy * Job is not cancelled but only block-copy call. This is possible
19171eed4ceSVladimir Sementsov-Ogievskiy * after job pause. Now the pause is finished, start new block-copy
19271eed4ceSVladimir Sementsov-Ogievskiy * iteration.
19371eed4ceSVladimir Sementsov-Ogievskiy */
19471eed4ceSVladimir Sementsov-Ogievskiy block_copy_call_free(s);
19571eed4ceSVladimir Sementsov-Ogievskiy continue;
19671eed4ceSVladimir Sementsov-Ogievskiy }
19771eed4ceSVladimir Sementsov-Ogievskiy
19871eed4ceSVladimir Sementsov-Ogievskiy /* The only remaining case is failed block-copy call. */
19971eed4ceSVladimir Sementsov-Ogievskiy assert(block_copy_call_failed(s));
20071eed4ceSVladimir Sementsov-Ogievskiy
20171eed4ceSVladimir Sementsov-Ogievskiy ret = block_copy_call_status(s, &error_is_read);
20271eed4ceSVladimir Sementsov-Ogievskiy act = backup_error_action(job, error_is_read, -ret);
20371eed4ceSVladimir Sementsov-Ogievskiy switch (act) {
20471eed4ceSVladimir Sementsov-Ogievskiy case BLOCK_ERROR_ACTION_REPORT:
20571eed4ceSVladimir Sementsov-Ogievskiy goto out;
20671eed4ceSVladimir Sementsov-Ogievskiy case BLOCK_ERROR_ACTION_STOP:
20771eed4ceSVladimir Sementsov-Ogievskiy /*
20871eed4ceSVladimir Sementsov-Ogievskiy * Go to pause prior to starting new block-copy call on the next
20971eed4ceSVladimir Sementsov-Ogievskiy * iteration.
21071eed4ceSVladimir Sementsov-Ogievskiy */
21171eed4ceSVladimir Sementsov-Ogievskiy job_pause_point(&job->common.job);
21271eed4ceSVladimir Sementsov-Ogievskiy break;
21371eed4ceSVladimir Sementsov-Ogievskiy case BLOCK_ERROR_ACTION_IGNORE:
21471eed4ceSVladimir Sementsov-Ogievskiy /* Proceed to new block-copy call to retry. */
21571eed4ceSVladimir Sementsov-Ogievskiy break;
21671eed4ceSVladimir Sementsov-Ogievskiy default:
21771eed4ceSVladimir Sementsov-Ogievskiy abort();
21871eed4ceSVladimir Sementsov-Ogievskiy }
21971eed4ceSVladimir Sementsov-Ogievskiy
22071eed4ceSVladimir Sementsov-Ogievskiy block_copy_call_free(s);
221d58d8453SJohn Snow }
222d58d8453SJohn Snow
22362aa1fbeSJohn Snow out:
22471eed4ceSVladimir Sementsov-Ogievskiy block_copy_call_free(s);
22571eed4ceSVladimir Sementsov-Ogievskiy job->bg_bcs_call = NULL;
22662aa1fbeSJohn Snow return ret;
227d58d8453SJohn Snow }
228d58d8453SJohn Snow
backup_init_bcs_bitmap(BackupBlockJob * job)229397f4e9dSVladimir Sementsov-Ogievskiy static void backup_init_bcs_bitmap(BackupBlockJob *job)
2308cc6dc62SVladimir Sementsov-Ogievskiy {
231141cdcdfSJohn Snow uint64_t estimate;
232397f4e9dSVladimir Sementsov-Ogievskiy BdrvDirtyBitmap *bcs_bitmap = block_copy_dirty_bitmap(job->bcs);
233141cdcdfSJohn Snow
234141cdcdfSJohn Snow if (job->sync_mode == MIRROR_SYNC_MODE_BITMAP) {
23506e0a9c1SVladimir Sementsov-Ogievskiy bdrv_clear_dirty_bitmap(bcs_bitmap, NULL);
236618af89eSVladimir Sementsov-Ogievskiy bdrv_dirty_bitmap_merge_internal(bcs_bitmap, job->sync_bitmap, NULL,
237618af89eSVladimir Sementsov-Ogievskiy true);
23806e0a9c1SVladimir Sementsov-Ogievskiy } else if (job->sync_mode == MIRROR_SYNC_MODE_TOP) {
2397e30dd61SJohn Snow /*
2407e30dd61SJohn Snow * We can't hog the coroutine to initialize this thoroughly.
2417e30dd61SJohn Snow * Set a flag and resume work when we are able to yield safely.
2427e30dd61SJohn Snow */
243397f4e9dSVladimir Sementsov-Ogievskiy block_copy_set_skip_unallocated(job->bcs, true);
2447e30dd61SJohn Snow }
2458cc6dc62SVladimir Sementsov-Ogievskiy
246397f4e9dSVladimir Sementsov-Ogievskiy estimate = bdrv_get_dirty_count(bcs_bitmap);
247141cdcdfSJohn Snow job_progress_set_remaining(&job->common.job, estimate);
2488cc6dc62SVladimir Sementsov-Ogievskiy }
2498cc6dc62SVladimir Sementsov-Ogievskiy
backup_run(Job * job,Error ** errp)25068702775SJohn Snow static int coroutine_fn backup_run(Job *job, Error **errp)
25198d2c6f2SDietmar Maurer {
25268702775SJohn Snow BackupBlockJob *s = container_of(job, BackupBlockJob, common.job);
253511e7d31SVladimir Sementsov-Ogievskiy int ret;
25498d2c6f2SDietmar Maurer
255397f4e9dSVladimir Sementsov-Ogievskiy backup_init_bcs_bitmap(s);
2568cc6dc62SVladimir Sementsov-Ogievskiy
2577e30dd61SJohn Snow if (s->sync_mode == MIRROR_SYNC_MODE_TOP) {
2587e30dd61SJohn Snow int64_t offset = 0;
2597e30dd61SJohn Snow int64_t count;
2607e30dd61SJohn Snow
2617e30dd61SJohn Snow for (offset = 0; offset < s->len; ) {
26271eed4ceSVladimir Sementsov-Ogievskiy if (job_is_cancelled(job)) {
26371eed4ceSVladimir Sementsov-Ogievskiy return -ECANCELED;
26471eed4ceSVladimir Sementsov-Ogievskiy }
26571eed4ceSVladimir Sementsov-Ogievskiy
26671eed4ceSVladimir Sementsov-Ogievskiy job_pause_point(job);
26771eed4ceSVladimir Sementsov-Ogievskiy
26871eed4ceSVladimir Sementsov-Ogievskiy if (job_is_cancelled(job)) {
269511e7d31SVladimir Sementsov-Ogievskiy return -ECANCELED;
2707e30dd61SJohn Snow }
2717e30dd61SJohn Snow
2727ff9579eSKevin Wolf /* rdlock protects the subsequent call to bdrv_is_allocated() */
2737ff9579eSKevin Wolf bdrv_graph_co_rdlock();
2742c8074c4SVladimir Sementsov-Ogievskiy ret = block_copy_reset_unallocated(s->bcs, offset, &count);
2757ff9579eSKevin Wolf bdrv_graph_co_rdunlock();
2767e30dd61SJohn Snow if (ret < 0) {
277511e7d31SVladimir Sementsov-Ogievskiy return ret;
2787e30dd61SJohn Snow }
2797e30dd61SJohn Snow
2807e30dd61SJohn Snow offset += count;
2817e30dd61SJohn Snow }
282397f4e9dSVladimir Sementsov-Ogievskiy block_copy_set_skip_unallocated(s->bcs, false);
2837e30dd61SJohn Snow }
2847e30dd61SJohn Snow
28568702775SJohn Snow if (s->sync_mode == MIRROR_SYNC_MODE_NONE) {
2860e23e382SVladimir Sementsov-Ogievskiy /*
287397f4e9dSVladimir Sementsov-Ogievskiy * All bits are set in bcs bitmap to allow any cluster to be copied.
2880e23e382SVladimir Sementsov-Ogievskiy * This does not actually require them to be copied.
2890e23e382SVladimir Sementsov-Ogievskiy */
29068702775SJohn Snow while (!job_is_cancelled(job)) {
2910e23e382SVladimir Sementsov-Ogievskiy /*
2920e23e382SVladimir Sementsov-Ogievskiy * Yield until the job is cancelled. We just let our before_write
2930e23e382SVladimir Sementsov-Ogievskiy * notify callback service CoW requests.
2940e23e382SVladimir Sementsov-Ogievskiy */
29568702775SJohn Snow job_yield(job);
296fc5d3f84SIan Main }
297fc5d3f84SIan Main } else {
298511e7d31SVladimir Sementsov-Ogievskiy return backup_loop(s);
299fc5d3f84SIan Main }
30098d2c6f2SDietmar Maurer
301511e7d31SVladimir Sementsov-Ogievskiy return 0;
30298d2c6f2SDietmar Maurer }
30398d2c6f2SDietmar Maurer
backup_pause(Job * job)30471eed4ceSVladimir Sementsov-Ogievskiy static void coroutine_fn backup_pause(Job *job)
30571eed4ceSVladimir Sementsov-Ogievskiy {
30671eed4ceSVladimir Sementsov-Ogievskiy BackupBlockJob *s = container_of(job, BackupBlockJob, common.job);
30771eed4ceSVladimir Sementsov-Ogievskiy
30871eed4ceSVladimir Sementsov-Ogievskiy if (s->bg_bcs_call && !block_copy_call_finished(s->bg_bcs_call)) {
30971eed4ceSVladimir Sementsov-Ogievskiy block_copy_call_cancel(s->bg_bcs_call);
31071eed4ceSVladimir Sementsov-Ogievskiy s->wait = true;
31171eed4ceSVladimir Sementsov-Ogievskiy qemu_coroutine_yield();
31271eed4ceSVladimir Sementsov-Ogievskiy }
31371eed4ceSVladimir Sementsov-Ogievskiy }
31471eed4ceSVladimir Sementsov-Ogievskiy
backup_set_speed(BlockJob * job,int64_t speed)3151a215256SAlberto Faria static void backup_set_speed(BlockJob *job, int64_t speed)
31671eed4ceSVladimir Sementsov-Ogievskiy {
31771eed4ceSVladimir Sementsov-Ogievskiy BackupBlockJob *s = container_of(job, BackupBlockJob, common);
31871eed4ceSVladimir Sementsov-Ogievskiy
31971eed4ceSVladimir Sementsov-Ogievskiy /*
32071eed4ceSVladimir Sementsov-Ogievskiy * block_job_set_speed() is called first from block_job_create(), when we
32171eed4ceSVladimir Sementsov-Ogievskiy * don't yet have s->bcs.
32271eed4ceSVladimir Sementsov-Ogievskiy */
32371eed4ceSVladimir Sementsov-Ogievskiy if (s->bcs) {
32471eed4ceSVladimir Sementsov-Ogievskiy block_copy_set_speed(s->bcs, speed);
32571eed4ceSVladimir Sementsov-Ogievskiy if (s->bg_bcs_call) {
32671eed4ceSVladimir Sementsov-Ogievskiy block_copy_kick(s->bg_bcs_call);
32771eed4ceSVladimir Sementsov-Ogievskiy }
32871eed4ceSVladimir Sementsov-Ogievskiy }
32971eed4ceSVladimir Sementsov-Ogievskiy }
33071eed4ceSVladimir Sementsov-Ogievskiy
backup_cancel(Job * job,bool force)33173895f38SHanna Reitz static bool backup_cancel(Job *job, bool force)
332ff789bf5SVladimir Sementsov-Ogievskiy {
333ff789bf5SVladimir Sementsov-Ogievskiy BackupBlockJob *s = container_of(job, BackupBlockJob, common.job);
334ff789bf5SVladimir Sementsov-Ogievskiy
335ff789bf5SVladimir Sementsov-Ogievskiy bdrv_cancel_in_flight(s->target_bs);
33673895f38SHanna Reitz return true;
337ff789bf5SVladimir Sementsov-Ogievskiy }
338ff789bf5SVladimir Sementsov-Ogievskiy
339a7815a76SJohn Snow static const BlockJobDriver backup_job_driver = {
34033e9e9bdSKevin Wolf .job_driver = {
341a7815a76SJohn Snow .instance_size = sizeof(BackupBlockJob),
3428e4c8700SKevin Wolf .job_type = JOB_TYPE_BACKUP,
34380fa2c75SKevin Wolf .free = block_job_free,
344b15de828SKevin Wolf .user_resume = block_job_user_resume,
345f67432a2SJohn Snow .run = backup_run,
346a7815a76SJohn Snow .commit = backup_commit,
347a7815a76SJohn Snow .abort = backup_abort,
348a7815a76SJohn Snow .clean = backup_clean,
34971eed4ceSVladimir Sementsov-Ogievskiy .pause = backup_pause,
350ff789bf5SVladimir Sementsov-Ogievskiy .cancel = backup_cancel,
35171eed4ceSVladimir Sementsov-Ogievskiy },
35271eed4ceSVladimir Sementsov-Ogievskiy .set_speed = backup_set_speed,
353a7815a76SJohn Snow };
354a7815a76SJohn Snow
backup_job_create(const char * job_id,BlockDriverState * bs,BlockDriverState * target,int64_t speed,MirrorSyncMode sync_mode,BdrvDirtyBitmap * sync_bitmap,BitmapSyncMode bitmap_mode,bool compress,bool discard_source,const char * filter_node_name,BackupPerf * perf,BlockdevOnError on_source_error,BlockdevOnError on_target_error,int creation_flags,BlockCompletionFunc * cb,void * opaque,JobTxn * txn,Error ** errp)355111049a4SJohn Snow BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
35670559d49SAlberto Garcia BlockDriverState *target, int64_t speed,
35770559d49SAlberto Garcia MirrorSyncMode sync_mode, BdrvDirtyBitmap *sync_bitmap,
358c8b56501SJohn Snow BitmapSyncMode bitmap_mode,
3590fd05c8dSVladimir Sementsov-Ogievskiy bool compress, bool discard_source,
36000e30f05SVladimir Sementsov-Ogievskiy const char *filter_node_name,
36186c6a3b6SVladimir Sementsov-Ogievskiy BackupPerf *perf,
36298d2c6f2SDietmar Maurer BlockdevOnError on_source_error,
36398d2c6f2SDietmar Maurer BlockdevOnError on_target_error,
36447970dfbSJohn Snow int creation_flags,
365097310b5SMarkus Armbruster BlockCompletionFunc *cb, void *opaque,
36662c9e416SKevin Wolf JobTxn *txn, Error **errp)
36798d2c6f2SDietmar Maurer {
368958a04bdSKevin Wolf int64_t len, target_len;
36991ab6883SKevin Wolf BackupBlockJob *job = NULL;
370ae6b12faSVladimir Sementsov-Ogievskiy int64_t cluster_size;
371d003e0aeSVladimir Sementsov-Ogievskiy BlockDriverState *cbw = NULL;
37200e30f05SVladimir Sementsov-Ogievskiy BlockCopyState *bcs = NULL;
37398d2c6f2SDietmar Maurer
37498d2c6f2SDietmar Maurer assert(bs);
37598d2c6f2SDietmar Maurer assert(target);
376b4ad82aaSEmanuele Giuseppe Esposito GLOBAL_STATE_CODE();
37798d2c6f2SDietmar Maurer
378a6c9365aSJohn Snow /* QMP interface protects us from these cases */
379a6c9365aSJohn Snow assert(sync_mode != MIRROR_SYNC_MODE_INCREMENTAL);
380a6c9365aSJohn Snow assert(sync_bitmap || sync_mode != MIRROR_SYNC_MODE_BITMAP);
381a6c9365aSJohn Snow
382c29c1dd3SFam Zheng if (bs == target) {
383c29c1dd3SFam Zheng error_setg(errp, "Source and target cannot be the same");
384111049a4SJohn Snow return NULL;
385c29c1dd3SFam Zheng }
386c29c1dd3SFam Zheng
387f3bbc53dSKevin Wolf bdrv_graph_rdlock_main_loop();
388c29c1dd3SFam Zheng if (!bdrv_is_inserted(bs)) {
389c29c1dd3SFam Zheng error_setg(errp, "Device is not inserted: %s",
390c29c1dd3SFam Zheng bdrv_get_device_name(bs));
391f3bbc53dSKevin Wolf goto error_rdlock;
392c29c1dd3SFam Zheng }
393c29c1dd3SFam Zheng
394c29c1dd3SFam Zheng if (!bdrv_is_inserted(target)) {
395c29c1dd3SFam Zheng error_setg(errp, "Device is not inserted: %s",
396c29c1dd3SFam Zheng bdrv_get_device_name(target));
397f3bbc53dSKevin Wolf goto error_rdlock;
398c29c1dd3SFam Zheng }
399c29c1dd3SFam Zheng
4002b088c60SMax Reitz if (compress && !bdrv_supports_compressed_writes(target)) {
40113b9414bSPavel Butsykin error_setg(errp, "Compression is not supported for this drive %s",
40213b9414bSPavel Butsykin bdrv_get_device_name(target));
403f3bbc53dSKevin Wolf goto error_rdlock;
40413b9414bSPavel Butsykin }
40513b9414bSPavel Butsykin
406c29c1dd3SFam Zheng if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
407f3bbc53dSKevin Wolf goto error_rdlock;
408c29c1dd3SFam Zheng }
409c29c1dd3SFam Zheng
410c29c1dd3SFam Zheng if (bdrv_op_is_blocked(target, BLOCK_OP_TYPE_BACKUP_TARGET, errp)) {
411f3bbc53dSKevin Wolf goto error_rdlock;
412c29c1dd3SFam Zheng }
413f3bbc53dSKevin Wolf bdrv_graph_rdunlock_main_loop();
414c29c1dd3SFam Zheng
4158fc898ceSStefano Garzarella if (perf->max_workers < 1 || perf->max_workers > INT_MAX) {
4168fc898ceSStefano Garzarella error_setg(errp, "max-workers must be between 1 and %d", INT_MAX);
4172c59fd83SVladimir Sementsov-Ogievskiy return NULL;
4182c59fd83SVladimir Sementsov-Ogievskiy }
4192c59fd83SVladimir Sementsov-Ogievskiy
4202c59fd83SVladimir Sementsov-Ogievskiy if (perf->max_chunk < 0) {
4212c59fd83SVladimir Sementsov-Ogievskiy error_setg(errp, "max-chunk must be zero (which means no limit) or "
4222c59fd83SVladimir Sementsov-Ogievskiy "positive");
4232c59fd83SVladimir Sementsov-Ogievskiy return NULL;
4242c59fd83SVladimir Sementsov-Ogievskiy }
4252c59fd83SVladimir Sementsov-Ogievskiy
4261a2b8b40SJohn Snow if (sync_bitmap) {
427b30ffbefSJohn Snow /* If we need to write to this bitmap, check that we can: */
428b30ffbefSJohn Snow if (bitmap_mode != BITMAP_SYNC_MODE_NEVER &&
429b30ffbefSJohn Snow bdrv_dirty_bitmap_check(sync_bitmap, BDRV_BITMAP_DEFAULT, errp)) {
430b30ffbefSJohn Snow return NULL;
431b30ffbefSJohn Snow }
432b30ffbefSJohn Snow
433d58d8453SJohn Snow /* Create a new bitmap, and freeze/disable this one. */
4345deb6cbdSVladimir Sementsov-Ogievskiy if (bdrv_dirty_bitmap_create_successor(sync_bitmap, errp) < 0) {
435111049a4SJohn Snow return NULL;
436d58d8453SJohn Snow }
437d58d8453SJohn Snow }
438d58d8453SJohn Snow
43998d2c6f2SDietmar Maurer len = bdrv_getlength(bs);
44098d2c6f2SDietmar Maurer if (len < 0) {
441f3bbc53dSKevin Wolf GRAPH_RDLOCK_GUARD_MAINLOOP();
44258226634SKevin Wolf error_setg_errno(errp, -len, "Unable to get length for '%s'",
44358226634SKevin Wolf bdrv_get_device_or_node_name(bs));
444d58d8453SJohn Snow goto error;
44598d2c6f2SDietmar Maurer }
44698d2c6f2SDietmar Maurer
447958a04bdSKevin Wolf target_len = bdrv_getlength(target);
448958a04bdSKevin Wolf if (target_len < 0) {
449f3bbc53dSKevin Wolf GRAPH_RDLOCK_GUARD_MAINLOOP();
450958a04bdSKevin Wolf error_setg_errno(errp, -target_len, "Unable to get length for '%s'",
451958a04bdSKevin Wolf bdrv_get_device_or_node_name(bs));
452958a04bdSKevin Wolf goto error;
453958a04bdSKevin Wolf }
454958a04bdSKevin Wolf
455958a04bdSKevin Wolf if (target_len != len) {
456958a04bdSKevin Wolf error_setg(errp, "Source and target image have different sizes");
457958a04bdSKevin Wolf goto error;
458958a04bdSKevin Wolf }
459958a04bdSKevin Wolf
4600fd05c8dSVladimir Sementsov-Ogievskiy cbw = bdrv_cbw_append(bs, target, filter_node_name, discard_source,
461*6252deb2SFiona Ebner perf->min_cluster_size, &bcs, errp);
462d003e0aeSVladimir Sementsov-Ogievskiy if (!cbw) {
46300e30f05SVladimir Sementsov-Ogievskiy goto error;
46400e30f05SVladimir Sementsov-Ogievskiy }
46500e30f05SVladimir Sementsov-Ogievskiy
466b518e9e9SVladimir Sementsov-Ogievskiy cluster_size = block_copy_cluster_size(bcs);
467b518e9e9SVladimir Sementsov-Ogievskiy
468b518e9e9SVladimir Sementsov-Ogievskiy if (perf->max_chunk && perf->max_chunk < cluster_size) {
469b518e9e9SVladimir Sementsov-Ogievskiy error_setg(errp, "Required max-chunk (%" PRIi64 ") is less than backup "
470b518e9e9SVladimir Sementsov-Ogievskiy "cluster size (%" PRIi64 ")", perf->max_chunk, cluster_size);
471b518e9e9SVladimir Sementsov-Ogievskiy goto error;
472b518e9e9SVladimir Sementsov-Ogievskiy }
473b518e9e9SVladimir Sementsov-Ogievskiy
474843670f3SVladimir Sementsov-Ogievskiy /* job->len is fixed, so we can't allow resize */
475d003e0aeSVladimir Sementsov-Ogievskiy job = block_job_create(job_id, &backup_job_driver, txn, cbw,
47600e30f05SVladimir Sementsov-Ogievskiy 0, BLK_PERM_ALL,
477843670f3SVladimir Sementsov-Ogievskiy speed, creation_flags, cb, opaque, errp);
478843670f3SVladimir Sementsov-Ogievskiy if (!job) {
479843670f3SVladimir Sementsov-Ogievskiy goto error;
480843670f3SVladimir Sementsov-Ogievskiy }
481843670f3SVladimir Sementsov-Ogievskiy
482d003e0aeSVladimir Sementsov-Ogievskiy job->cbw = cbw;
483843670f3SVladimir Sementsov-Ogievskiy job->source_bs = bs;
484ff789bf5SVladimir Sementsov-Ogievskiy job->target_bs = target;
485843670f3SVladimir Sementsov-Ogievskiy job->on_source_error = on_source_error;
486843670f3SVladimir Sementsov-Ogievskiy job->on_target_error = on_target_error;
487843670f3SVladimir Sementsov-Ogievskiy job->sync_mode = sync_mode;
488843670f3SVladimir Sementsov-Ogievskiy job->sync_bitmap = sync_bitmap;
489843670f3SVladimir Sementsov-Ogievskiy job->bitmap_mode = bitmap_mode;
49000e30f05SVladimir Sementsov-Ogievskiy job->bcs = bcs;
491ae6b12faSVladimir Sementsov-Ogievskiy job->cluster_size = cluster_size;
492843670f3SVladimir Sementsov-Ogievskiy job->len = len;
49386c6a3b6SVladimir Sementsov-Ogievskiy job->perf = *perf;
4944c9bca7eSJohn Snow
4952a6511dfSVladimir Sementsov-Ogievskiy block_copy_set_copy_opts(bcs, perf->use_copy_range, compress);
496d0ebeca1SVladimir Sementsov-Ogievskiy block_copy_set_progress_meter(bcs, &job->common.job.progress);
49771eed4ceSVladimir Sementsov-Ogievskiy block_copy_set_speed(bcs, speed);
4980f4b02b7SVladimir Sementsov-Ogievskiy
499d003e0aeSVladimir Sementsov-Ogievskiy /* Required permissions are taken by copy-before-write filter target */
5006bc30f19SStefan Hajnoczi bdrv_graph_wrlock();
50176d554e2SKevin Wolf block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL,
50276d554e2SKevin Wolf &error_abort);
5036bc30f19SStefan Hajnoczi bdrv_graph_wrunlock();
504111049a4SJohn Snow
505111049a4SJohn Snow return &job->common;
506d58d8453SJohn Snow
507d58d8453SJohn Snow error:
508d58d8453SJohn Snow if (sync_bitmap) {
5095deb6cbdSVladimir Sementsov-Ogievskiy bdrv_reclaim_dirty_bitmap(sync_bitmap, NULL);
510d58d8453SJohn Snow }
511d003e0aeSVladimir Sementsov-Ogievskiy if (cbw) {
512d003e0aeSVladimir Sementsov-Ogievskiy bdrv_cbw_drop(cbw);
51391ab6883SKevin Wolf }
514111049a4SJohn Snow
515111049a4SJohn Snow return NULL;
516f3bbc53dSKevin Wolf
517f3bbc53dSKevin Wolf error_rdlock:
518f3bbc53dSKevin Wolf bdrv_graph_rdunlock_main_loop();
519f3bbc53dSKevin Wolf return NULL;
52098d2c6f2SDietmar Maurer }
521