From: Fam Zheng <f...@redhat.com> This adds three qmp commands to transactions.
Users can stop a dirty bitmap, start backup of it, and start another dirty bitmap atomically, so that the dirty bitmap is tracked incrementally and we don't miss any write. Signed-off-by: Fam Zheng <f...@redhat.com> Signed-off-by: John Snow <js...@redhat.com> --- blockdev.c | 147 +++++++++++++++++++++++++++++++++++++++++++------------ qapi-schema.json | 5 +- 2 files changed, 119 insertions(+), 33 deletions(-) diff --git a/blockdev.c b/blockdev.c index adf841a..b98249b 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1497,6 +1497,106 @@ static void drive_backup_abort(BlkTransactionState *common) } } +static void block_dirty_bitmap_add_prepare(BlkTransactionState *common, + Error **errp) +{ + BlockDirtyBitmapAdd *action; + + action = common->action->block_dirty_bitmap_add; + qmp_block_dirty_bitmap_add(action->device, action->name, + action->has_granularity, action->granularity, + errp); +} + +static void block_dirty_bitmap_add_abort(BlkTransactionState *common) +{ + BlockDirtyBitmapAdd *action; + BdrvDirtyBitmap *bm; + BlockDriverState *bs; + + action = common->action->block_dirty_bitmap_add; + bs = bdrv_lookup_bs(action->device, NULL, NULL); + if (bs) { + bm = bdrv_find_dirty_bitmap(bs, action->name); + if (bm) { + bdrv_release_dirty_bitmap(bs, bm); + } + } +} + +typedef struct BlockDirtyBitmapState { + BlkTransactionState common; + BdrvDirtyBitmap *bitmap; +} BlockDirtyBitmapState; + +static BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *device, + const char *name, + Error **errp) +{ + BlockDriverState *bs; + BdrvDirtyBitmap *bitmap; + Error *local_err = NULL; + + if (!device) { + error_setg(errp, "Device cannot be NULL"); + return NULL; + } + if (!name) { + error_setg(errp, "Bitmap name cannot be NULL"); + return NULL; + } + + bs = bdrv_lookup_bs(device, NULL, &local_err); + if (!bs) { + error_propagate(errp, local_err); + return NULL; + } + + bitmap = bdrv_find_dirty_bitmap(bs, name); + if (!bitmap) { + error_setg(errp, "Dirty bitmap not found: %s", name); + return NULL; + } + + return bitmap; +} + +/** + * Enable and Disable re-uses the same preparation. + */ +static void block_dirty_bitmap_en_toggle_prepare(BlkTransactionState *common, + Error **errp) +{ + BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState, + common, common); + BlockDirtyBitmap *action; + Error *local_err = NULL; + + action = common->action->block_dirty_bitmap_enable; + + state->bitmap = block_dirty_bitmap_lookup(action->device, + action->name, + &local_err); + if (!state->bitmap) { + error_propagate(errp, local_err); + return; + } +} + +static void block_dirty_bitmap_enable_commit(BlkTransactionState *common) +{ + BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState, + common, common); + bdrv_enable_dirty_bitmap(NULL, state->bitmap); +} + +static void block_dirty_bitmap_disable_commit(BlkTransactionState *common) +{ + BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState, + common, common); + bdrv_disable_dirty_bitmap(NULL, state->bitmap); +} + static void abort_prepare(BlkTransactionState *common, Error **errp) { error_setg(errp, "Transaction aborted using Abort action"); @@ -1529,6 +1629,21 @@ static const BdrvActionOps actions[] = { .prepare = internal_snapshot_prepare, .abort = internal_snapshot_abort, }, + [TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_ADD] = { + .instance_size = sizeof(BlkTransactionState), + .prepare = block_dirty_bitmap_add_prepare, + .abort = block_dirty_bitmap_add_abort, + }, + [TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_ENABLE] = { + .instance_size = sizeof(BlockDirtyBitmapState), + .prepare = block_dirty_bitmap_en_toggle_prepare, + .commit = block_dirty_bitmap_enable_commit, + }, + [TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_DISABLE] = { + .instance_size = sizeof(BlockDirtyBitmapState), + .prepare = block_dirty_bitmap_en_toggle_prepare, + .commit = block_dirty_bitmap_disable_commit, + }, }; /* @@ -1875,38 +1990,6 @@ void qmp_block_dirty_bitmap_remove(const char *device, const char *name, bdrv_release_dirty_bitmap(bs, bitmap); } -static BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *device, - const char *name, - Error **errp) -{ - BlockDriverState *bs; - BdrvDirtyBitmap *bitmap; - Error *local_err = NULL; - - if (!device) { - error_setg(errp, "Device cannot be NULL"); - return NULL; - } - if (!name) { - error_setg(errp, "Bitmap name cannot be NULL"); - return NULL; - } - - bs = bdrv_lookup_bs(device, NULL, &local_err); - if (!bs) { - error_propagate(errp, local_err); - return NULL; - } - - bitmap = bdrv_find_dirty_bitmap(bs, name); - if (!bitmap) { - error_setg(errp, "Dirty bitmap not found: %s", name); - return NULL; - } - - return bitmap; -} - void qmp_block_dirty_bitmap_enable(const char *device, const char *name, Error **errp) { diff --git a/qapi-schema.json b/qapi-schema.json index d0926d9..958be35 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -1260,7 +1260,10 @@ 'blockdev-snapshot-sync': 'BlockdevSnapshot', 'drive-backup': 'DriveBackup', 'abort': 'Abort', - 'blockdev-snapshot-internal-sync': 'BlockdevSnapshotInternal' + 'blockdev-snapshot-internal-sync': 'BlockdevSnapshotInternal', + 'block-dirty-bitmap-add': 'BlockDirtyBitmapAdd', + 'block-dirty-bitmap-enable': 'BlockDirtyBitmap', + 'block-dirty-bitmap-disable': 'BlockDirtyBitmap' } } ## -- 1.9.3