#include "block/blockjob_int.h"
#include "block/block_backup.h"
#include "block/block-copy.h"
+#include "block/dirty-bitmap.h"
#include "qapi/error.h"
-#include "qapi/qmp/qerror.h"
#include "qemu/cutils.h"
#include "sysemu/block-backend.h"
#include "qemu/bitmap.h"
static void backup_init_bcs_bitmap(BackupBlockJob *job)
{
- bool ret;
uint64_t estimate;
BdrvDirtyBitmap *bcs_bitmap = block_copy_dirty_bitmap(job->bcs);
if (job->sync_mode == MIRROR_SYNC_MODE_BITMAP) {
bdrv_clear_dirty_bitmap(bcs_bitmap, NULL);
- ret = bdrv_dirty_bitmap_merge_internal(bcs_bitmap, job->sync_bitmap,
- NULL, true);
- assert(ret);
+ bdrv_dirty_bitmap_merge_internal(bcs_bitmap, job->sync_bitmap, NULL,
+ true);
} else if (job->sync_mode == MIRROR_SYNC_MODE_TOP) {
/*
* We can't hog the coroutine to initialize this thoroughly.
return -ECANCELED;
}
+ /* rdlock protects the subsequent call to bdrv_is_allocated() */
+ bdrv_graph_co_rdlock();
ret = block_copy_reset_unallocated(s->bcs, offset, &count);
+ bdrv_graph_co_rdunlock();
if (ret < 0) {
return ret;
}
}
}
-static void coroutine_fn backup_set_speed(BlockJob *job, int64_t speed)
+static void backup_set_speed(BlockJob *job, int64_t speed)
{
BackupBlockJob *s = container_of(job, BackupBlockJob, common);
}
}
-static void backup_cancel(Job *job, bool force)
+static bool backup_cancel(Job *job, bool force)
{
BackupBlockJob *s = container_of(job, BackupBlockJob, common.job);
bdrv_cancel_in_flight(s->target_bs);
+ return true;
}
static const BlockJobDriver backup_job_driver = {
assert(bs);
assert(target);
+ GLOBAL_STATE_CODE();
/* QMP interface protects us from these cases */
assert(sync_mode != MIRROR_SYNC_MODE_INCREMENTAL);
return NULL;
}
+ bdrv_graph_rdlock_main_loop();
if (!bdrv_is_inserted(bs)) {
error_setg(errp, "Device is not inserted: %s",
bdrv_get_device_name(bs));
- return NULL;
+ goto error_rdlock;
}
if (!bdrv_is_inserted(target)) {
error_setg(errp, "Device is not inserted: %s",
bdrv_get_device_name(target));
- return NULL;
+ goto error_rdlock;
}
if (compress && !bdrv_supports_compressed_writes(target)) {
error_setg(errp, "Compression is not supported for this drive %s",
bdrv_get_device_name(target));
- return NULL;
+ goto error_rdlock;
}
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
- return NULL;
+ goto error_rdlock;
}
if (bdrv_op_is_blocked(target, BLOCK_OP_TYPE_BACKUP_TARGET, errp)) {
- return NULL;
+ goto error_rdlock;
}
+ bdrv_graph_rdunlock_main_loop();
- if (perf->max_workers < 1) {
- error_setg(errp, "max-workers must be greater than zero");
+ if (perf->max_workers < 1 || perf->max_workers > INT_MAX) {
+ error_setg(errp, "max-workers must be between 1 and %d", INT_MAX);
return NULL;
}
len = bdrv_getlength(bs);
if (len < 0) {
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
error_setg_errno(errp, -len, "Unable to get length for '%s'",
bdrv_get_device_or_node_name(bs));
goto error;
target_len = bdrv_getlength(target);
if (target_len < 0) {
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
error_setg_errno(errp, -target_len, "Unable to get length for '%s'",
bdrv_get_device_or_node_name(bs));
goto error;
block_copy_set_speed(bcs, speed);
/* Required permissions are taken by copy-before-write filter target */
+ bdrv_graph_wrlock();
block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL,
&error_abort);
+ bdrv_graph_wrunlock();
return &job->common;
}
return NULL;
+
+error_rdlock:
+ bdrv_graph_rdunlock_main_loop();
+ return NULL;
}