From: Eric Blake <eblake@redhat.com>
To: qemu-devel@nongnu.org
Cc: kwolf@redhat.com, vsementsov@virtuozzo.com,
qemu-block@nongnu.org, armbru@redhat.com, mreitz@redhat.com,
pkrempa@redhat.com, jsnow@redhat.com
Subject: [PATCH v3 1/6] block: add bitmap-populate job
Date: Fri, 19 Jun 2020 14:56:16 -0500 [thread overview]
Message-ID: <20200619195621.58740-2-eblake@redhat.com> (raw)
In-Reply-To: <20200619195621.58740-1-eblake@redhat.com>
From: John Snow <jsnow@redhat.com>
This job copies the allocation map into a bitmap. It's a job because
there's no guarantee that allocation interrogation will be quick (or
won't hang), so it cannot be retrofitted into block-dirty-bitmap-merge.
It was designed with different possible population patterns in mind,
but only top layer allocation was implemented for now.
Signed-off-by: John Snow <jsnow@redhat.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
---
qapi/block-core.json | 48 +++++++++
qapi/job.json | 6 +-
include/block/block_int.h | 21 ++++
block/bitmap-populate.c | 207 ++++++++++++++++++++++++++++++++++++++
blockjob.c | 3 +-
MAINTAINERS | 1 +
block/Makefile.objs | 1 +
7 files changed, 285 insertions(+), 2 deletions(-)
create mode 100644 block/bitmap-populate.c
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 0e1c6a59f228..a1bcdba04423 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -2211,6 +2211,54 @@
{ 'command': 'block-dirty-bitmap-merge',
'data': 'BlockDirtyBitmapMerge' }
+##
+# @BitmapPattern:
+#
+# An enumeration of possible patterns that can be written into a bitmap.
+#
+# @allocation-top: The allocation status of the top layer
+# of the attached storage node.
+#
+# Since: 5.1
+##
+{ 'enum': 'BitmapPattern',
+ 'data': ['allocation-top'] }
+
+##
+# @BlockDirtyBitmapPopulate:
+#
+# @job-id: identifier for the newly-created block job.
+#
+# @pattern: What pattern should be written into the bitmap?
+#
+# @on-error: the action to take if an error is encountered on a bitmap's
+# attached node, default 'report'.
+# 'stop' and 'enospc' can only be used if the block device supports
+# io-status (see BlockInfo).
+#
+# @auto-finalize: When false, this job will wait in a PENDING state after it has
+# finished its work, waiting for @block-job-finalize before
+# making any block graph changes.
+# When true, this job will automatically
+# perform its abort or commit actions.
+# Defaults to true.
+#
+# @auto-dismiss: When false, this job will wait in a CONCLUDED state after it
+# has completely ceased all work, and awaits @block-job-dismiss.
+# When true, this job will automatically disappear from the query
+# list without user intervention.
+# Defaults to true.
+#
+# Since: 5.1
+##
+{ 'struct': 'BlockDirtyBitmapPopulate',
+ 'base': 'BlockDirtyBitmap',
+ 'data': { 'job-id': 'str',
+ 'pattern': 'BitmapPattern',
+ '*on-error': 'BlockdevOnError',
+ '*auto-finalize': 'bool',
+ '*auto-dismiss': 'bool' } }
+
##
# @BlockDirtyBitmapSha256:
#
diff --git a/qapi/job.json b/qapi/job.json
index 5e658281f5c4..33ff3500f794 100644
--- a/qapi/job.json
+++ b/qapi/job.json
@@ -19,10 +19,14 @@
#
# @create: image creation job type, see "blockdev-create" (since 3.0)
#
+# @bitmap-populate: drive bitmap population job type, see
+# "block-dirty-bitmap-populate" (since 5.1)
+#
# Since: 1.7
##
{ 'enum': 'JobType',
- 'data': ['commit', 'stream', 'mirror', 'backup', 'create'] }
+ 'data': ['commit', 'stream', 'mirror', 'backup', 'create',
+ 'bitmap-populate'] }
##
# @JobStatus:
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 791de6a59c2c..93fb886e7e97 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -1231,6 +1231,27 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
BlockCompletionFunc *cb, void *opaque,
JobTxn *txn, Error **errp);
+/*
+ * bitpop_job_create: Create a new bitmap population job.
+ *
+ * @job_id: The id of the newly-created job.
+ * @bs: Block device associated with the @target_bitmap.
+ * @target_bitmap: The bitmap to populate.
+ * @on_error: What to do if an error on @bs is encountered.
+ * @creation_flags: Flags that control the behavior of the Job lifetime.
+ * See @BlockJobCreateFlags
+ * @cb: Completion function for the job.
+ * @opaque: Opaque pointer value passed to @cb.
+ * @txn: Transaction that this job is part of (may be NULL).
+ */
+BlockJob *bitpop_job_create(const char *job_id, BlockDriverState *bs,
+ BdrvDirtyBitmap *target_bitmap,
+ BitmapPattern pattern,
+ BlockdevOnError on_error,
+ int creation_flags,
+ BlockCompletionFunc *cb, void *opaque,
+ JobTxn *txn, Error **errp);
+
BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
const char *child_name,
const BdrvChildClass *child_class,
diff --git a/block/bitmap-populate.c b/block/bitmap-populate.c
new file mode 100644
index 000000000000..901b78b56c3e
--- /dev/null
+++ b/block/bitmap-populate.c
@@ -0,0 +1,207 @@
+/*
+ * Async Dirty Bitmap Populator
+ *
+ * Copyright (C) 2020 Red Hat, Inc.
+ *
+ * Authors:
+ * John Snow <jsnow@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+
+#include "trace.h"
+#include "block/block.h"
+#include "block/block_int.h"
+#include "block/blockjob_int.h"
+#include "block/block_backup.h"
+#include "block/block-copy.h"
+#include "qapi/error.h"
+#include "qapi/qmp/qerror.h"
+#include "qemu/ratelimit.h"
+#include "qemu/cutils.h"
+#include "sysemu/block-backend.h"
+#include "qemu/bitmap.h"
+#include "qemu/error-report.h"
+
+typedef struct BitpopBlockJob {
+ BlockJob common;
+ BlockDriverState *bs;
+ BdrvDirtyBitmap *target_bitmap;
+ BdrvDirtyBitmap *new_bitmap;
+ BlockdevOnError on_error;
+ uint64_t len;
+} BitpopBlockJob;
+
+static const BlockJobDriver bitpop_job_driver;
+
+static void bitpop_commit(Job *job)
+{
+ BitpopBlockJob *s = container_of(job, BitpopBlockJob, common.job);
+
+ bdrv_dirty_bitmap_merge_internal(s->target_bitmap, s->new_bitmap,
+ NULL, true);
+}
+
+/* no abort needed; just clean without committing. */
+
+static void bitpop_clean(Job *job)
+{
+ BitpopBlockJob *s = container_of(job, BitpopBlockJob, common.job);
+
+ bdrv_release_dirty_bitmap(s->new_bitmap);
+ bdrv_dirty_bitmap_set_busy(s->target_bitmap, false);
+}
+
+static BlockErrorAction bitpop_error_action(BitpopBlockJob *job, int error)
+{
+ return block_job_error_action(&job->common, job->on_error, true, error);
+}
+
+static bool coroutine_fn yield_and_check(Job *job)
+{
+ if (job_is_cancelled(job)) {
+ return true;
+ }
+
+ job_sleep_ns(job, 0);
+
+ if (job_is_cancelled(job)) {
+ return true;
+ }
+
+ return false;
+}
+
+static int coroutine_fn bitpop_run(Job *job, Error **errp)
+{
+ BitpopBlockJob *s = container_of(job, BitpopBlockJob, common.job);
+ int ret = 0;
+ int64_t offset;
+ int64_t count;
+ int64_t bytes;
+
+ for (offset = 0; offset < s->len; ) {
+ if (yield_and_check(job)) {
+ ret = -ECANCELED;
+ break;
+ }
+
+ bytes = s->len - offset;
+ ret = bdrv_is_allocated(s->bs, offset, bytes, &count);
+ if (ret < 0) {
+ if (bitpop_error_action(s, -ret) == BLOCK_ERROR_ACTION_REPORT) {
+ break;
+ }
+ continue;
+ }
+
+ if (!count) {
+ ret = 0;
+ break;
+ }
+
+ if (ret) {
+ bdrv_set_dirty_bitmap(s->new_bitmap, offset, count);
+ ret = 0;
+ }
+
+ job_progress_update(job, count);
+ offset += count;
+ }
+
+ return ret;
+}
+
+static const BlockJobDriver bitpop_job_driver = {
+ .job_driver = {
+ .instance_size = sizeof(BitpopBlockJob),
+ .job_type = JOB_TYPE_BITMAP_POPULATE,
+ .free = block_job_free,
+ .user_resume = block_job_user_resume,
+ .run = bitpop_run,
+ .commit = bitpop_commit,
+ .clean = bitpop_clean,
+ }
+};
+
+
+BlockJob *bitpop_job_create(
+ const char *job_id,
+ BlockDriverState *bs,
+ BdrvDirtyBitmap *target_bitmap,
+ BitmapPattern pattern,
+ BlockdevOnError on_error,
+ int creation_flags,
+ BlockCompletionFunc *cb,
+ void *opaque,
+ JobTxn *txn,
+ Error **errp)
+{
+ int64_t len;
+ BitpopBlockJob *job = NULL;
+ int64_t cluster_size;
+ BdrvDirtyBitmap *new_bitmap = NULL;
+
+ assert(bs);
+ assert(target_bitmap);
+
+ if (!bdrv_is_inserted(bs)) {
+ error_setg(errp, "Device is not inserted: %s",
+ bdrv_get_device_name(bs));
+ return NULL;
+ }
+
+ if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
+ return NULL;
+ }
+
+ if (bdrv_dirty_bitmap_check(target_bitmap, BDRV_BITMAP_DEFAULT, errp)) {
+ return NULL;
+ }
+
+ if (pattern != BITMAP_PATTERN_ALLOCATION_TOP) {
+ error_setg(errp, "Unrecognized bitmap pattern");
+ return NULL;
+ }
+
+ len = bdrv_getlength(bs);
+ if (len < 0) {
+ error_setg_errno(errp, -len, "unable to get length for '%s'",
+ bdrv_get_device_or_node_name(bs));
+ return NULL;
+ }
+
+ /* NB: new bitmap is anonymous and enabled */
+ cluster_size = bdrv_dirty_bitmap_granularity(target_bitmap);
+ new_bitmap = bdrv_create_dirty_bitmap(bs, cluster_size, NULL, errp);
+ if (!new_bitmap) {
+ return NULL;
+ }
+
+ /* Take ownership; we reserve the right to write into this on-commit. */
+ bdrv_dirty_bitmap_set_busy(target_bitmap, true);
+
+ job = block_job_create(job_id, &bitpop_job_driver, txn, bs,
+ BLK_PERM_CONSISTENT_READ,
+ BLK_PERM_ALL & ~BLK_PERM_RESIZE,
+ 0, creation_flags,
+ cb, opaque, errp);
+ if (!job) {
+ bdrv_dirty_bitmap_set_busy(target_bitmap, false);
+ bdrv_release_dirty_bitmap(new_bitmap);
+ return NULL;
+ }
+
+ job->bs = bs;
+ job->on_error = on_error;
+ job->target_bitmap = target_bitmap;
+ job->new_bitmap = new_bitmap;
+ job->len = len;
+ job_progress_set_remaining(&job->common.job, job->len);
+
+ return &job->common;
+}
diff --git a/blockjob.c b/blockjob.c
index 470facfd47a0..e6ee8376645d 100644
--- a/blockjob.c
+++ b/blockjob.c
@@ -56,7 +56,8 @@ static bool is_block_job(Job *job)
return job_type(job) == JOB_TYPE_BACKUP ||
job_type(job) == JOB_TYPE_COMMIT ||
job_type(job) == JOB_TYPE_MIRROR ||
- job_type(job) == JOB_TYPE_STREAM;
+ job_type(job) == JOB_TYPE_STREAM ||
+ job_type(job) == JOB_TYPE_BITMAP_POPULATE;
}
BlockJob *block_job_next(BlockJob *bjob)
diff --git a/MAINTAINERS b/MAINTAINERS
index 955cc8dd5cd0..99651abcac4a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2050,6 +2050,7 @@ S: Supported
F: include/qemu/hbitmap.h
F: include/block/dirty-bitmap.h
F: block/monitor/bitmap-qmp-cmds.c
+F: block/bitmap-populate.c
F: block/dirty-bitmap.c
F: block/qcow2-bitmap.c
F: migration/block-dirty-bitmap.c
diff --git a/block/Makefile.objs b/block/Makefile.objs
index 96028eedcef7..55f5970f7625 100644
--- a/block/Makefile.objs
+++ b/block/Makefile.objs
@@ -36,6 +36,7 @@ block-obj-$(CONFIG_LIBSSH) += ssh.o
block-obj-y += accounting.o dirty-bitmap.o
block-obj-y += write-threshold.o
block-obj-y += backup.o
+block-obj-y += bitmap-populate.o
block-obj-$(CONFIG_REPLICATION) += replication.o
block-obj-y += throttle.o copy-on-read.o
block-obj-y += block-copy.o
--
2.27.0
next prev parent reply other threads:[~2020-06-19 19:59 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-06-19 19:56 [PATCH v3 0/6] block: add block-dirty-bitmap-populate job Eric Blake
2020-06-19 19:56 ` Eric Blake [this message]
2020-06-20 4:16 ` [PATCH v3 1/6] block: add bitmap-populate job Vladimir Sementsov-Ogievskiy
2020-06-22 21:44 ` Eric Blake
2020-06-23 7:01 ` Vladimir Sementsov-Ogievskiy
2020-09-02 15:58 ` Eric Blake
2020-06-23 11:50 ` Kevin Wolf
2020-06-19 19:56 ` [PATCH v3 2/6] blockdev: combine DriveBackupState and BlockdevBackupState Eric Blake
2020-06-22 5:12 ` Vladimir Sementsov-Ogievskiy
2020-06-22 21:45 ` Eric Blake
2020-06-19 19:56 ` [PATCH v3 3/6] qmp: expose block-dirty-bitmap-populate Eric Blake
2020-06-19 19:56 ` [PATCH v3 4/6] iotests: move bitmap helpers into their own file Eric Blake
2020-06-22 5:26 ` Vladimir Sementsov-Ogievskiy
2020-06-19 19:56 ` [PATCH v3 5/6] iotests: add 298 for block-dirty-bitmap-populate Eric Blake
2020-06-19 19:56 ` [PATCH v3 6/6] bitmaps: Use x- prefix for block-dirty-bitmap-popluate Eric Blake
2020-06-23 11:45 ` Kevin Wolf
2020-06-23 11:47 ` [PATCH v3 0/6] block: add block-dirty-bitmap-populate job Kevin Wolf
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200619195621.58740-2-eblake@redhat.com \
--to=eblake@redhat.com \
--cc=armbru@redhat.com \
--cc=jsnow@redhat.com \
--cc=kwolf@redhat.com \
--cc=mreitz@redhat.com \
--cc=pkrempa@redhat.com \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
--cc=vsementsov@virtuozzo.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.