提交 30bc4260 编写于 作者: P Peter Krempa

qemu: checkpoint: Introduce support for deleting checkpoints accross snapshots

Allow deleting of checkpoints when snapshots were created along. The
code tracks and modifies the checkpoint list so that backups can still
be taken with such a backing chain. This unfortunately requires to
rename few bitmaps (by copying and deleting them) in some cases.
Signed-off-by: NPeter Krempa <pkrempa@redhat.com>
Reviewed-by: NJán Tomko <jtomko@redhat.com>
上级 d7d97e87
......@@ -24,6 +24,7 @@
#include "qemu_capabilities.h"
#include "qemu_monitor.h"
#include "qemu_domain.h"
#include "qemu_block.h"
#include "virerror.h"
#include "virlog.h"
......@@ -150,39 +151,92 @@ qemuCheckpointFindActiveDiskInParent(virDomainObjPtr vm,
int
qemuCheckpointDiscardDiskBitmaps(virStorageSourcePtr src,
virHashTablePtr blockNamedNodeData,
const char *delbitmap,
const char *parentbitmap,
bool chkcurrent,
virJSONValuePtr actions)
virJSONValuePtr actions,
const char *diskdst)
{
if (parentbitmap) {
g_autoptr(virJSONValue) arr = NULL;
virStorageSourcePtr n = src;
if (!(arr = virJSONValueNewArray()))
return -1;
/* find the backing chain entry with bitmap named '@delbitmap' */
while (n) {
qemuBlockNamedNodeDataBitmapPtr tmp;
if (qemuMonitorTransactionBitmapMergeSourceAddBitmap(arr,
src->nodeformat,
delbitmap) < 0)
return -1;
if ((tmp = qemuBlockNamedNodeDataGetBitmapByName(blockNamedNodeData,
n, delbitmap))) {
break;
}
n = n->backingStore;
}
if (!n) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("bitmap '%s' not found in backing chain of '%s'"),
delbitmap, diskdst);
return -1;
}
if (chkcurrent) {
if (qemuMonitorTransactionBitmapEnable(actions,
src->nodeformat,
parentbitmap) < 0)
while (n) {
qemuBlockNamedNodeDataBitmapPtr srcbitmap;
if (!(srcbitmap = qemuBlockNamedNodeDataGetBitmapByName(blockNamedNodeData,
n, delbitmap)))
break;
/* For the actual checkpoint deletion we will merge any bitmap into the
* bitmap of the parent checkpoint (@parentbitmap) or for any image
* where the parent checkpoint bitmap is not present we must rename
* the bitmap of the deleted checkpoint into the bitmap of the parent
* checkpoint as qemu can't currently take the allocation map and turn
* it into a bitmap and thus we wouldn't be able to do a backup. */
if (parentbitmap) {
qemuBlockNamedNodeDataBitmapPtr dstbitmap;
g_autoptr(virJSONValue) arr = NULL;
dstbitmap = qemuBlockNamedNodeDataGetBitmapByName(blockNamedNodeData,
n, parentbitmap);
if (dstbitmap) {
if (srcbitmap->recording && !dstbitmap->recording) {
if (qemuMonitorTransactionBitmapEnable(actions,
n->nodeformat,
dstbitmap->name) < 0)
return -1;
}
} else {
if (qemuMonitorTransactionBitmapAdd(actions,
n->nodeformat,
parentbitmap,
true,
!srcbitmap->recording,
srcbitmap->granularity) < 0)
return -1;
}
if (!(arr = virJSONValueNewArray()))
return -1;
if (qemuMonitorTransactionBitmapMergeSourceAddBitmap(arr,
n->nodeformat,
srcbitmap->name) < 0)
return -1;
if (qemuMonitorTransactionBitmapMerge(actions,
n->nodeformat,
parentbitmap, &arr) < 0)
return -1;
}
if (qemuMonitorTransactionBitmapMerge(actions,
src->nodeformat,
parentbitmap, &arr) < 0)
if (qemuMonitorTransactionBitmapRemove(actions,
n->nodeformat,
srcbitmap->name) < 0)
return -1;
}
if (qemuMonitorTransactionBitmapRemove(actions,
src->nodeformat,
delbitmap) < 0)
return -1;
n = n->backingStore;
}
return 0;
}
......@@ -191,11 +245,11 @@ qemuCheckpointDiscardDiskBitmaps(virStorageSourcePtr src,
static int
qemuCheckpointDiscardBitmaps(virDomainObjPtr vm,
virDomainCheckpointDefPtr chkdef,
bool chkcurrent,
virDomainMomentObjPtr parent)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
virQEMUDriverPtr driver = priv->driver;
g_autoptr(virHashTable) blockNamedNodeData = NULL;
int rc;
g_autoptr(virJSONValue) actions = NULL;
size_t i;
......@@ -203,6 +257,11 @@ qemuCheckpointDiscardBitmaps(virDomainObjPtr vm,
if (!(actions = virJSONValueNewArray()))
return -1;
qemuDomainObjEnterMonitor(driver, vm);
blockNamedNodeData = qemuMonitorBlockGetNamedNodeData(priv->mon);
if (qemuDomainObjExitMonitor(priv->driver, vm) < 0 || !blockNamedNodeData)
return -1;
for (i = 0; i < chkdef->ndisks; i++) {
virDomainCheckpointDiskDef *chkdisk = &chkdef->disks[i];
virDomainDiskDefPtr domdisk = virDomainDiskByTarget(vm->def, chkdisk->name);
......@@ -223,8 +282,9 @@ qemuCheckpointDiscardBitmaps(virDomainObjPtr vm,
chkdisk->name)))
parentbitmap = parentchkdisk->name;
if (qemuCheckpointDiscardDiskBitmaps(domdisk->src, chkdisk->bitmap,
parentbitmap, chkcurrent, actions) < 0)
if (qemuCheckpointDiscardDiskBitmaps(domdisk->src, blockNamedNodeData,
chkdisk->bitmap, parentbitmap,
actions, domdisk->dst) < 0)
return -1;
}
......@@ -262,7 +322,7 @@ qemuCheckpointDiscard(virQEMUDriverPtr driver,
virDomainCheckpointDefPtr chkdef = virDomainCheckpointObjGetDef(chk);
parent = virDomainCheckpointFindByName(vm->checkpoints,
chk->def->parent_name);
if (qemuCheckpointDiscardBitmaps(vm, chkdef, chkcurrent, parent) < 0)
if (qemuCheckpointDiscardBitmaps(vm, chkdef, parent) < 0)
return -1;
}
......
......@@ -74,7 +74,8 @@ qemuCheckpointRollbackMetadata(virDomainObjPtr vm,
int
qemuCheckpointDiscardDiskBitmaps(virStorageSourcePtr src,
virHashTablePtr blockNamedNodeData,
const char *delbitmap,
const char *parentbitmap,
bool chkcurrent,
virJSONValuePtr actions);
virJSONValuePtr actions,
const char *diskdst);
......@@ -708,6 +708,7 @@ struct testQemuCheckpointDeleteMergeData {
virStorageSourcePtr chain;
const char *deletebitmap;
const char *parentbitmap;
const char *nodedatafile;
};
......@@ -718,22 +719,30 @@ testQemuCheckpointDeleteMerge(const void *opaque)
g_autofree char *actual = NULL;
g_autofree char *expectpath = NULL;
g_autoptr(virJSONValue) actions = NULL;
bool currentcheckpoint;
g_autoptr(virJSONValue) nodedatajson = NULL;
g_autoptr(virHashTable) nodedata = NULL;
expectpath = g_strdup_printf("%s/%s%s-out.json", abs_srcdir,
checkpointDeletePrefix, data->name);
if (!(actions = virJSONValueNewArray()))
if (!(nodedatajson = virTestLoadFileJSON(bitmapDetectPrefix, data->nodedatafile,
".json", NULL)))
return -1;
/* hack to get the 'current' state until the function stops accepting it */
currentcheckpoint = STREQ("current", data->deletebitmap);
if (!(nodedata = qemuMonitorJSONBlockGetNamedNodeDataJSON(nodedatajson))) {
VIR_TEST_VERBOSE("failed to load nodedata JSON\n");
return -1;
}
if (!(actions = virJSONValueNewArray()))
return -1;
if (qemuCheckpointDiscardDiskBitmaps(data->chain,
nodedata,
data->deletebitmap,
data->parentbitmap,
currentcheckpoint,
actions) < 0) {
actions,
"testdisk") < 0) {
VIR_TEST_VERBOSE("failed to generate checkpoint delete transaction\n");
return -1;
}
......@@ -992,22 +1001,23 @@ mymain(void)
TEST_BACKUP_BITMAP_CALCULATE("snapshot-intermediate", bitmapSourceChain, "d", "snapshots");
TEST_BACKUP_BITMAP_CALCULATE("snapshot-deep", bitmapSourceChain, "a", "snapshots");
#define TEST_CHECKPOINT_DELETE_MERGE(testname, delbmp, parbmp) \
#define TEST_CHECKPOINT_DELETE_MERGE(testname, delbmp, parbmp, named) \
do { \
checkpointdeletedata.name = testname; \
checkpointdeletedata.chain = bitmapSourceChain; \
checkpointdeletedata.deletebitmap = delbmp; \
checkpointdeletedata.parentbitmap = parbmp; \
checkpointdeletedata.nodedatafile = named; \
if (virTestRun("checkpoint delete " testname, \
testQemuCheckpointDeleteMerge, &checkpointdeletedata) < 0) \
ret = -1; \
} while (0)
TEST_CHECKPOINT_DELETE_MERGE("basic-noparent", "a", NULL);
TEST_CHECKPOINT_DELETE_MERGE("basic-intermediate1", "b", "a");
TEST_CHECKPOINT_DELETE_MERGE("basic-intermediate2", "c", "b");
TEST_CHECKPOINT_DELETE_MERGE("basic-intermediate3", "d", "c");
TEST_CHECKPOINT_DELETE_MERGE("basic-current", "current", "d");
TEST_CHECKPOINT_DELETE_MERGE("basic-noparent", "a", NULL, "basic");
TEST_CHECKPOINT_DELETE_MERGE("basic-intermediate1", "b", "a", "basic");
TEST_CHECKPOINT_DELETE_MERGE("basic-intermediate2", "c", "b", "basic");
TEST_CHECKPOINT_DELETE_MERGE("basic-intermediate3", "d", "c", "basic");
TEST_CHECKPOINT_DELETE_MERGE("basic-current", "current", "d", "basic");
cleanup:
virHashFree(diskxmljsondata.schema);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册