mirror of
https://github.com/qemu/qemu.git
synced 2025-08-16 14:54:29 +00:00
block/backup: upgrade copy_bitmap to BdrvDirtyBitmap
This simplifies some interface matters; namely the initialization and (later) merging the manifest back into the sync_bitmap if it was provided. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Max Reitz <mreitz@redhat.com> Message-id: 20190709232550.10724-12-jsnow@redhat.com Signed-off-by: John Snow <jsnow@redhat.com>
This commit is contained in:
parent
28636b8211
commit
62aa1fbeac
@ -38,7 +38,10 @@ typedef struct CowRequest {
|
|||||||
typedef struct BackupBlockJob {
|
typedef struct BackupBlockJob {
|
||||||
BlockJob common;
|
BlockJob common;
|
||||||
BlockBackend *target;
|
BlockBackend *target;
|
||||||
|
|
||||||
BdrvDirtyBitmap *sync_bitmap;
|
BdrvDirtyBitmap *sync_bitmap;
|
||||||
|
BdrvDirtyBitmap *copy_bitmap;
|
||||||
|
|
||||||
MirrorSyncMode sync_mode;
|
MirrorSyncMode sync_mode;
|
||||||
BitmapSyncMode bitmap_mode;
|
BitmapSyncMode bitmap_mode;
|
||||||
BlockdevOnError on_source_error;
|
BlockdevOnError on_source_error;
|
||||||
@ -51,7 +54,6 @@ typedef struct BackupBlockJob {
|
|||||||
NotifierWithReturn before_write;
|
NotifierWithReturn before_write;
|
||||||
QLIST_HEAD(, CowRequest) inflight_reqs;
|
QLIST_HEAD(, CowRequest) inflight_reqs;
|
||||||
|
|
||||||
HBitmap *copy_bitmap;
|
|
||||||
bool use_copy_range;
|
bool use_copy_range;
|
||||||
int64_t copy_range_size;
|
int64_t copy_range_size;
|
||||||
|
|
||||||
@ -113,7 +115,7 @@ static int coroutine_fn backup_cow_with_bounce_buffer(BackupBlockJob *job,
|
|||||||
int write_flags = job->serialize_target_writes ? BDRV_REQ_SERIALISING : 0;
|
int write_flags = job->serialize_target_writes ? BDRV_REQ_SERIALISING : 0;
|
||||||
|
|
||||||
assert(QEMU_IS_ALIGNED(start, job->cluster_size));
|
assert(QEMU_IS_ALIGNED(start, job->cluster_size));
|
||||||
hbitmap_reset(job->copy_bitmap, start, job->cluster_size);
|
bdrv_reset_dirty_bitmap(job->copy_bitmap, start, job->cluster_size);
|
||||||
nbytes = MIN(job->cluster_size, job->len - start);
|
nbytes = MIN(job->cluster_size, job->len - start);
|
||||||
if (!*bounce_buffer) {
|
if (!*bounce_buffer) {
|
||||||
*bounce_buffer = blk_blockalign(blk, job->cluster_size);
|
*bounce_buffer = blk_blockalign(blk, job->cluster_size);
|
||||||
@ -146,7 +148,7 @@ static int coroutine_fn backup_cow_with_bounce_buffer(BackupBlockJob *job,
|
|||||||
|
|
||||||
return nbytes;
|
return nbytes;
|
||||||
fail:
|
fail:
|
||||||
hbitmap_set(job->copy_bitmap, start, job->cluster_size);
|
bdrv_set_dirty_bitmap(job->copy_bitmap, start, job->cluster_size);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -169,12 +171,14 @@ static int coroutine_fn backup_cow_with_offload(BackupBlockJob *job,
|
|||||||
assert(QEMU_IS_ALIGNED(start, job->cluster_size));
|
assert(QEMU_IS_ALIGNED(start, job->cluster_size));
|
||||||
nbytes = MIN(job->copy_range_size, end - start);
|
nbytes = MIN(job->copy_range_size, end - start);
|
||||||
nr_clusters = DIV_ROUND_UP(nbytes, job->cluster_size);
|
nr_clusters = DIV_ROUND_UP(nbytes, job->cluster_size);
|
||||||
hbitmap_reset(job->copy_bitmap, start, job->cluster_size * nr_clusters);
|
bdrv_reset_dirty_bitmap(job->copy_bitmap, start,
|
||||||
|
job->cluster_size * nr_clusters);
|
||||||
ret = blk_co_copy_range(blk, start, job->target, start, nbytes,
|
ret = blk_co_copy_range(blk, start, job->target, start, nbytes,
|
||||||
read_flags, write_flags);
|
read_flags, write_flags);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
trace_backup_do_cow_copy_range_fail(job, start, ret);
|
trace_backup_do_cow_copy_range_fail(job, start, ret);
|
||||||
hbitmap_set(job->copy_bitmap, start, job->cluster_size * nr_clusters);
|
bdrv_set_dirty_bitmap(job->copy_bitmap, start,
|
||||||
|
job->cluster_size * nr_clusters);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,13 +208,14 @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job,
|
|||||||
while (start < end) {
|
while (start < end) {
|
||||||
int64_t dirty_end;
|
int64_t dirty_end;
|
||||||
|
|
||||||
if (!hbitmap_get(job->copy_bitmap, start)) {
|
if (!bdrv_dirty_bitmap_get(job->copy_bitmap, start)) {
|
||||||
trace_backup_do_cow_skip(job, start);
|
trace_backup_do_cow_skip(job, start);
|
||||||
start += job->cluster_size;
|
start += job->cluster_size;
|
||||||
continue; /* already copied */
|
continue; /* already copied */
|
||||||
}
|
}
|
||||||
|
|
||||||
dirty_end = hbitmap_next_zero(job->copy_bitmap, start, (end - start));
|
dirty_end = bdrv_dirty_bitmap_next_zero(job->copy_bitmap, start,
|
||||||
|
(end - start));
|
||||||
if (dirty_end < 0) {
|
if (dirty_end < 0) {
|
||||||
dirty_end = end;
|
dirty_end = end;
|
||||||
}
|
}
|
||||||
@ -307,14 +312,16 @@ static void backup_abort(Job *job)
|
|||||||
static void backup_clean(Job *job)
|
static void backup_clean(Job *job)
|
||||||
{
|
{
|
||||||
BackupBlockJob *s = container_of(job, BackupBlockJob, common.job);
|
BackupBlockJob *s = container_of(job, BackupBlockJob, common.job);
|
||||||
|
BlockDriverState *bs = blk_bs(s->common.blk);
|
||||||
|
|
||||||
|
if (s->copy_bitmap) {
|
||||||
|
bdrv_release_dirty_bitmap(bs, s->copy_bitmap);
|
||||||
|
s->copy_bitmap = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
assert(s->target);
|
assert(s->target);
|
||||||
blk_unref(s->target);
|
blk_unref(s->target);
|
||||||
s->target = NULL;
|
s->target = NULL;
|
||||||
|
|
||||||
if (s->copy_bitmap) {
|
|
||||||
hbitmap_free(s->copy_bitmap);
|
|
||||||
s->copy_bitmap = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void backup_do_checkpoint(BlockJob *job, Error **errp)
|
void backup_do_checkpoint(BlockJob *job, Error **errp)
|
||||||
@ -329,7 +336,7 @@ void backup_do_checkpoint(BlockJob *job, Error **errp)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
hbitmap_set(backup_job->copy_bitmap, 0, backup_job->len);
|
bdrv_set_dirty_bitmap(backup_job->copy_bitmap, 0, backup_job->len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void backup_drain(BlockJob *job)
|
static void backup_drain(BlockJob *job)
|
||||||
@ -398,59 +405,52 @@ static bool bdrv_is_unallocated_range(BlockDriverState *bs,
|
|||||||
|
|
||||||
static int coroutine_fn backup_loop(BackupBlockJob *job)
|
static int coroutine_fn backup_loop(BackupBlockJob *job)
|
||||||
{
|
{
|
||||||
int ret;
|
|
||||||
bool error_is_read;
|
bool error_is_read;
|
||||||
int64_t offset;
|
int64_t offset;
|
||||||
HBitmapIter hbi;
|
BdrvDirtyBitmapIter *bdbi;
|
||||||
BlockDriverState *bs = blk_bs(job->common.blk);
|
BlockDriverState *bs = blk_bs(job->common.blk);
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
hbitmap_iter_init(&hbi, job->copy_bitmap, 0);
|
bdbi = bdrv_dirty_iter_new(job->copy_bitmap);
|
||||||
while ((offset = hbitmap_iter_next(&hbi)) != -1) {
|
while ((offset = bdrv_dirty_iter_next(bdbi)) != -1) {
|
||||||
if (job->sync_mode == MIRROR_SYNC_MODE_TOP &&
|
if (job->sync_mode == MIRROR_SYNC_MODE_TOP &&
|
||||||
bdrv_is_unallocated_range(bs, offset, job->cluster_size))
|
bdrv_is_unallocated_range(bs, offset, job->cluster_size))
|
||||||
{
|
{
|
||||||
hbitmap_reset(job->copy_bitmap, offset, job->cluster_size);
|
bdrv_reset_dirty_bitmap(job->copy_bitmap, offset,
|
||||||
|
job->cluster_size);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (yield_and_check(job)) {
|
if (yield_and_check(job)) {
|
||||||
return 0;
|
goto out;
|
||||||
}
|
}
|
||||||
ret = backup_do_cow(job, offset,
|
ret = backup_do_cow(job, offset,
|
||||||
job->cluster_size, &error_is_read, false);
|
job->cluster_size, &error_is_read, false);
|
||||||
if (ret < 0 && backup_error_action(job, error_is_read, -ret) ==
|
if (ret < 0 && backup_error_action(job, error_is_read, -ret) ==
|
||||||
BLOCK_ERROR_ACTION_REPORT)
|
BLOCK_ERROR_ACTION_REPORT)
|
||||||
{
|
{
|
||||||
return ret;
|
goto out;
|
||||||
}
|
}
|
||||||
} while (ret < 0);
|
} while (ret < 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
out:
|
||||||
|
bdrv_dirty_iter_free(bdbi);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* init copy_bitmap from sync_bitmap */
|
/* init copy_bitmap from sync_bitmap */
|
||||||
static void backup_incremental_init_copy_bitmap(BackupBlockJob *job)
|
static void backup_incremental_init_copy_bitmap(BackupBlockJob *job)
|
||||||
{
|
{
|
||||||
uint64_t offset = 0;
|
bool ret = bdrv_dirty_bitmap_merge_internal(job->copy_bitmap,
|
||||||
uint64_t bytes = job->len;
|
job->sync_bitmap,
|
||||||
|
NULL, true);
|
||||||
while (bdrv_dirty_bitmap_next_dirty_area(job->sync_bitmap,
|
assert(ret);
|
||||||
&offset, &bytes))
|
|
||||||
{
|
|
||||||
hbitmap_set(job->copy_bitmap, offset, bytes);
|
|
||||||
|
|
||||||
offset += bytes;
|
|
||||||
if (offset >= job->len) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
bytes = job->len - offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TODO job_progress_set_remaining() would make more sense */
|
/* TODO job_progress_set_remaining() would make more sense */
|
||||||
job_progress_update(&job->common.job,
|
job_progress_update(&job->common.job,
|
||||||
job->len - hbitmap_count(job->copy_bitmap));
|
job->len - bdrv_get_dirty_count(job->copy_bitmap));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int coroutine_fn backup_run(Job *job, Error **errp)
|
static int coroutine_fn backup_run(Job *job, Error **errp)
|
||||||
@ -467,7 +467,7 @@ static int coroutine_fn backup_run(Job *job, Error **errp)
|
|||||||
if (s->sync_mode == MIRROR_SYNC_MODE_BITMAP) {
|
if (s->sync_mode == MIRROR_SYNC_MODE_BITMAP) {
|
||||||
backup_incremental_init_copy_bitmap(s);
|
backup_incremental_init_copy_bitmap(s);
|
||||||
} else {
|
} else {
|
||||||
hbitmap_set(s->copy_bitmap, 0, s->len);
|
bdrv_set_dirty_bitmap(s->copy_bitmap, 0, s->len);
|
||||||
}
|
}
|
||||||
|
|
||||||
s->before_write.notify = backup_before_write_notify;
|
s->before_write.notify = backup_before_write_notify;
|
||||||
@ -560,7 +560,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
|||||||
BackupBlockJob *job = NULL;
|
BackupBlockJob *job = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
int64_t cluster_size;
|
int64_t cluster_size;
|
||||||
HBitmap *copy_bitmap = NULL;
|
BdrvDirtyBitmap *copy_bitmap = NULL;
|
||||||
|
|
||||||
assert(bs);
|
assert(bs);
|
||||||
assert(target);
|
assert(target);
|
||||||
@ -630,7 +630,11 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
copy_bitmap = hbitmap_alloc(len, ctz32(cluster_size));
|
copy_bitmap = bdrv_create_dirty_bitmap(bs, cluster_size, NULL, errp);
|
||||||
|
if (!copy_bitmap) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
bdrv_disable_dirty_bitmap(copy_bitmap);
|
||||||
|
|
||||||
/* job->len is fixed, so we can't allow resize */
|
/* job->len is fixed, so we can't allow resize */
|
||||||
job = block_job_create(job_id, &backup_job_driver, txn, bs,
|
job = block_job_create(job_id, &backup_job_driver, txn, bs,
|
||||||
@ -682,7 +686,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
|
|||||||
error:
|
error:
|
||||||
if (copy_bitmap) {
|
if (copy_bitmap) {
|
||||||
assert(!job || !job->copy_bitmap);
|
assert(!job || !job->copy_bitmap);
|
||||||
hbitmap_free(copy_bitmap);
|
bdrv_release_dirty_bitmap(bs, copy_bitmap);
|
||||||
}
|
}
|
||||||
if (sync_bitmap) {
|
if (sync_bitmap) {
|
||||||
bdrv_reclaim_dirty_bitmap(bs, sync_bitmap, NULL);
|
bdrv_reclaim_dirty_bitmap(bs, sync_bitmap, NULL);
|
||||||
|
Loading…
Reference in New Issue
Block a user