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;
};
}
/* 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)
{
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;
}
}
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");
.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.
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)) {
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);
}
/**