[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-block] [PATCH v3 18/18] block/backup: use fleecing-hook instead of
From: |
Vladimir Sementsov-Ogievskiy |
Subject: |
[Qemu-block] [PATCH v3 18/18] block/backup: use fleecing-hook instead of write notifiers |
Date: |
Mon, 1 Oct 2018 13:29:28 +0300 |
Drop write notifiers and use filter node instead. Changes:
1. copy-before-writes now handled by filter node, so, drop all
is_write_notifier arguments.
2. we don't have intersecting requests, so their handling is dropped.
Instead, synchronization works as follows:
when backup or fleecing-hook starts copying of some area it firstly
clears copy-bitmap bits, and nobody touches areas, not marked with
dirty bits in copy-bitmap, so there no intersection. Also, read
requests are marked serializing, to not interfer with guest writes and
not read changed data from source (before reading we clear
corresponding bit in copy-bitmap, so, this area is not more handled by
fleecing-hook).
3. To sync with in-flight requests we no just drain hook node, we don't
need rw-lock.
Signed-off-by: Vladimir Sementsov-Ogievskiy <address@hidden>
---
block/backup.c | 142 ++++++++++++++++---------------------------------
1 file changed, 45 insertions(+), 97 deletions(-)
diff --git a/block/backup.c b/block/backup.c
index 6cab54dea4..9c85b23d68 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -29,13 +29,6 @@
#define BACKUP_CLUSTER_SIZE_DEFAULT (1 << 16)
-typedef struct CowRequest {
- int64_t start_byte;
- int64_t end_byte;
- QLIST_ENTRY(CowRequest) list;
- CoQueue wait_queue; /* coroutines blocked on this request */
-} CowRequest;
-
typedef struct BackupBlockJob {
BlockJob common;
BlockBackend *target;
@@ -44,13 +37,10 @@ typedef struct BackupBlockJob {
MirrorSyncMode sync_mode;
BlockdevOnError on_source_error;
BlockdevOnError on_target_error;
- CoRwlock flush_rwlock;
uint64_t len;
uint64_t bytes_read;
int64_t cluster_size;
bool compress;
- NotifierWithReturn before_write;
- QLIST_HEAD(, CowRequest) inflight_reqs;
BdrvDirtyBitmap *copy_bitmap;
bool copy_bitmap_created;
@@ -58,53 +48,18 @@ typedef struct BackupBlockJob {
int64_t copy_range_size;
bool serialize_target_writes;
+
+ BlockDriverState *hook;
+ uint64_t fleecing_hook_progress;
} BackupBlockJob;
static const BlockJobDriver backup_job_driver;
-/* See if in-flight requests overlap and wait for them to complete */
-static void coroutine_fn wait_for_overlapping_requests(BackupBlockJob *job,
- int64_t start,
- int64_t end)
-{
- CowRequest *req;
- bool retry;
-
- do {
- retry = false;
- QLIST_FOREACH(req, &job->inflight_reqs, list) {
- if (end > req->start_byte && start < req->end_byte) {
- qemu_co_queue_wait(&req->wait_queue, NULL);
- retry = true;
- break;
- }
- }
- } while (retry);
-}
-
-/* Keep track of an in-flight request */
-static void cow_request_begin(CowRequest *req, BackupBlockJob *job,
- int64_t start, int64_t end)
-{
- req->start_byte = start;
- req->end_byte = end;
- qemu_co_queue_init(&req->wait_queue);
- QLIST_INSERT_HEAD(&job->inflight_reqs, req, list);
-}
-
-/* Forget about a completed request */
-static void cow_request_end(CowRequest *req)
-{
- QLIST_REMOVE(req, list);
- qemu_co_queue_restart_all(&req->wait_queue);
-}
-
/* Copy range to target with a bounce buffer and return the bytes copied. If
* error occurred, return a negative error number */
static int coroutine_fn backup_cow_with_bounce_buffer(BackupBlockJob *job,
int64_t start,
int64_t end,
- bool is_write_notifier,
bool *error_is_read,
void **bounce_buffer)
{
@@ -113,7 +68,7 @@ static int coroutine_fn
backup_cow_with_bounce_buffer(BackupBlockJob *job,
QEMUIOVector qiov;
BlockBackend *blk = job->common.blk;
int nbytes;
- int read_flags = is_write_notifier ? BDRV_REQ_NO_SERIALISING : 0;
+ int read_flags = BDRV_REQ_SERIALISING;
int write_flags = job->serialize_target_writes ? BDRV_REQ_SERIALISING : 0;
assert(start % job->cluster_size == 0);
@@ -161,15 +116,13 @@ fail:
/* Copy range to target and return the bytes copied. If error occurred, return
a
* negative error number. */
static int coroutine_fn backup_cow_with_offload(BackupBlockJob *job,
- int64_t start,
- int64_t end,
- bool is_write_notifier)
+ int64_t start, int64_t end)
{
int ret;
int nr_clusters;
BlockBackend *blk = job->common.blk;
int nbytes;
- int read_flags = is_write_notifier ? BDRV_REQ_NO_SERIALISING : 0;
+ int read_flags = BDRV_REQ_SERIALISING;
int write_flags = job->serialize_target_writes ? BDRV_REQ_SERIALISING : 0;
assert(QEMU_IS_ALIGNED(job->copy_range_size, job->cluster_size));
@@ -192,24 +145,18 @@ static int coroutine_fn
backup_cow_with_offload(BackupBlockJob *job,
static int coroutine_fn backup_do_cow(BackupBlockJob *job,
int64_t offset, uint64_t bytes,
- bool *error_is_read,
- bool is_write_notifier)
+ bool *error_is_read)
{
- CowRequest cow_request;
int ret = 0;
int64_t start, end; /* bytes */
void *bounce_buffer = NULL;
-
- qemu_co_rwlock_rdlock(&job->flush_rwlock);
+ uint64_t fleecing_hook_progress;
start = QEMU_ALIGN_DOWN(offset, job->cluster_size);
end = QEMU_ALIGN_UP(bytes + offset, job->cluster_size);
trace_backup_do_cow_enter(job, start, offset, bytes);
- wait_for_overlapping_requests(job, start, end);
- cow_request_begin(&cow_request, job, start, end);
-
while (start < end) {
if (!bdrv_get_dirty_locked(NULL, job->copy_bitmap, start)) {
trace_backup_do_cow_skip(job, start);
@@ -220,13 +167,13 @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job,
trace_backup_do_cow_process(job, start);
if (job->use_copy_range) {
- ret = backup_cow_with_offload(job, start, end, is_write_notifier);
+ ret = backup_cow_with_offload(job, start, end);
if (ret < 0) {
job->use_copy_range = false;
}
}
if (!job->use_copy_range) {
- ret = backup_cow_with_bounce_buffer(job, start, end,
is_write_notifier,
+ ret = backup_cow_with_bounce_buffer(job, start, end,
error_is_read, &bounce_buffer);
}
if (ret < 0) {
@@ -238,7 +185,10 @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job,
*/
start += ret;
job->bytes_read += ret;
- job_progress_update(&job->common.job, ret);
+ fleecing_hook_progress = bdrv_fleecing_hook_progress(job->hook);
+ job_progress_update(&job->common.job, ret + fleecing_hook_progress -
+ job->fleecing_hook_progress);
+ job->fleecing_hook_progress = fleecing_hook_progress;
ret = 0;
}
@@ -246,29 +196,11 @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job,
qemu_vfree(bounce_buffer);
}
- cow_request_end(&cow_request);
-
trace_backup_do_cow_return(job, offset, bytes, ret);
- qemu_co_rwlock_unlock(&job->flush_rwlock);
-
return ret;
}
-static int coroutine_fn backup_before_write_notify(
- NotifierWithReturn *notifier,
- void *opaque)
-{
- BackupBlockJob *job = container_of(notifier, BackupBlockJob, before_write);
- BdrvTrackedRequest *req = opaque;
-
- assert(req->bs == blk_bs(job->common.blk));
- assert(QEMU_IS_ALIGNED(req->offset, BDRV_SECTOR_SIZE));
- assert(QEMU_IS_ALIGNED(req->bytes, BDRV_SECTOR_SIZE));
-
- return backup_do_cow(job, req->offset, req->bytes, NULL, true);
-}
-
static void backup_cleanup_sync_bitmap(BackupBlockJob *job, int ret)
{
BdrvDirtyBitmap *bm;
@@ -312,6 +244,8 @@ static void backup_clean(Job *job)
bdrv_release_dirty_bitmap(blk_bs(s->common.blk), s->copy_bitmap);
s->copy_bitmap = NULL;
}
+
+ bdrv_fleecing_hook_drop(s->hook);
}
static void backup_attached_aio_context(BlockJob *job, AioContext *aio_context)
@@ -396,8 +330,7 @@ static int coroutine_fn
backup_run_incremental(BackupBlockJob *job)
if (yield_and_check(job)) {
goto out;
}
- ret = backup_do_cow(job, offset,
- job->cluster_size, &error_is_read, false);
+ ret = backup_do_cow(job, offset, job->cluster_size,
&error_is_read);
if (ret < 0 && backup_error_action(job, error_is_read, -ret) ==
BLOCK_ERROR_ACTION_REPORT)
{
@@ -441,9 +374,7 @@ static int coroutine_fn backup_run(Job *job, Error **errp)
BlockDriverState *bs = blk_bs(s->common.blk);
int64_t offset;
int ret = 0;
-
- QLIST_INIT(&s->inflight_reqs);
- qemu_co_rwlock_init(&s->flush_rwlock);
+ uint64_t fleecing_hook_progress;
job_progress_set_remaining(job, s->len);
@@ -455,15 +386,12 @@ static int coroutine_fn backup_run(Job *job, Error **errp)
bdrv_set_dirty_bitmap(s->copy_bitmap, 0, s->len);
}
- s->before_write.notify = backup_before_write_notify;
- bdrv_add_before_write_notifier(bs, &s->before_write);
-
if (s->sync_mode == MIRROR_SYNC_MODE_NONE) {
/* All bits are set in copy_bitmap to allow any cluster to be copied.
* This does not actually require them to be copied. */
while (!job_is_cancelled(job)) {
- /* Yield until the job is cancelled. We just let our before_write
- * notify callback service CoW requests. */
+ /* Yield until the job is cancelled. We just let our fleecing-hook
+ * fileter driver service CbW requests. */
job_yield(job);
}
} else if (s->sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) {
@@ -514,7 +442,7 @@ static int coroutine_fn backup_run(Job *job, Error **errp)
ret = alloced;
} else {
ret = backup_do_cow(s, offset, s->cluster_size,
- &error_is_read, false);
+ &error_is_read);
}
if (ret < 0) {
/* Depending on error action, fail now or retry cluster */
@@ -530,11 +458,13 @@ static int coroutine_fn backup_run(Job *job, Error **errp)
}
}
- notifier_with_return_remove(&s->before_write);
+ /* wait pending CBW operations in fleecing hook */
+ bdrv_drain(s->hook);
- /* wait until pending backup_do_cow() calls have completed */
- qemu_co_rwlock_wrlock(&s->flush_rwlock);
- qemu_co_rwlock_unlock(&s->flush_rwlock);
+ fleecing_hook_progress = bdrv_fleecing_hook_progress(s->hook);
+ job_progress_update(job, ret + fleecing_hook_progress -
+ s->fleecing_hook_progress);
+ s->fleecing_hook_progress = fleecing_hook_progress;
return ret;
}
@@ -573,6 +503,7 @@ BlockJob *backup_job_create(const char *job_id,
BlockDriverState *bs,
int64_t cluster_size;
BdrvDirtyBitmap *copy_bitmap = NULL;
bool copy_bitmap_created = false;
+ BlockDriverState *hook;
assert(bs);
assert(target);
@@ -669,6 +600,19 @@ BlockJob *backup_job_create(const char *job_id,
BlockDriverState *bs,
return NULL;
}
+ /* bdrv_get_device_name will not help to find device name starting from
+ * @bs after fleecing hook append, so let's calculate job_id before. Do
+ * it in the same way like block_job_create
+ */
+ if (job_id == NULL && !(creation_flags & JOB_INTERNAL)) {
+ job_id = bdrv_get_device_name(bs);
+ }
+
+ hook = bdrv_fleecing_hook_append(bs, target, x_copy_bitmap, errp);
+ if (!hook) {
+ return NULL;
+ }
+
len = bdrv_getlength(bs);
if (len < 0) {
error_setg_errno(errp, -len, "unable to get length for '%s'",
@@ -718,6 +662,7 @@ BlockJob *backup_job_create(const char *job_id,
BlockDriverState *bs,
block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL,
&error_abort);
job->len = len;
+ job->hook = hook;
return &job->common;
@@ -733,6 +678,9 @@ BlockJob *backup_job_create(const char *job_id,
BlockDriverState *bs,
backup_clean(&job->common.job);
job_early_fail(&job->common.job);
}
+ if (hook) {
+ bdrv_fleecing_hook_drop(hook);
+ }
return NULL;
}
--
2.18.0
- Re: [Qemu-block] [PATCH v3 13/18] block: introduce new filter driver: fleecing-hook, (continued)
- Re: [Qemu-block] [PATCH v3 13/18] block: introduce new filter driver: fleecing-hook, Vladimir Sementsov-Ogievskiy, 2018/10/04
- Re: [Qemu-block] [PATCH v3 13/18] block: introduce new filter driver: fleecing-hook, Vladimir Sementsov-Ogievskiy, 2018/10/05
- Re: [Qemu-block] [PATCH v3 13/18] block: introduce new filter driver: fleecing-hook, Kevin Wolf, 2018/10/05
- Re: [Qemu-block] [PATCH v3 13/18] block: introduce new filter driver: fleecing-hook, Vladimir Sementsov-Ogievskiy, 2018/10/05
- Re: [Qemu-block] [PATCH v3 13/18] block: introduce new filter driver: fleecing-hook, Eric Blake, 2018/10/05
- Re: [Qemu-block] [PATCH v3 13/18] block: introduce new filter driver: fleecing-hook, Vladimir Sementsov-Ogievskiy, 2018/10/05
[Qemu-block] [PATCH v3 16/18] iotests: test new fleecing-hook driver in context of 222 iotest, Vladimir Sementsov-Ogievskiy, 2018/10/01
[Qemu-block] [PATCH v3 11/18] iotests: allow resume_drive by node name, Vladimir Sementsov-Ogievskiy, 2018/10/01
[Qemu-block] [PATCH v3 07/18] block/backup: allow use existent copy-bitmap, Vladimir Sementsov-Ogievskiy, 2018/10/01
[Qemu-block] [PATCH v3 17/18] block/backup: tiny refactor backup_job_create, Vladimir Sementsov-Ogievskiy, 2018/10/01
[Qemu-block] [PATCH v3 18/18] block/backup: use fleecing-hook instead of write notifiers,
Vladimir Sementsov-Ogievskiy <=
[Qemu-block] [PATCH v3 09/18] block: improve should_update_child, Vladimir Sementsov-Ogievskiy, 2018/10/01
[Qemu-block] [PATCH v3 15/18] qapi: add x-drop-fleecing qmp command, Vladimir Sementsov-Ogievskiy, 2018/10/01
[Qemu-block] [PATCH v3 12/18] iotests: prepare 055 to graph changes during backup job, Vladimir Sementsov-Ogievskiy, 2018/10/01
Re: [Qemu-block] [PATCH v3 00/18] fleecing-hook driver for backup, Eric Blake, 2018/10/02