xref: /qemu/block/backup.c (revision 6bc30f19)
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,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,
35913b9414bSPavel Butsykin                   bool compress,
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 
4604c1e992bSVladimir Sementsov-Ogievskiy     cbw = bdrv_cbw_append(bs, target, filter_node_name, &bcs, errp);
461d003e0aeSVladimir Sementsov-Ogievskiy     if (!cbw) {
46200e30f05SVladimir Sementsov-Ogievskiy         goto error;
46300e30f05SVladimir Sementsov-Ogievskiy     }
46400e30f05SVladimir Sementsov-Ogievskiy 
465b518e9e9SVladimir Sementsov-Ogievskiy     cluster_size = block_copy_cluster_size(bcs);
466b518e9e9SVladimir Sementsov-Ogievskiy 
467b518e9e9SVladimir Sementsov-Ogievskiy     if (perf->max_chunk && perf->max_chunk < cluster_size) {
468b518e9e9SVladimir Sementsov-Ogievskiy         error_setg(errp, "Required max-chunk (%" PRIi64 ") is less than backup "
469b518e9e9SVladimir Sementsov-Ogievskiy                    "cluster size (%" PRIi64 ")", perf->max_chunk, cluster_size);
470b518e9e9SVladimir Sementsov-Ogievskiy         goto error;
471b518e9e9SVladimir Sementsov-Ogievskiy     }
472b518e9e9SVladimir Sementsov-Ogievskiy 
473843670f3SVladimir Sementsov-Ogievskiy     /* job->len is fixed, so we can't allow resize */
474d003e0aeSVladimir Sementsov-Ogievskiy     job = block_job_create(job_id, &backup_job_driver, txn, cbw,
47500e30f05SVladimir Sementsov-Ogievskiy                            0, BLK_PERM_ALL,
476843670f3SVladimir Sementsov-Ogievskiy                            speed, creation_flags, cb, opaque, errp);
477843670f3SVladimir Sementsov-Ogievskiy     if (!job) {
478843670f3SVladimir Sementsov-Ogievskiy         goto error;
479843670f3SVladimir Sementsov-Ogievskiy     }
480843670f3SVladimir Sementsov-Ogievskiy 
481d003e0aeSVladimir Sementsov-Ogievskiy     job->cbw = cbw;
482843670f3SVladimir Sementsov-Ogievskiy     job->source_bs = bs;
483ff789bf5SVladimir Sementsov-Ogievskiy     job->target_bs = target;
484843670f3SVladimir Sementsov-Ogievskiy     job->on_source_error = on_source_error;
485843670f3SVladimir Sementsov-Ogievskiy     job->on_target_error = on_target_error;
486843670f3SVladimir Sementsov-Ogievskiy     job->sync_mode = sync_mode;
487843670f3SVladimir Sementsov-Ogievskiy     job->sync_bitmap = sync_bitmap;
488843670f3SVladimir Sementsov-Ogievskiy     job->bitmap_mode = bitmap_mode;
48900e30f05SVladimir Sementsov-Ogievskiy     job->bcs = bcs;
490ae6b12faSVladimir Sementsov-Ogievskiy     job->cluster_size = cluster_size;
491843670f3SVladimir Sementsov-Ogievskiy     job->len = len;
49286c6a3b6SVladimir Sementsov-Ogievskiy     job->perf = *perf;
4934c9bca7eSJohn Snow 
4942a6511dfSVladimir Sementsov-Ogievskiy     block_copy_set_copy_opts(bcs, perf->use_copy_range, compress);
495d0ebeca1SVladimir Sementsov-Ogievskiy     block_copy_set_progress_meter(bcs, &job->common.job.progress);
49671eed4ceSVladimir Sementsov-Ogievskiy     block_copy_set_speed(bcs, speed);
4970f4b02b7SVladimir Sementsov-Ogievskiy 
498d003e0aeSVladimir Sementsov-Ogievskiy     /* Required permissions are taken by copy-before-write filter target */
499*6bc30f19SStefan Hajnoczi     bdrv_graph_wrlock();
50076d554e2SKevin Wolf     block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL,
50176d554e2SKevin Wolf                        &error_abort);
502*6bc30f19SStefan Hajnoczi     bdrv_graph_wrunlock();
503111049a4SJohn Snow 
504111049a4SJohn Snow     return &job->common;
505d58d8453SJohn Snow 
506d58d8453SJohn Snow  error:
507d58d8453SJohn Snow     if (sync_bitmap) {
5085deb6cbdSVladimir Sementsov-Ogievskiy         bdrv_reclaim_dirty_bitmap(sync_bitmap, NULL);
509d58d8453SJohn Snow     }
510d003e0aeSVladimir Sementsov-Ogievskiy     if (cbw) {
511d003e0aeSVladimir Sementsov-Ogievskiy         bdrv_cbw_drop(cbw);
51291ab6883SKevin Wolf     }
513111049a4SJohn Snow 
514111049a4SJohn Snow     return NULL;
515f3bbc53dSKevin Wolf 
516f3bbc53dSKevin Wolf error_rdlock:
517f3bbc53dSKevin Wolf     bdrv_graph_rdunlock_main_loop();
518f3bbc53dSKevin Wolf     return NULL;
51998d2c6f2SDietmar Maurer }
520