diff mbox

[v4,2/9] qmp: Add dirty-bitmap-add and dirty-bitmap-remove

Message ID 1395911388-31027-3-git-send-email-famz@redhat.com
State New
Headers show

Commit Message

Fam Zheng March 27, 2014, 9:09 a.m. UTC
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.

Signed-off-by: Fam Zheng <famz@redhat.com>
---
 blockdev.c       | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 qapi-schema.json | 45 ++++++++++++++++++++++++++++++++++++++++++
 qmp-commands.hx  | 49 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 154 insertions(+)

Comments

Stefan Hajnoczi March 27, 2014, 3:43 p.m. UTC | #1
On Thu, Mar 27, 2014 at 05:09:41PM +0800, Fam Zheng wrote:
> @@ -1713,6 +1713,66 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
>      }
>  }
>  
> +void qmp_dirty_bitmap_add(const char *device, const char *name,
> +                          bool has_granularity, int64_t granularity,
> +                          Error **errp)
> +{
> +    BlockDriverState *bs;
> +    BdrvDirtyBitmap *bitmap;
> +
> +    bs = bdrv_find(device);
> +    if (!bs) {
> +        error_set(errp, QERR_DEVICE_NOT_FOUND, device);
> +        return;
> +    }
> +
> +    if (!name || name[0] == '\0') {
> +        error_setg(errp, "Bitmap name cannot be empty");
> +        return;
> +    }
> +    if (has_granularity) {
> +        if (granularity & (granularity - 1)) {
> +            error_setg(errp, "Granularity must be power of 2");
> +            return;
> +        }

granularity must be non-zero, otherwise bdrv_create_dirty_bitmap() hits
an assertion failure.

It should probably also be at least 512.

> +    } else {
> +        granularity = 65536;
> +    }
> +
> +    bitmap = bdrv_create_dirty_bitmap(bs, granularity, name, errp);
> +    if (!bitmap) {
> +        return;
> +    }

Useless error return.

> +}
> +
> +void qmp_dirty_bitmap_remove(const char *device, const char *name,
> +                             Error **errp)
> +{
> +    BlockDriverState *bs;
> +    BdrvDirtyBitmap *bitmap;
> +
> +    bs = bdrv_find(device);
> +    if (!bs) {
> +        error_set(errp, QERR_DEVICE_NOT_FOUND, device);
> +        return;
> +    }
> +
> +    if (!name || name[0] == '\0') {
> +        error_setg(errp, "Bitmap name cannot be empty");
> +        return;
> +    }
> +    bitmap = bdrv_find_dirty_bitmap(bs, name);
> +    if (!bitmap) {
> +        error_setg(errp, "Dirty bitmap not found: %s", name);
> +        return;
> +    }
> +
> +    /* Make it invisible to user in case the following
> +     * bdrv_release_dirty_bitmap doens't free it because of refcnt */

"doesn't"
Stefan Hajnoczi March 27, 2014, 4:09 p.m. UTC | #2
On Thu, Mar 27, 2014 at 05:09:41PM +0800, Fam Zheng wrote:
> +    if (has_granularity) {
> +        if (granularity & (granularity - 1)) {
> +            error_setg(errp, "Granularity must be power of 2");
> +            return;
> +        }
> +    } else {
> +        granularity = 65536;
> +    }

util/hbitmap.c has:
assert(granularity >= 0 && granularity < 64);

Please make sure the argument is checked before we pass it down.  We
should never hit an assertion failure due to bad inputs.

Stefan
Dr. David Alan Gilbert March 27, 2014, 4:39 p.m. UTC | #3
Hi Fam,
  Could you make this something like block-dirty-bitmap  - the RAM migration
also has a dirty bitmap, and it would just make it clearer.

Dave
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
Eric Blake March 27, 2014, 4:41 p.m. UTC | #4
On 03/27/2014 03:09 AM, Fam Zheng wrote:
> 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.
> 
> Signed-off-by: Fam Zheng <famz@redhat.com>
> ---

> +++ b/qapi-schema.json
> @@ -2209,6 +2209,51 @@
>              '*on-target-error': 'BlockdevOnError' } }
>  
>  ##
> +# @DirtyBitmap
> +#
> +# @device: name of device which the bitmap is tracking
> +#
> +# @name: name of the dirty bitmap
> +#
> +# @granularity: #optional the bitmap granularity, default is 64k for
> +#               dirty-bitmap-add

