From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:52314) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YGpZF-0006wF-IM for qemu-devel@nongnu.org; Thu, 29 Jan 2015 08:55:35 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YGpZ9-0000w6-OM for qemu-devel@nongnu.org; Thu, 29 Jan 2015 08:55:33 -0500 Received: from mx2.parallels.com ([199.115.105.18]:45755) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YGpZ9-0000vt-FH for qemu-devel@nongnu.org; Thu, 29 Jan 2015 08:55:27 -0500 Message-ID: <54CA3BC6.4080907@parallels.com> Date: Thu, 29 Jan 2015 16:55:18 +0300 From: Vladimir Sementsov-Ogievskiy MIME-Version: 1.0 References: <1421080265-2228-1-git-send-email-jsnow@redhat.com> <1421080265-2228-4-git-send-email-jsnow@redhat.com> In-Reply-To: <1421080265-2228-4-git-send-email-jsnow@redhat.com> Content-Type: text/plain; charset="utf-8"; format=flowed Content-Transfer-Encoding: 7bit Subject: Re: [Qemu-devel] [PATCH v11 03/13] qmp: Add block-dirty-bitmap-add and block-dirty-bitmap-remove List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: John Snow , qemu-devel@nongnu.org Cc: kwolf@redhat.com, famz@redhat.com, armbru@redhat.com, mreitz@redhat.com, stefanha@redhat.com s/{'command'/{ 'command'/g - to be consistent with other staff in qapi/block-core.json and the same fix for block-dirty-bitmap-enable and block-dirty-bitmap-disable Best regards, Vladimir On 12.01.2015 19:30, John Snow wrote: > From: Fam Zheng > > The new command pair is added to manage user created dirty bitmap. The > dirty bitmap's name is mandatory and must be unique for the same device, > but different devices can have bitmaps with the same names. > > The granularity is an optional field. If it is not specified, we will > choose a default granularity based on the cluster size if available, > clamped to between 4K and 64K to mirror how the 'mirror' code was > already choosing granularity. If we do not have cluster size info > available, we choose 64K. This code has been factored out into a helper > shared with block/mirror. > > This patch also introduces the 'block_dirty_bitmap_lookup' helper, > which takes a device name and a dirty bitmap name and validates the > lookup, returning NULL and setting errp if there is a problem with > either field. This helper will be re-used in future patches in this > series. > > The types added to block-core.json will be re-used in future patches > in this series, see: > 'qapi: Add transaction support to block-dirty-bitmap-{add, enable, disable}' > > Signed-off-by: Fam Zheng > Signed-off-by: John Snow > --- > block.c | 20 ++++++++++ > block/mirror.c | 10 +---- > blockdev.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++ > include/block/block.h | 1 + > qapi/block-core.json | 55 +++++++++++++++++++++++++++ > qmp-commands.hx | 51 +++++++++++++++++++++++++ > 6 files changed, 228 insertions(+), 9 deletions(-) > > diff --git a/block.c b/block.c > index bfeae6b..3eb77ee 100644 > --- a/block.c > +++ b/block.c > @@ -5417,6 +5417,26 @@ int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector > } > } > > +/** > + * Chooses a default granularity based on the existing cluster size, > + * but clamped between [4K, 64K]. Defaults to 64K in the case that there > + * is no cluster size information available. > + */ > +uint64_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs) > +{ > + BlockDriverInfo bdi; > + uint64_t granularity; > + > + if (bdrv_get_info(bs, &bdi) >= 0 && bdi.cluster_size != 0) { > + granularity = MAX(4096, bdi.cluster_size); > + granularity = MIN(65536, granularity); > + } else { > + granularity = 65536; > + } > + > + return granularity; > +} > + > void bdrv_dirty_iter_init(BlockDriverState *bs, > BdrvDirtyBitmap *bitmap, HBitmapIter *hbi) > { > diff --git a/block/mirror.c b/block/mirror.c > index d819952..fc545f1 100644 > --- a/block/mirror.c > +++ b/block/mirror.c > @@ -667,15 +667,7 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target, > MirrorBlockJob *s; > > if (granularity == 0) { > - /* Choose the default granularity based on the target file's cluster > - * size, clamped between 4k and 64k. */ > - BlockDriverInfo bdi; > - if (bdrv_get_info(target, &bdi) >= 0 && bdi.cluster_size != 0) { > - granularity = MAX(4096, bdi.cluster_size); > - granularity = MIN(65536, granularity); > - } else { > - granularity = 65536; > - } > + granularity = bdrv_get_default_bitmap_granularity(target); > } > > assert ((granularity & (granularity - 1)) == 0); > diff --git a/blockdev.c b/blockdev.c > index 5651a8e..95251c7 100644 > --- a/blockdev.c > +++ b/blockdev.c > @@ -1173,6 +1173,48 @@ out_aio_context: > return NULL; > } > > +/** > + * Return a dirty bitmap (if present), after validating > + * the node reference and bitmap names. Returns NULL on error, > + * including when the BDS and/or bitmap is not found. > + */ > +static BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *node_ref, > + const char *name, > + BlockDriverState **pbs, > + Error **errp) > +{ > + BlockDriverState *bs; > + BdrvDirtyBitmap *bitmap; > + > + if (!node_ref) { > + error_setg(errp, "Node reference cannot be NULL"); > + return NULL; > + } > + if (!name) { > + error_setg(errp, "Bitmap name cannot be NULL"); > + return NULL; > + } > + > + bs = bdrv_lookup_bs(node_ref, node_ref, errp); > + if (!bs) { > + error_setg(errp, "Node reference '%s' not found", node_ref); > + return NULL; > + } > + > + /* If caller provided a BDS*, provide the result of that lookup, too. */ > + if (pbs) { > + *pbs = bs; > + } > + > + bitmap = bdrv_find_dirty_bitmap(bs, name); > + if (!bitmap) { > + error_setg(errp, "Dirty bitmap not found: %s", name); > + return NULL; > + } > + > + return bitmap; > +} > + > /* New and old BlockDriverState structs for atomic group operations */ > > typedef struct BlkTransactionState BlkTransactionState; > @@ -1894,6 +1936,64 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd, > aio_context_release(aio_context); > } > > +void qmp_block_dirty_bitmap_add(const char *node_ref, const char *name, > + bool has_granularity, int64_t granularity, > + Error **errp) > +{ > + AioContext *aio_context; > + BlockDriverState *bs; > + > + if (!name || name[0] == '\0') { > + error_setg(errp, "Bitmap name cannot be empty"); > + return; > + } > + > + bs = bdrv_lookup_bs(node_ref, node_ref, errp); > + if (!bs) { > + return; > + } > + > + aio_context = bdrv_get_aio_context(bs); > + aio_context_acquire(aio_context); > + > + if (has_granularity) { > + if (granularity < 512 || !is_power_of_2(granularity)) { > + error_setg(errp, "Granularity must be power of 2 " > + "and at least 512"); > + goto out; > + } > + } else { > + /* Default to cluster size, if available: */ > + granularity = bdrv_get_default_bitmap_granularity(bs); > + } > + > + bdrv_create_dirty_bitmap(bs, granularity, name, errp); > + > + out: > + aio_context_release(aio_context); > +} > + > +void qmp_block_dirty_bitmap_remove(const char *node_ref, const char *name, > + Error **errp) > +{ > + AioContext *aio_context; > + BlockDriverState *bs; > + BdrvDirtyBitmap *bitmap; > + > + bitmap = block_dirty_bitmap_lookup(node_ref, name, &bs, errp); > + if (!bitmap || !bs) { > + return; > + } > + > + aio_context = bdrv_get_aio_context(bs); > + aio_context_acquire(aio_context); > + > + bdrv_dirty_bitmap_make_anon(bs, bitmap); > + bdrv_release_dirty_bitmap(bs, bitmap); > + > + aio_context_release(aio_context); > +} > + > int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data) > { > const char *id = qdict_get_str(qdict, "id"); > diff --git a/include/block/block.h b/include/block/block.h > index bf767af..44dd6ca 100644 > --- a/include/block/block.h > +++ b/include/block/block.h > @@ -438,6 +438,7 @@ BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs, > void bdrv_dirty_bitmap_make_anon(BlockDriverState *bs, BdrvDirtyBitmap *bitmap); > void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap); > BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs); > +uint64_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs); > int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector); > void bdrv_set_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, > int64_t cur_sector, int nr_sectors); > diff --git a/qapi/block-core.json b/qapi/block-core.json > index d176324..f79d165 100644 > --- a/qapi/block-core.json > +++ b/qapi/block-core.json > @@ -894,6 +894,61 @@ > '*on-target-error': 'BlockdevOnError' } } > > ## > +# @BlockDirtyBitmap > +# > +# @node-ref: name of device/node-name which the bitmap is tracking > +# > +# @name: name of the dirty bitmap > +# > +# Since 2.3 > +## > +{ 'type': 'BlockDirtyBitmap', > + 'data': { 'node-ref': 'str', 'name': 'str' } } > + > +## > +# @BlockDirtyBitmapAdd > +# > +# @node-ref: name of device/node-name which the bitmap is tracking > +# > +# @name: name of the dirty bitmap > +# > +# @granularity: #optional the bitmap granularity, default is 64k for > +# block-dirty-bitmap-add > +# > +# Since 2.3 > +## > +{ 'type': 'BlockDirtyBitmapAdd', > + 'data': { 'node-ref': 'str', 'name': 'str', '*granularity': 'int' } } > + > +## > +# @block-dirty-bitmap-add > +# > +# Create a dirty bitmap with a name on the node > +# > +# Returns: nothing on success > +# If @node-ref is not a valid block device, DeviceNotFound > +# If @name is already taken, GenericError with an explanation > +# > +# Since 2.3 > +## > +{'command': 'block-dirty-bitmap-add', > + 'data': 'BlockDirtyBitmapAdd' } > + > +## > +# @block-dirty-bitmap-remove > +# > +# Remove a dirty bitmap on the node > +# > +# Returns: nothing on success > +# If @node-ref is not a valid block device, DeviceNotFound > +# If @name is not found, GenericError with an explanation > +# > +# Since 2.3 > +## > +{'command': 'block-dirty-bitmap-remove', > + 'data': 'BlockDirtyBitmap' } > + > +## > # @block_set_io_throttle: > # > # Change I/O throttle limits for a block drive. > diff --git a/qmp-commands.hx b/qmp-commands.hx > index 6945d30..4ffca8a 100644 > --- a/qmp-commands.hx > +++ b/qmp-commands.hx > @@ -1202,6 +1202,57 @@ Example: > EQMP > > { > + .name = "block-dirty-bitmap-add", > + .args_type = "node-ref:B,name:s,granularity:i?", > + .mhandler.cmd_new = qmp_marshal_input_block_dirty_bitmap_add, > + }, > + { > + .name = "block-dirty-bitmap-remove", > + .args_type = "node-ref:B,name:s", > + .mhandler.cmd_new = qmp_marshal_input_block_dirty_bitmap_remove, > + }, > + > +SQMP > + > +block-dirty-bitmap-add > +---------------------- > +Since 2.3 > + > +Create a dirty bitmap with a name on the device, and start tracking the writes. > + > +Arguments: > + > +- "node-ref": device/node on which to create dirty bitmap (json-string) > +- "name": name of the new dirty bitmap (json-string) > +- "granularity": granularity to track writes with (int, optional) > + > +Example: > + > +-> { "execute": "block-dirty-bitmap-add", "arguments": { "node-ref": "drive0", > + "name": "bitmap0" } } > +<- { "return": {} } > + > +block-dirty-bitmap-remove > +------------------------- > +Since 2.3 > + > +Stop write tracking and remove the dirty bitmap that was created with > +block-dirty-bitmap-add. > + > +Arguments: > + > +- "node-ref": device/node on which to remove dirty bitmap (json-string) > +- "name": name of the dirty bitmap to remove (json-string) > + > +Example: > + > +-> { "execute": "block-dirty-bitmap-remove", "arguments": { "node-ref": "drive0", > + "name": "bitmap0" } } > +<- { "return": {} } > + > +EQMP > + > + { > .name = "blockdev-snapshot-sync", > .args_type = "device:s?,node-name:s?,snapshot-file:s,snapshot-node-name:s?,format:s?,mode:s?", > .mhandler.cmd_new = qmp_marshal_input_blockdev_snapshot_sync,