mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-08-05 16:33:50 +00:00
qemu: Rewrite bitmap handling for block copy
Reuse qemuBlockGetBitmapMergeActions which allows the removal of the ad-hoc implementation of bitmap merging for block copy. Signed-off-by: Peter Krempa <pkrempa@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com>
This commit is contained in:
parent
057e4bc591
commit
7bfff40fdf
@ -3068,38 +3068,6 @@ qemuBlockBitmapChainIsValid(virStorageSourcePtr src,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct qemuBlockBitmapsHandleBlockcopyConcatData {
|
|
||||||
virHashTablePtr bitmaps_merge;
|
|
||||||
virJSONValuePtr actions;
|
|
||||||
const char *mirrornodeformat;
|
|
||||||
bool has_bitmaps;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
qemuBlockBitmapsHandleBlockcopyConcatActions(void *payload,
|
|
||||||
const void *name,
|
|
||||||
void *opaque)
|
|
||||||
{
|
|
||||||
struct qemuBlockBitmapsHandleBlockcopyConcatData *data = opaque;
|
|
||||||
virJSONValuePtr createactions = payload;
|
|
||||||
const char *bitmapname = name;
|
|
||||||
g_autoptr(virJSONValue) mergebitmaps = virHashSteal(data->bitmaps_merge, bitmapname);
|
|
||||||
|
|
||||||
data->has_bitmaps = true;
|
|
||||||
|
|
||||||
virJSONValueArrayConcat(data->actions, createactions);
|
|
||||||
|
|
||||||
if (qemuMonitorTransactionBitmapMerge(data->actions,
|
|
||||||
data->mirrornodeformat,
|
|
||||||
bitmapname,
|
|
||||||
&mergebitmaps) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qemuBlockBitmapsHandleBlockcopy:
|
* qemuBlockBitmapsHandleBlockcopy:
|
||||||
* @src: disk source
|
* @src: disk source
|
||||||
@ -3122,86 +3090,15 @@ qemuBlockBitmapsHandleBlockcopy(virStorageSourcePtr src,
|
|||||||
bool shallow,
|
bool shallow,
|
||||||
virJSONValuePtr *actions)
|
virJSONValuePtr *actions)
|
||||||
{
|
{
|
||||||
g_autoptr(virHashTable) bitmaps = virHashNew(virJSONValueHashFree);
|
virStorageSourcePtr base = NULL;
|
||||||
g_autoptr(virHashTable) bitmaps_merge = virHashNew(virJSONValueHashFree);
|
|
||||||
g_autoptr(virHashTable) bitmaps_skip = virHashNew(NULL);
|
|
||||||
g_autoptr(virJSONValue) tmpactions = virJSONValueNewArray();
|
|
||||||
qemuBlockNamedNodeDataPtr entry;
|
|
||||||
virStorageSourcePtr n;
|
|
||||||
size_t i;
|
|
||||||
struct qemuBlockBitmapsHandleBlockcopyConcatData data = { .bitmaps_merge = bitmaps_merge,
|
|
||||||
.actions = tmpactions,
|
|
||||||
.mirrornodeformat = mirror->nodeformat,
|
|
||||||
.has_bitmaps = false, };
|
|
||||||
|
|
||||||
for (n = src; n; n = n->backingStore) {
|
if (shallow)
|
||||||
if (!(entry = virHashLookup(blockNamedNodeData, n->nodeformat)))
|
base = src->backingStore;
|
||||||
continue;
|
|
||||||
|
|
||||||
for (i = 0; i < entry->nbitmaps; i++) {
|
if (qemuBlockGetBitmapMergeActions(src, base, mirror, NULL, NULL, mirror, actions,
|
||||||
qemuBlockNamedNodeDataBitmapPtr bitmap = entry->bitmaps[i];
|
blockNamedNodeData) < 0)
|
||||||
virJSONValuePtr bitmap_merge;
|
|
||||||
|
|
||||||
if (virHashHasEntry(bitmaps_skip, bitmap->name))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!(bitmap_merge = virHashLookup(bitmaps_merge, bitmap->name))) {
|
|
||||||
g_autoptr(virJSONValue) tmp = NULL;
|
|
||||||
bool disabled = !bitmap->recording;
|
|
||||||
|
|
||||||
/* disable any non top-layer bitmaps */
|
|
||||||
if (n != src)
|
|
||||||
disabled = true;
|
|
||||||
|
|
||||||
if (!bitmap->persistent ||
|
|
||||||
!(qemuBlockBitmapChainIsValid(n, bitmap->name,
|
|
||||||
blockNamedNodeData))) {
|
|
||||||
ignore_value(virHashAddEntry(bitmaps_skip, bitmap->name, NULL));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* prepare the data for adding the bitmap to the mirror */
|
|
||||||
tmp = virJSONValueNewArray();
|
|
||||||
|
|
||||||
if (qemuMonitorTransactionBitmapAdd(tmp,
|
|
||||||
mirror->nodeformat,
|
|
||||||
bitmap->name,
|
|
||||||
true,
|
|
||||||
disabled,
|
|
||||||
bitmap->granularity) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (virHashAddEntry(bitmaps, bitmap->name, tmp) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
tmp = NULL;
|
|
||||||
|
|
||||||
/* prepare array for merging all the bitmaps from the original chain */
|
|
||||||
tmp = virJSONValueNewArray();
|
|
||||||
|
|
||||||
if (virHashAddEntry(bitmaps_merge, bitmap->name, tmp) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
bitmap_merge = g_steal_pointer(&tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (qemuMonitorTransactionBitmapMergeSourceAddBitmap(bitmap_merge,
|
|
||||||
n->nodeformat,
|
|
||||||
bitmap->name) < 0)
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shallow)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (virHashForEach(bitmaps, qemuBlockBitmapsHandleBlockcopyConcatActions,
|
|
||||||
&data) < 0)
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (data.has_bitmaps)
|
|
||||||
*actions = g_steal_pointer(&tmpactions);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1282,6 +1282,43 @@ qemuBlockJobProcessEventCompletedActiveCommit(virQEMUDriverPtr driver,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
qemuBlockJobProcessEventCompletedCopyBitmaps(virDomainObjPtr vm,
|
||||||
|
qemuBlockJobDataPtr job,
|
||||||
|
qemuDomainAsyncJob asyncJob)
|
||||||
|
{
|
||||||
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||||
|
g_autoptr(virHashTable) blockNamedNodeData = NULL;
|
||||||
|
g_autoptr(virJSONValue) actions = NULL;
|
||||||
|
bool shallow = job->jobflags & VIR_DOMAIN_BLOCK_COPY_SHALLOW;
|
||||||
|
|
||||||
|
if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV_REOPEN))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!(blockNamedNodeData = qemuBlockGetNamedNodeData(vm, asyncJob)))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (qemuBlockBitmapsHandleBlockcopy(job->disk->src,
|
||||||
|
job->disk->mirror,
|
||||||
|
blockNamedNodeData,
|
||||||
|
shallow,
|
||||||
|
&actions) < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!actions)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (qemuDomainObjEnterMonitorAsync(priv->driver, vm, asyncJob) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
qemuMonitorTransaction(priv->mon, &actions);
|
||||||
|
|
||||||
|
if (qemuDomainObjExitMonitor(priv->driver, vm) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
qemuBlockJobProcessEventConcludedCopyPivot(virQEMUDriverPtr driver,
|
qemuBlockJobProcessEventConcludedCopyPivot(virQEMUDriverPtr driver,
|
||||||
virDomainObjPtr vm,
|
virDomainObjPtr vm,
|
||||||
@ -1296,6 +1333,8 @@ qemuBlockJobProcessEventConcludedCopyPivot(virQEMUDriverPtr driver,
|
|||||||
!job->disk->mirror)
|
!job->disk->mirror)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
qemuBlockJobProcessEventCompletedCopyBitmaps(vm, job, asyncJob);
|
||||||
|
|
||||||
/* for shallow copy without reusing external image the user can either not
|
/* for shallow copy without reusing external image the user can either not
|
||||||
* specify the backing chain in which case libvirt will open and use the
|
* specify the backing chain in which case libvirt will open and use the
|
||||||
* chain the user provided or not specify a chain in which case we'll
|
* chain the user provided or not specify a chain in which case we'll
|
||||||
@ -1329,6 +1368,7 @@ qemuBlockJobProcessEventConcludedCopyAbort(virQEMUDriverPtr driver,
|
|||||||
!job->disk->mirror)
|
!job->disk->mirror)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* activeWrite bitmap is removed automatically here */
|
||||||
qemuBlockJobEventProcessConcludedRemoveChain(driver, vm, asyncJob, job->disk->mirror);
|
qemuBlockJobEventProcessConcludedRemoveChain(driver, vm, asyncJob, job->disk->mirror);
|
||||||
virObjectUnref(job->disk->mirror);
|
virObjectUnref(job->disk->mirror);
|
||||||
job->disk->mirror = NULL;
|
job->disk->mirror = NULL;
|
||||||
|
@ -17381,14 +17381,15 @@ qemuDomainBlockPivot(virQEMUDriverPtr driver,
|
|||||||
if (blockdev && !job->jobflagsmissing) {
|
if (blockdev && !job->jobflagsmissing) {
|
||||||
bool shallow = job->jobflags & VIR_DOMAIN_BLOCK_COPY_SHALLOW;
|
bool shallow = job->jobflags & VIR_DOMAIN_BLOCK_COPY_SHALLOW;
|
||||||
bool reuse = job->jobflags & VIR_DOMAIN_BLOCK_COPY_REUSE_EXT;
|
bool reuse = job->jobflags & VIR_DOMAIN_BLOCK_COPY_REUSE_EXT;
|
||||||
g_autoptr(virHashTable) blockNamedNodeData = NULL;
|
|
||||||
|
|
||||||
if (!(blockNamedNodeData = qemuBlockGetNamedNodeData(vm, QEMU_ASYNC_JOB_NONE)))
|
actions = virJSONValueNewArray();
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (qemuBlockBitmapsHandleBlockcopy(disk->src, disk->mirror,
|
if (qemuMonitorTransactionBitmapAdd(actions,
|
||||||
blockNamedNodeData,
|
disk->mirror->nodeformat,
|
||||||
shallow, &actions) < 0)
|
"libvirt-tmp-activewrite",
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
0) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/* Open and install the backing chain of 'mirror' late if we can use
|
/* Open and install the backing chain of 'mirror' late if we can use
|
||||||
|
@ -881,6 +881,7 @@ testQemuBlockBitmapBlockcopy(const void *opaque)
|
|||||||
g_autoptr(virJSONValue) nodedatajson = NULL;
|
g_autoptr(virJSONValue) nodedatajson = NULL;
|
||||||
g_autoptr(virHashTable) nodedata = NULL;
|
g_autoptr(virHashTable) nodedata = NULL;
|
||||||
g_autoptr(virStorageSource) fakemirror = virStorageSourceNew();
|
g_autoptr(virStorageSource) fakemirror = virStorageSourceNew();
|
||||||
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
||||||
|
|
||||||
if (!fakemirror)
|
if (!fakemirror)
|
||||||
return -1;
|
return -1;
|
||||||
@ -903,10 +904,13 @@ testQemuBlockBitmapBlockcopy(const void *opaque)
|
|||||||
data->shallow, &actions) < 0)
|
data->shallow, &actions) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
|
||||||
if (actions &&
|
if (actions &&
|
||||||
!(actual = virJSONValueToString(actions, true)))
|
virJSONValueToBuffer(actions, &buf, true) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
actual = virBufferContentAndReset(&buf);
|
||||||
|
|
||||||
return virTestCompareToFile(actual, expectpath);
|
return virTestCompareToFile(actual, expectpath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user