qmp: add block-dirty-bitmap-clear

Add bdrv_clear_dirty_bitmap and a matching QMP command,
qmp_block_dirty_bitmap_clear that enables a user to reset
the bitmap attached to a drive.

This allows us to reset a bitmap in the event of a full
drive backup.

Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-id: 1429314609-29776-12-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
John Snow 2015-04-17 19:49:59 -04:00 committed by Kevin Wolf
parent d58d845397
commit e74e6b78e6
5 changed files with 86 additions and 0 deletions

View File

@ -63,6 +63,7 @@
struct BdrvDirtyBitmap { struct BdrvDirtyBitmap {
HBitmap *bitmap; HBitmap *bitmap;
BdrvDirtyBitmap *successor; BdrvDirtyBitmap *successor;
int64_t size;
char *name; char *name;
bool disabled; bool disabled;
QLIST_ENTRY(BdrvDirtyBitmap) list; QLIST_ENTRY(BdrvDirtyBitmap) list;
@ -5557,6 +5558,7 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
} }
bitmap = g_new0(BdrvDirtyBitmap, 1); bitmap = g_new0(BdrvDirtyBitmap, 1);
bitmap->bitmap = hbitmap_alloc(bitmap_size, ctz32(sector_granularity)); bitmap->bitmap = hbitmap_alloc(bitmap_size, ctz32(sector_granularity));
bitmap->size = bitmap_size;
bitmap->name = g_strdup(name); bitmap->name = g_strdup(name);
bitmap->disabled = false; bitmap->disabled = false;
QLIST_INSERT_HEAD(&bs->dirty_bitmaps, bitmap, list); QLIST_INSERT_HEAD(&bs->dirty_bitmaps, bitmap, list);
@ -5759,6 +5761,12 @@ void bdrv_reset_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors); hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
} }
void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap)
{
assert(bdrv_dirty_bitmap_enabled(bitmap));
hbitmap_reset(bitmap->bitmap, 0, bitmap->size);
}
static void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector, static void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
int nr_sectors) int nr_sectors)
{ {

View File

@ -2079,6 +2079,40 @@ void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
aio_context_release(aio_context); aio_context_release(aio_context);
} }
/**
* Completely clear a bitmap, for the purposes of synchronizing a bitmap
* immediately after a full backup operation.
*/
void qmp_block_dirty_bitmap_clear(const char *node, const char *name,
Error **errp)
{
AioContext *aio_context;
BdrvDirtyBitmap *bitmap;
BlockDriverState *bs;
bitmap = block_dirty_bitmap_lookup(node, name, &bs, &aio_context, errp);
if (!bitmap || !bs) {
return;
}
if (bdrv_dirty_bitmap_frozen(bitmap)) {
error_setg(errp,
"Bitmap '%s' is currently frozen and cannot be modified",
name);
goto out;
} else if (!bdrv_dirty_bitmap_enabled(bitmap)) {
error_setg(errp,
"Bitmap '%s' is currently disabled and cannot be cleared",
name);
goto out;
}
bdrv_clear_dirty_bitmap(bitmap);
out:
aio_context_release(aio_context);
}
int hmp_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data) int hmp_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
{ {
const char *id = qdict_get_str(qdict, "id"); const char *id = qdict_get_str(qdict, "id");

View File

@ -479,6 +479,7 @@ void bdrv_set_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
int64_t cur_sector, int nr_sectors); int64_t cur_sector, int nr_sectors);
void bdrv_reset_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, void bdrv_reset_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
int64_t cur_sector, int nr_sectors); int64_t cur_sector, int nr_sectors);
void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap);
void bdrv_dirty_iter_init(BlockDriverState *bs, void bdrv_dirty_iter_init(BlockDriverState *bs,
BdrvDirtyBitmap *bitmap, struct HBitmapIter *hbi); BdrvDirtyBitmap *bitmap, struct HBitmapIter *hbi);
void bdrv_set_dirty_iter(struct HBitmapIter *hbi, int64_t offset); void bdrv_set_dirty_iter(struct HBitmapIter *hbi, int64_t offset);

View File

@ -1021,6 +1021,20 @@
{ 'command': 'block-dirty-bitmap-remove', { 'command': 'block-dirty-bitmap-remove',
'data': 'BlockDirtyBitmap' } 'data': 'BlockDirtyBitmap' }
##
# @block-dirty-bitmap-clear
#
# Clear (reset) a dirty bitmap on the device
#
# Returns: nothing on success
# If @node is not a valid block device, DeviceNotFound
# If @name is not found, GenericError with an explanation
#
# Since 2.4
##
{ 'command': 'block-dirty-bitmap-clear',
'data': 'BlockDirtyBitmap' }
## ##
# @block_set_io_throttle: # @block_set_io_throttle:
# #

View File

@ -1361,6 +1361,35 @@ Example:
"name": "bitmap0" } } "name": "bitmap0" } }
<- { "return": {} } <- { "return": {} }
EQMP
{
.name = "block-dirty-bitmap-clear",
.args_type = "node:B,name:s",
.mhandler.cmd_new = qmp_marshal_input_block_dirty_bitmap_clear,
},
SQMP
block-dirty-bitmap-clear
------------------------
Since 2.4
Reset the dirty bitmap associated with a node so that an incremental backup
from this point in time forward will only backup clusters modified after this
clear operation.
Arguments:
- "node": 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-clear", "arguments": { "node": "drive0",
"name": "bitmap0" } }
<- { "return": {} }
EQMP EQMP
{ {