qapi: implement block-dirty-bitmap-remove transaction action

It is used to do transactional movement of the bitmap (which is
possible in conjunction with merge command). Transactional bitmap
movement is needed in scenarios with external snapshot, when we don't
want to leave copy of the bitmap in the base image.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Message-id: 20190708220502.12977-3-jsnow@redhat.com
[Edited "since" version to 4.2 --js]
Signed-off-by: John Snow <jsnow@redhat.com>
This commit is contained in:
John Snow 2019-07-29 16:35:54 -04:00
parent 2899f41eef
commit c4e4b0fa59
6 changed files with 85 additions and 17 deletions

View File

@ -5346,7 +5346,7 @@ static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs,
for (bm = bdrv_dirty_bitmap_next(bs, NULL); bm;
bm = bdrv_dirty_bitmap_next(bs, bm))
{
bdrv_dirty_bitmap_set_migration(bm, false);
bdrv_dirty_bitmap_skip_store(bm, false);
}
ret = refresh_total_sectors(bs, bs->total_sectors);

View File

@ -48,10 +48,9 @@ struct BdrvDirtyBitmap {
bool inconsistent; /* bitmap is persistent, but inconsistent.
It cannot be used at all in any way, except
a QMP user can remove it. */
bool migration; /* Bitmap is selected for migration, it should
not be stored on the next inactivation
(persistent flag doesn't matter until next
invalidation).*/
bool skip_store; /* We are either migrating or deleting this
* bitmap; it should not be stored on the next
* inactivation. */
QLIST_ENTRY(BdrvDirtyBitmap) list;
};
@ -762,16 +761,16 @@ void bdrv_dirty_bitmap_set_inconsistent(BdrvDirtyBitmap *bitmap)
}
/* Called with BQL taken. */
void bdrv_dirty_bitmap_set_migration(BdrvDirtyBitmap *bitmap, bool migration)
void bdrv_dirty_bitmap_skip_store(BdrvDirtyBitmap *bitmap, bool skip)
{
qemu_mutex_lock(bitmap->mutex);
bitmap->migration = migration;
bitmap->skip_store = skip;
qemu_mutex_unlock(bitmap->mutex);
}
bool bdrv_dirty_bitmap_get_persistence(BdrvDirtyBitmap *bitmap)
{
return bitmap->persistent && !bitmap->migration;
return bitmap->persistent && !bitmap->skip_store;
}
bool bdrv_dirty_bitmap_inconsistent(const BdrvDirtyBitmap *bitmap)
@ -783,7 +782,7 @@ bool bdrv_has_changed_persistent_bitmaps(BlockDriverState *bs)
{
BdrvDirtyBitmap *bm;
QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) {
if (bm->persistent && !bm->readonly && !bm->migration) {
if (bm->persistent && !bm->readonly && !bm->skip_store) {
return true;
}
}

View File

@ -2136,6 +2136,51 @@ static void block_dirty_bitmap_merge_prepare(BlkActionState *common,
errp);
}
static BdrvDirtyBitmap *do_block_dirty_bitmap_remove(
const char *node, const char *name, bool release,
BlockDriverState **bitmap_bs, Error **errp);
static void block_dirty_bitmap_remove_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.block_dirty_bitmap_remove.data;
state->bitmap = do_block_dirty_bitmap_remove(action->node, action->name,
false, &state->bs, errp);
if (state->bitmap) {
bdrv_dirty_bitmap_skip_store(state->bitmap, true);
bdrv_dirty_bitmap_set_busy(state->bitmap, true);
}
}
static void block_dirty_bitmap_remove_abort(BlkActionState *common)
{
BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
common, common);
if (state->bitmap) {
bdrv_dirty_bitmap_skip_store(state->bitmap, false);
bdrv_dirty_bitmap_set_busy(state->bitmap, false);
}
}
static void block_dirty_bitmap_remove_commit(BlkActionState *common)
{
BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
common, common);
bdrv_dirty_bitmap_set_busy(state->bitmap, false);
bdrv_release_dirty_bitmap(state->bs, state->bitmap);
}
static void abort_prepare(BlkActionState *common, Error **errp)
{
error_setg(errp, "Transaction aborted using Abort action");
@ -2213,6 +2258,12 @@ static const BlkActionOps actions[] = {
.commit = block_dirty_bitmap_free_backup,
.abort = block_dirty_bitmap_restore,
},
[TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_REMOVE] = {
.instance_size = sizeof(BlockDirtyBitmapState),
.prepare = block_dirty_bitmap_remove_prepare,
.commit = block_dirty_bitmap_remove_commit,
.abort = block_dirty_bitmap_remove_abort,
},
/* Where are transactions for MIRROR, COMMIT and STREAM?
* Although these blockjobs use transaction callbacks like the backup job,
* these jobs do not necessarily adhere to transaction semantics.
@ -2871,20 +2922,21 @@ void qmp_block_dirty_bitmap_add(const char *node, const char *name,
bdrv_dirty_bitmap_set_persistence(bitmap, persistent);
}
void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
Error **errp)
static BdrvDirtyBitmap *do_block_dirty_bitmap_remove(
const char *node, const char *name, bool release,
BlockDriverState **bitmap_bs, Error **errp)
{
BlockDriverState *bs;
BdrvDirtyBitmap *bitmap;
bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
if (!bitmap || !bs) {
return;
return NULL;
}
if (bdrv_dirty_bitmap_check(bitmap, BDRV_BITMAP_BUSY | BDRV_BITMAP_RO,
errp)) {
return;
return NULL;
}
if (bdrv_dirty_bitmap_get_persistence(bitmap)) {
@ -2894,13 +2946,28 @@ void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
aio_context_acquire(aio_context);
bdrv_remove_persistent_dirty_bitmap(bs, name, &local_err);
aio_context_release(aio_context);
if (local_err != NULL) {
error_propagate(errp, local_err);
return;
return NULL;
}
}
bdrv_release_dirty_bitmap(bs, bitmap);
if (release) {
bdrv_release_dirty_bitmap(bs, bitmap);
}
if (bitmap_bs) {
*bitmap_bs = bs;
}
return release ? NULL : bitmap;
}
void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
Error **errp)
{
do_block_dirty_bitmap_remove(node, name, true, NULL, errp);
}
/**

View File

@ -83,7 +83,7 @@ void bdrv_dirty_bitmap_set_inconsistent(BdrvDirtyBitmap *bitmap);
void bdrv_dirty_bitmap_set_busy(BdrvDirtyBitmap *bitmap, bool busy);
void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src,
HBitmap **backup, Error **errp);
void bdrv_dirty_bitmap_set_migration(BdrvDirtyBitmap *bitmap, bool migration);
void bdrv_dirty_bitmap_skip_store(BdrvDirtyBitmap *bitmap, bool skip);
bool bdrv_dirty_bitmap_get(BdrvDirtyBitmap *bitmap, int64_t offset);
/* Functions that require manual locking. */

View File

@ -326,7 +326,7 @@ static int init_dirty_bitmap_migration(void)
/* unset migration flags here, to not roll back it */
QSIMPLEQ_FOREACH(dbms, &dirty_bitmap_mig_state.dbms_list, entry) {
bdrv_dirty_bitmap_set_migration(dbms->bitmap, true);
bdrv_dirty_bitmap_skip_store(dbms->bitmap, true);
}
if (QSIMPLEQ_EMPTY(&dirty_bitmap_mig_state.dbms_list)) {

View File

@ -45,6 +45,7 @@
#
# - @abort: since 1.6
# - @block-dirty-bitmap-add: since 2.5
# - @block-dirty-bitmap-remove: since 4.2
# - @block-dirty-bitmap-clear: since 2.5
# - @block-dirty-bitmap-enable: since 4.0
# - @block-dirty-bitmap-disable: since 4.0
@ -61,6 +62,7 @@
'data': {
'abort': 'Abort',
'block-dirty-bitmap-add': 'BlockDirtyBitmapAdd',
'block-dirty-bitmap-remove': 'BlockDirtyBitmap',
'block-dirty-bitmap-clear': 'BlockDirtyBitmap',
'block-dirty-bitmap-enable': 'BlockDirtyBitmap',
'block-dirty-bitmap-disable': 'BlockDirtyBitmap',