Optional, but only affects dirty-bitmap-add.  You later document...

> +# @dirty-bitmap-remove
> +#
> +# Remove a dirty bitmap on the device
> +#
> +# Setting granularity has no effect here.

...that it is silently ignored where it can't be used here, and again in
7/9 for both dirty-bitmap-disable and dirty-bitmap-enable.

I think it would be smarter to do:

{ 'type': 'DirtyBitmap',
  'data': { 'device': 'str', 'name': 'str' } }

{'command': 'dirty-bitmap-add',
  'data': { 'map': 'DirtyBitmap', '*granularity': 'int' } }

Or:

{ 'type': 'DirtyBitmap',
  'data': { 'device': 'str', 'name': 'str' } }
{ 'type': 'DirtyBitmapGranularity',
  'base': 'DirtyBitmap',
  'data': { '*granularity': 'int' } }
{'command': 'dirty-bitmap-add',
  'data': 'DirtyBitmapGranularity' }


which says that the 'DirtyBitmap' struct has no optional members, and
instead of silently ignoring an optional member in 3 commands, we
instead write the one command that takes the optional argument when we
actually care about it.
Fam Zheng April 1, 2014, 7:45 a.m. UTC | #5
On Thu, 03/27 16:43, Stefan Hajnoczi wrote:
> On Thu, Mar 27, 2014 at 05:09:41PM +0800, Fam Zheng wrote:
> > @@ -1713,6 +1713,66 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
> >      }
> >  }
> >  
> > +void qmp_dirty_bitmap_add(const char *device, const char *name,
> > +                          bool has_granularity, int64_t granularity,
> > +                          Error **errp)
> > +{
> > +    BlockDriverState *bs;
> > +    BdrvDirtyBitmap *bitmap;
> > +
> > +    bs = bdrv_find(device);
> > +    if (!bs) {
> > +        error_set(errp, QERR_DEVICE_NOT_FOUND, device);
> > +        return;
> > +    }
> > +
> > +    if (!name || name[0] == '\0') {
> > +        error_setg(errp, "Bitmap name cannot be empty");
> > +        return;
> > +    }
> > +    if (has_granularity) {
> > +        if (granularity & (granularity - 1)) {
> > +            error_setg(errp, "Granularity must be power of 2");
> > +            return;
> > +        }
> 
> granularity must be non-zero, otherwise bdrv_create_dirty_bitmap() hits
> an assertion failure.
> 
> It should probably also be at least 512.

Sure, adding a check.

> 
> > +    } else {
> > +        granularity = 65536;
> > +    }
> > +
> > +    bitmap = bdrv_create_dirty_bitmap(bs, granularity, name, errp);
> > +    if (!bitmap) {
> > +        return;
> > +    }
> 
> Useless error return.

Removing.

> 
> > +}
> > +
> > +void qmp_dirty_bitmap_remove(const char *device, const char *name,
> > +                             Error **errp)
> > +{
> > +    BlockDriverState *bs;
> > +    BdrvDirtyBitmap *bitmap;
> > +
> > +    bs = bdrv_find(device);
> > +    if (!bs) {
> > +        error_set(errp, QERR_DEVICE_NOT_FOUND, device);
> > +        return;
> > +    }
> > +
> > +    if (!name || name[0] == '\0') {
> > +        error_setg(errp, "Bitmap name cannot be empty");
> > +        return;
> > +    }
> > +    bitmap = bdrv_find_dirty_bitmap(bs, name);
> > +    if (!bitmap) {
> > +        error_setg(errp, "Dirty bitmap not found: %s", name);
> > +        return;
> > +    }
> > +
> > +    /* Make it invisible to user in case the following
> > +     * bdrv_release_dirty_bitmap doens't free it because of refcnt */
> 
> "doesn't"

Thanks,
Fam
Fam Zheng April 1, 2014, 7:48 a.m. UTC | #6
On Thu, 03/27 16:39, Dr. David Alan Gilbert wrote:
> Hi Fam,
>   Could you make this something like block-dirty-bitmap  - the RAM migration
> also has a dirty bitmap, and it would just make it clearer.

Good idea. Thanks, Dave.

Fam
Fam Zheng April 1, 2014, 8:02 a.m. UTC | #7
On Thu, 03/27 10:41, Eric Blake wrote:
> On 03/27/2014 03:09 AM, Fam Zheng wrote:
> > 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.
> > 
> > Signed-off-by: Fam Zheng <famz@redhat.com>
> > ---
> 
> > +++ b/qapi-schema.json
> > @@ -2209,6 +2209,51 @@
> >              '*on-target-error': 'BlockdevOnError' } }
> >  
> >  ##
> > +# @DirtyBitmap
> > +#
> > +# @device: name of device which the bitmap is tracking
> > +#
> > +# @name: name of the dirty bitmap
> > +#
> > +# @granularity: #optional the bitmap granularity, default is 64k for
> > +#               dirty-bitmap-add
> 
> Optional, but only affects dirty-bitmap-add.  You later document...
> 
> > +# @dirty-bitmap-remove
> > +#
> > +# Remove a dirty bitmap on the device
> > +#
> > +# Setting granularity has no effect here.
> 
> ...that it is silently ignored where it can't be used here, and again in
> 7/9 for both dirty-bitmap-disable and dirty-bitmap-enable.
> 
> I think it would be smarter to do:
> 
> { 'type': 'DirtyBitmap',
>   'data': { 'device': 'str', 'name': 'str' } }
> 
> {'command': 'dirty-bitmap-add',
>   'data': { 'map': 'DirtyBitmap', '*granularity': 'int' } }
> 
> Or:
> 
> { 'type': 'DirtyBitmap',
>   'data': { 'device': 'str', 'name': 'str' } }
> { 'type': 'DirtyBitmapGranularity',
>   'base': 'DirtyBitmap',
>   'data': { '*granularity': 'int' } }
> {'command': 'dirty-bitmap-add',
>   'data': 'DirtyBitmapGranularity' }
> 
> 
> which says that the 'DirtyBitmap' struct has no optional members, and
> instead of silently ignoring an optional member in 3 commands, we
> instead write the one command that takes the optional argument when we
> actually care about it.
> 

