mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-02 01:45:17 +00:00
qemu: block: Add universal helper for merging dirty bitmaps for all scenarios
Add a function which allows merging bitmaps according to the new semantics and will allow replacing all the specific ad-hoc functions currently in use for 'backup', 'block commit', 'block copy' and will also be usable in the future for 'block pull' and non-shared storage migration. The semantics are a bit quirky for the 'backup' case but these quirks are documented and will prevent us from having two slightly different algorithms. Signed-off-by: Peter Krempa <pkrempa@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com>
This commit is contained in:
parent
2c5a3da365
commit
4fa8654ece
@ -2847,6 +2847,178 @@ qemuBlockGetNamedNodeData(virDomainObjPtr vm,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* qemuBlockGetBitmapMergeActionsGetBitmaps:
|
||||
*
|
||||
* Collect a list of bitmaps which need to be handled in
|
||||
* qemuBlockGetBitmapMergeActions. The list contains only valid bitmaps in the
|
||||
* sub-chain which is being processed.
|
||||
*
|
||||
* Note that the returned GSList contains bitmap names string pointers borrowed
|
||||
* from @blockNamedNodeData so they must not be freed.
|
||||
*/
|
||||
static GSList *
|
||||
qemuBlockGetBitmapMergeActionsGetBitmaps(virStorageSourcePtr topsrc,
|
||||
const char *bitmapname,
|
||||
virHashTablePtr blockNamedNodeData)
|
||||
{
|
||||
g_autoptr(GSList) ret = NULL;
|
||||
qemuBlockNamedNodeDataPtr entry;
|
||||
size_t i;
|
||||
|
||||
/* for now it doesn't make sense to consider bitmaps which are not present
|
||||
* in @topsrc as we can't recreate a bitmap for a layer if it's missing */
|
||||
|
||||
if (!(entry = virHashLookup(blockNamedNodeData, topsrc->nodeformat)))
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < entry->nbitmaps; i++) {
|
||||
qemuBlockNamedNodeDataBitmapPtr bitmap = entry->bitmaps[i];
|
||||
|
||||
if (bitmapname &&
|
||||
STRNEQ(bitmapname, bitmap->name))
|
||||
continue;
|
||||
|
||||
if (!qemuBlockBitmapChainIsValid(topsrc, bitmap->name, blockNamedNodeData))
|
||||
continue;
|
||||
|
||||
ret = g_slist_prepend(ret, bitmap->name);
|
||||
}
|
||||
|
||||
return g_steal_pointer(&ret);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* qemuBlockGetBitmapMergeActions:
|
||||
* @topsrc: top of the chain to merge bitmaps in
|
||||
* @basesrc: bottom of the chain to merge bitmaps in (NULL for full chain)
|
||||
* @target: destination storage source of the merge (may be part of original chain)
|
||||
* @bitmapname: name of bitmap to perform the merge (NULL for all bitmaps)
|
||||
* @dstbitmapname: name of destination bitmap of the merge (see below for caveats)
|
||||
* @writebitmapsrc: storage source corresponding to the node containing the write temporary bitmap
|
||||
* @actions: returns actions for a 'transaction' QMP command for executing the merge
|
||||
* @blockNamedNodeData: hash table filled with qemuBlockNamedNodeData
|
||||
*
|
||||
* Calculate handling of dirty block bitmaps between @topsrc and @basesrc. If
|
||||
* @basesrc is NULL the end of the chain is considered. @target is the destination
|
||||
* storage source definition of the merge and may or may not be part of the
|
||||
* merged chain.
|
||||
*
|
||||
* Specifically the merging algorithm ensures that each considered bitmap is
|
||||
* merged with the appropriate bitmaps so that it properly describes
|
||||
* the state of dirty blocks when looked at from @topsrc based on the depth
|
||||
* of the backing chain where the bitmap is placed.
|
||||
*
|
||||
* If @bitmapname is non-NULL only bitmaps with that name are handled, otherwise
|
||||
* all bitmaps are considered.
|
||||
*
|
||||
* If @dstbitmap is non-NULL everything is merged into a bitmap with that name,
|
||||
* otherwise each bitmap is merged into a bitmap with the same name into @target.
|
||||
* Additionally if @dstbitmap is non-NULL the target bitmap is created as 'inactive'
|
||||
* and 'transient' as a special case for the backup operation.
|
||||
*
|
||||
* If @writebitmapsrc is non-NULL, the 'libvirt-tmp-activewrite' bitmap from
|
||||
* given node is merged along with others. This bitmap corresponds to the writes
|
||||
* which occurred between an active layer job finished and the rest of the bitmap
|
||||
* merging.
|
||||
*
|
||||
* If the bitmap is not valid somehow (see qemuBlockBitmapChainIsValid) given
|
||||
* bitmap is silently skipped, so callers must ensure that given bitmap is valid
|
||||
* if they care about it.
|
||||
*
|
||||
* The resulting 'transaction' QMP command actions are filled in and returned via
|
||||
* @actions.
|
||||
*
|
||||
* Note that @actions may be NULL if no merging is required.
|
||||
*/
|
||||
int
|
||||
qemuBlockGetBitmapMergeActions(virStorageSourcePtr topsrc,
|
||||
virStorageSourcePtr basesrc,
|
||||
virStorageSourcePtr target,
|
||||
const char *bitmapname,
|
||||
const char *dstbitmapname,
|
||||
virStorageSourcePtr writebitmapsrc,
|
||||
virJSONValuePtr *actions,
|
||||
virHashTablePtr blockNamedNodeData)
|
||||
{
|
||||
g_autoptr(virJSONValue) act = virJSONValueNewArray();
|
||||
virStorageSourcePtr n;
|
||||
|
||||
g_autoptr(GSList) bitmaps = NULL;
|
||||
GSList *next;
|
||||
|
||||
if (!(bitmaps = qemuBlockGetBitmapMergeActionsGetBitmaps(topsrc, bitmapname,
|
||||
blockNamedNodeData)))
|
||||
return 0;
|
||||
|
||||
for (next = bitmaps; next; next = next->next) {
|
||||
const char *curbitmap = next->data;
|
||||
const char *mergebitmapname = dstbitmapname;
|
||||
bool mergebitmappersistent = false;
|
||||
bool mergebitmapdisabled = true;
|
||||
g_autoptr(virJSONValue) merge = virJSONValueNewArray();
|
||||
unsigned long long granularity = 0;
|
||||
qemuBlockNamedNodeDataBitmapPtr bitmap;
|
||||
|
||||
/* explicitly named destinations mean that we want a temporary
|
||||
* disabled bitmap only, so undo the default for non-explicit cases */
|
||||
if (!mergebitmapname) {
|
||||
mergebitmapname = curbitmap;
|
||||
mergebitmappersistent = true;
|
||||
mergebitmapdisabled = false;
|
||||
}
|
||||
|
||||
for (n = topsrc; virStorageSourceIsBacking(n) && n != basesrc; n = n->backingStore) {
|
||||
if (!(bitmap = qemuBlockNamedNodeDataGetBitmapByName(blockNamedNodeData,
|
||||
n, curbitmap)))
|
||||
continue;
|
||||
|
||||
if (granularity == 0)
|
||||
granularity = bitmap->granularity;
|
||||
|
||||
if (qemuMonitorTransactionBitmapMergeSourceAddBitmap(merge,
|
||||
n->nodeformat,
|
||||
bitmap->name) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dstbitmapname ||
|
||||
!(bitmap = qemuBlockNamedNodeDataGetBitmapByName(blockNamedNodeData,
|
||||
target, curbitmap))) {
|
||||
|
||||
if (qemuMonitorTransactionBitmapAdd(act,
|
||||
target->nodeformat,
|
||||
mergebitmapname,
|
||||
mergebitmappersistent,
|
||||
mergebitmapdisabled,
|
||||
granularity) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (writebitmapsrc &&
|
||||
qemuMonitorTransactionBitmapMergeSourceAddBitmap(merge,
|
||||
writebitmapsrc->nodeformat,
|
||||
"libvirt-tmp-activewrite") < 0)
|
||||
return -1;
|
||||
|
||||
if (qemuMonitorTransactionBitmapMerge(act, target->nodeformat,
|
||||
mergebitmapname, &merge) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (writebitmapsrc &&
|
||||
qemuMonitorTransactionBitmapRemove(act, writebitmapsrc->nodeformat,
|
||||
"libvirt-tmp-activewrite") < 0)
|
||||
return -1;
|
||||
|
||||
if (virJSONValueArraySize(act) > 0)
|
||||
*actions = g_steal_pointer(&act);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* qemuBlockBitmapChainIsValid:
|
||||
*
|
||||
|
@ -221,6 +221,16 @@ virHashTablePtr
|
||||
qemuBlockGetNamedNodeData(virDomainObjPtr vm,
|
||||
qemuDomainAsyncJob asyncJob);
|
||||
|
||||
int
|
||||
qemuBlockGetBitmapMergeActions(virStorageSourcePtr topsrc,
|
||||
virStorageSourcePtr basesrc,
|
||||
virStorageSourcePtr target,
|
||||
const char *bitmapname,
|
||||
const char *dstbitmapname,
|
||||
virStorageSourcePtr writebitmapsrc,
|
||||
virJSONValuePtr *actions,
|
||||
virHashTablePtr blockNamedNodeData);
|
||||
|
||||
bool
|
||||
qemuBlockBitmapChainIsValid(virStorageSourcePtr src,
|
||||
const char *bitmapname,
|
||||
|
Loading…
x
Reference in New Issue
Block a user