diff options
Diffstat (limited to 'blockdev.c')
-rw-r--r-- | blockdev.c | 164 |
1 files changed, 162 insertions, 2 deletions
diff --git a/blockdev.c b/blockdev.c index 8de95be8f4..4862323012 100644 --- a/blockdev.c +++ b/blockdev.c @@ -2052,6 +2052,7 @@ typedef struct BlockDirtyBitmapState { BlockDriverState *bs; HBitmap *backup; bool prepared; + bool was_enabled; } BlockDirtyBitmapState; static void block_dirty_bitmap_add_prepare(BlkActionState *common, @@ -2072,6 +2073,7 @@ static void block_dirty_bitmap_add_prepare(BlkActionState *common, action->has_granularity, action->granularity, action->has_persistent, action->persistent, action->has_autoload, action->autoload, + action->has_x_disabled, action->x_disabled, &local_err); if (!local_err) { @@ -2151,6 +2153,74 @@ static void block_dirty_bitmap_clear_commit(BlkActionState *common) hbitmap_free(state->backup); } +static void block_dirty_bitmap_enable_prepare(BlkActionState *common, + Error **errp) +{ + BlockDirtyBitmap *action; + BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState, + common, common); + + if (action_check_completion_mode(common, errp) < 0) { + return; + } + + action = common->action->u.x_block_dirty_bitmap_enable.data; + state->bitmap = block_dirty_bitmap_lookup(action->node, + action->name, + NULL, + errp); + if (!state->bitmap) { + return; + } + + state->was_enabled = bdrv_dirty_bitmap_enabled(state->bitmap); + bdrv_enable_dirty_bitmap(state->bitmap); +} + +static void block_dirty_bitmap_enable_abort(BlkActionState *common) +{ + BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState, + common, common); + + if (!state->was_enabled) { + bdrv_disable_dirty_bitmap(state->bitmap); + } +} + +static void block_dirty_bitmap_disable_prepare(BlkActionState *common, + Error **errp) +{ + BlockDirtyBitmap *action; + BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState, + common, common); + + if (action_check_completion_mode(common, errp) < 0) { + return; + } + + action = common->action->u.x_block_dirty_bitmap_disable.data; + state->bitmap = block_dirty_bitmap_lookup(action->node, + action->name, + NULL, + errp); + if (!state->bitmap) { + return; + } + + state->was_enabled = bdrv_dirty_bitmap_enabled(state->bitmap); + bdrv_disable_dirty_bitmap(state->bitmap); +} + +static void block_dirty_bitmap_disable_abort(BlkActionState *common) +{ + BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState, + common, common); + + if (state->was_enabled) { + bdrv_enable_dirty_bitmap(state->bitmap); + } +} + static void abort_prepare(BlkActionState *common, Error **errp) { error_setg(errp, "Transaction aborted using Abort action"); @@ -2211,7 +2281,17 @@ static const BlkActionOps actions[] = { .prepare = block_dirty_bitmap_clear_prepare, .commit = block_dirty_bitmap_clear_commit, .abort = block_dirty_bitmap_clear_abort, - } + }, + [TRANSACTION_ACTION_KIND_X_BLOCK_DIRTY_BITMAP_ENABLE] = { + .instance_size = sizeof(BlockDirtyBitmapState), + .prepare = block_dirty_bitmap_enable_prepare, + .abort = block_dirty_bitmap_enable_abort, + }, + [TRANSACTION_ACTION_KIND_X_BLOCK_DIRTY_BITMAP_DISABLE] = { + .instance_size = sizeof(BlockDirtyBitmapState), + .prepare = block_dirty_bitmap_disable_prepare, + .abort = block_dirty_bitmap_disable_abort, + } }; /** @@ -2801,6 +2881,7 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name, bool has_granularity, uint32_t granularity, bool has_persistent, bool persistent, bool has_autoload, bool autoload, + bool has_disabled, bool disabled, Error **errp) { BlockDriverState *bs; @@ -2835,6 +2916,10 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name, warn_report("Autoload option is deprecated and its value is ignored"); } + if (!has_disabled) { + disabled = false; + } + if (persistent && !bdrv_can_store_new_dirty_bitmap(bs, name, granularity, errp)) { @@ -2846,6 +2931,10 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name, return; } + if (disabled) { + bdrv_disable_dirty_bitmap(bitmap); + } + bdrv_dirty_bitmap_set_persistance(bitmap, persistent); } @@ -2881,7 +2970,6 @@ void qmp_block_dirty_bitmap_remove(const char *node, const char *name, } } - bdrv_dirty_bitmap_make_anon(bitmap); bdrv_release_dirty_bitmap(bs, bitmap); } @@ -2923,6 +3011,78 @@ void qmp_block_dirty_bitmap_clear(const char *node, const char *name, bdrv_clear_dirty_bitmap(bitmap, NULL); } +void qmp_x_block_dirty_bitmap_enable(const char *node, const char *name, + Error **errp) +{ + BlockDriverState *bs; + BdrvDirtyBitmap *bitmap; + + bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp); + if (!bitmap) { + return; + } + + if (bdrv_dirty_bitmap_frozen(bitmap)) { + error_setg(errp, + "Bitmap '%s' is currently frozen and cannot be enabled", + name); + return; + } + + bdrv_enable_dirty_bitmap(bitmap); +} + +void qmp_x_block_dirty_bitmap_disable(const char *node, const char *name, + Error **errp) +{ + BlockDriverState *bs; + BdrvDirtyBitmap *bitmap; + + bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp); + if (!bitmap) { + return; + } + + if (bdrv_dirty_bitmap_frozen(bitmap)) { + error_setg(errp, + "Bitmap '%s' is currently frozen and cannot be disabled", + name); + return; + } + + bdrv_disable_dirty_bitmap(bitmap); +} + +void qmp_x_block_dirty_bitmap_merge(const char *node, const char *dst_name, + const char *src_name, Error **errp) +{ + BlockDriverState *bs; + BdrvDirtyBitmap *dst, *src; + + dst = block_dirty_bitmap_lookup(node, dst_name, &bs, errp); + if (!dst) { + return; + } + + if (bdrv_dirty_bitmap_frozen(dst)) { + error_setg(errp, "Bitmap '%s' is frozen and cannot be modified", + dst_name); + return; + } else if (bdrv_dirty_bitmap_readonly(dst)) { + error_setg(errp, "Bitmap '%s' is readonly and cannot be modified", + dst_name); + return; + } + + src = bdrv_find_dirty_bitmap(bs, src_name); + if (!src) { + error_setg(errp, "Dirty bitmap '%s' not found", src_name); + return; + } + + bdrv_merge_dirty_bitmap(dst, src, errp); +} + BlockDirtyBitmapSha256 *qmp_x_debug_block_dirty_bitmap_sha256(const char *node, const char *name, Error **errp) |