Yes, taking the later one since a type is needed for transaction support.
Thanks,

Fam
diff mbox

Patch

diff --git a/blockdev.c b/blockdev.c
index c3422a1..662c950 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1713,6 +1713,66 @@  void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
     }
 }
 
+void qmp_dirty_bitmap_add(const char *device, const char *name,
+                          bool has_granularity, int64_t granularity,
+                          Error **errp)
+{
+    BlockDriverState *bs;
+    BdrvDirtyBitmap *bitmap;
+
+    bs = bdrv_find(device);
+    if (!bs) {
+        error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+        return;
+    }
+
+    if (!name || name[0] == '\0') {
+        error_setg(errp, "Bitmap name cannot be empty");
+        return;
+    }
+    if (has_granularity) {
+        if (granularity & (granularity - 1)) {
+            error_setg(errp, "Granularity must be power of 2");
+            return;
+        }
+    } else {
+        granularity = 65536;
+    }
+
+    bitmap = bdrv_create_dirty_bitmap(bs, granularity, name, errp);
+    if (!bitmap) {
+        return;
+    }
+}
+
+void qmp_dirty_bitmap_remove(const char *device, const char *name,
+                             Error **errp)
+{
+    BlockDriverState *bs;
+    BdrvDirtyBitmap *bitmap;
+
+    bs = bdrv_find(device);
+    if (!bs) {
+        error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+        return;
+    }
+
+    if (!name || name[0] == '\0') {
+        error_setg(errp, "Bitmap name cannot be empty");
+        return;
+    }
+    bitmap = bdrv_find_dirty_bitmap(bs, name);
+    if (!bitmap) {
+        error_setg(errp, "Dirty bitmap not found: %s", name);
+        return;
+    }
+
+    /* Make it invisible to user in case the following
+     * bdrv_release_dirty_bitmap doens't free it because of refcnt */
+    bdrv_dirty_bitmap_make_anon(bs, bitmap);
+    bdrv_release_dirty_bitmap(bs, bitmap);
+}
+
 int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     const char *id = qdict_get_str(qdict, "id");
