|
@@ -2113,6 +2113,35 @@ static void block_dirty_bitmap_disable_abort(BlkActionState *common)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static void block_dirty_bitmap_merge_prepare(BlkActionState *common,
|
|
|
+ Error **errp)
|
|
|
+{
|
|
|
+ BlockDirtyBitmapMerge *action;
|
|
|
+ BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
|
|
|
+ common, common);
|
|
|
+ BdrvDirtyBitmap *merge_source;
|
|
|
+
|
|
|
+ if (action_check_completion_mode(common, errp) < 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ action = common->action->u.x_block_dirty_bitmap_merge.data;
|
|
|
+ state->bitmap = block_dirty_bitmap_lookup(action->node,
|
|
|
+ action->dst_name,
|
|
|
+ &state->bs,
|
|
|
+ errp);
|
|
|
+ if (!state->bitmap) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ merge_source = bdrv_find_dirty_bitmap(state->bs, action->src_name);
|
|
|
+ if (!merge_source) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ bdrv_merge_dirty_bitmap(state->bitmap, merge_source, &state->backup, errp);
|
|
|
+}
|
|
|
+
|
|
|
static void abort_prepare(BlkActionState *common, Error **errp)
|
|
|
{
|
|
|
error_setg(errp, "Transaction aborted using Abort action");
|
|
@@ -2184,6 +2213,12 @@ static const BlkActionOps actions[] = {
|
|
|
.prepare = block_dirty_bitmap_disable_prepare,
|
|
|
.abort = block_dirty_bitmap_disable_abort,
|
|
|
},
|
|
|
+ [TRANSACTION_ACTION_KIND_X_BLOCK_DIRTY_BITMAP_MERGE] = {
|
|
|
+ .instance_size = sizeof(BlockDirtyBitmapState),
|
|
|
+ .prepare = block_dirty_bitmap_merge_prepare,
|
|
|
+ .commit = block_dirty_bitmap_free_backup,
|
|
|
+ .abort = block_dirty_bitmap_restore,
|
|
|
+ },
|
|
|
/* 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.
|