diff --git a/qapi-schema.json b/qapi-schema.json
index 506c242..56f16a9 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2209,6 +2209,51 @@ 
             '*on-target-error': 'BlockdevOnError' } }
 
 ##
+# @DirtyBitmap
+#
+# @device: name of device which the bitmap is tracking
+#
+# @name: name of the dirty bitmap
+#
+# @granularity: #optional the bitmap granularity, default is 64k for
+#               dirty-bitmap-add
+#
+# Since 2.1
+##
+{ 'type': 'DirtyBitmap',
+  'data': { 'device': 'str', 'name': 'str', '*granularity': 'int' } }
+
+##
+# @dirty-bitmap-add
+#
+# Create a dirty bitmap with a name on the device
+#
+# Returns: nothing on success
+#          If @device is not a valid block device, DeviceNotFound
+#          If @name is already taken, GenericError with an explaining message
+#
+# Since 2.1
+##
+{'command': 'dirty-bitmap-add',
+  'data': 'DirtyBitmap' }
+
+##
+# @dirty-bitmap-remove
+#
+# Remove a dirty bitmap on the device
+#
+# Setting granularity has no effect here.
+#
+# Returns: nothing on success
+#          If @device is not a valid block device, DeviceNotFound
+#          If @name is not found, GenericError with an explaining message
+#
+# Since 2.1
+##
+{'command': 'dirty-bitmap-remove',
+  'data': { 'device': 'str', 'name': 'str' } }
+
+##
 # @migrate_cancel
 #
 # Cancel the current executing migration process.
diff --git a/qmp-commands.hx b/qmp-commands.hx
index ed3ab92..b74f6ed 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1185,6 +1185,55 @@  Example:
 EQMP
 
     {
+        .name       = "dirty-bitmap-add",
+        .args_type  = "device:B,name:s,granularity:i?",
+        .mhandler.cmd_new = qmp_marshal_input_dirty_bitmap_add,
+    },
+    {
+        .name       = "dirty-bitmap-remove",
+        .args_type  = "device:B,name:s",
+        .mhandler.cmd_new = qmp_marshal_input_dirty_bitmap_remove,
+    },
+
+SQMP
+
+dirty-bitmap-add
+----------------
+
+Create a dirty bitmap with a name on the device, and start tracking the writes.
+
+Arguments:
+
+- "device": device name to create dirty bitmap (json-string)
+- "name": name of the new dirty bitmap (json-string)
+- "granularity": granularity to track writes with. (int)
+
+Example:
+
+-> { "execute": "dirty-bitmap-add", "arguments": { "device": "drive0",
+                                                   "name": "bitmap0" } }
+<- { "return": {} }
+
+dirty-bitmap-remove
+----------------
+
+Stop write tracking and remove the dirty bitmap that was created with
+dirty-bitmap-add.
+
+Arguments:
+
+- "device": device name to remove dirty bitmap (json-string)
+- "name": name of the dirty bitmap to remove (json-string)
+
+Example:
+
+-> { "execute": "dirty-bitmap-remove", "arguments": { "device": "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,