mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-08-28 19:41:16 +00:00
Since qemuDomainDefPostParse callback requires qemuCaps, we need to make sure it gets the capabilities stored in the domain's private data if the domain is running. Passing NULL may cause QEMU capabilities probing to be triggered in case QEMU binary changed in the meantime. When this happens while a running domain object is locked, QMP event delivered to the domain before QEMU capabilities probing finishes will deadlock the event loop. Several general snapshot and checkpoint APIs were lazily passing NULL as the parseOpaque pointer instead of letting their callers pass the right data. This patch fixes all paths leading to virDomainDefParseNode. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
214 lines
6.0 KiB
C
214 lines
6.0 KiB
C
#include <config.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <fcntl.h>
|
|
|
|
#include "testutils.h"
|
|
|
|
#ifdef WITH_QEMU
|
|
|
|
# include "internal.h"
|
|
# include "qemu/qemu_conf.h"
|
|
# include "qemu/qemu_domain.h"
|
|
# include "checkpoint_conf.h"
|
|
# include "testutilsqemu.h"
|
|
# include "virstring.h"
|
|
|
|
# define VIR_FROM_THIS VIR_FROM_NONE
|
|
|
|
static virQEMUDriver driver;
|
|
|
|
enum {
|
|
TEST_REDEFINE = 1 << 0, /* Test use of REDEFINE parse flag */
|
|
TEST_PARENT = 1 << 1, /* hard-code parent after parse */
|
|
TEST_VDA_BITMAP = 1 << 2, /* hard-code disk vda after parse */
|
|
TEST_SIZE = 1 << 3, /* Test use of SIZE format flag */
|
|
TEST_INVALID = 1 << 4, /* Test that input fails parse */
|
|
};
|
|
|
|
static int
|
|
testCompareXMLToXMLFiles(const char *inxml,
|
|
const char *outxml,
|
|
unsigned int flags)
|
|
{
|
|
unsigned int parseflags = 0;
|
|
unsigned int formatflags = VIR_DOMAIN_CHECKPOINT_FORMAT_SECURE;
|
|
VIR_AUTOFREE(char *) inXmlData = NULL;
|
|
VIR_AUTOFREE(char *) outXmlData = NULL;
|
|
VIR_AUTOFREE(char *) actual = NULL;
|
|
VIR_AUTOUNREF(virDomainCheckpointDefPtr) def = NULL;
|
|
|
|
if (flags & TEST_REDEFINE)
|
|
parseflags |= VIR_DOMAIN_CHECKPOINT_PARSE_REDEFINE;
|
|
|
|
if (virTestLoadFile(inxml, &inXmlData) < 0)
|
|
return -1;
|
|
|
|
if (!(flags & TEST_INVALID) &&
|
|
virTestLoadFile(outxml, &outXmlData) < 0)
|
|
return -1;
|
|
|
|
if (!(def = virDomainCheckpointDefParseString(inXmlData, driver.caps,
|
|
driver.xmlopt, NULL,
|
|
parseflags))) {
|
|
if (flags & TEST_INVALID)
|
|
return 0;
|
|
return -1;
|
|
}
|
|
if (flags & TEST_PARENT) {
|
|
if (def->parent.parent_name)
|
|
return -1;
|
|
if (VIR_STRDUP(def->parent.parent_name, "1525111885") < 0)
|
|
return -1;
|
|
}
|
|
if (flags & TEST_VDA_BITMAP) {
|
|
virDomainCheckpointDiskDefPtr disk;
|
|
|
|
if (VIR_EXPAND_N(def->disks, def->ndisks, 1) < 0)
|
|
return -1;
|
|
disk = &def->disks[0];
|
|
if (disk->bitmap)
|
|
return -1;
|
|
if (!disk->name) {
|
|
disk->type = VIR_DOMAIN_CHECKPOINT_TYPE_BITMAP;
|
|
if (VIR_STRDUP(disk->name, "vda") < 0)
|
|
return -1;
|
|
} else if (STRNEQ(disk->name, "vda")) {
|
|
return -1;
|
|
}
|
|
if (VIR_STRDUP(disk->bitmap, def->parent.name) < 0)
|
|
return -1;
|
|
}
|
|
if (flags & TEST_SIZE) {
|
|
def->disks[0].size = 1048576;
|
|
formatflags |= VIR_DOMAIN_CHECKPOINT_FORMAT_SIZE;
|
|
}
|
|
|
|
/* Parsing XML does not populate the domain definition; work
|
|
* around that by not requesting domain on output */
|
|
if (!def->parent.dom)
|
|
formatflags |= VIR_DOMAIN_CHECKPOINT_FORMAT_NO_DOMAIN;
|
|
|
|
if (!(actual = virDomainCheckpointDefFormat(def, driver.caps,
|
|
driver.xmlopt,
|
|
formatflags)))
|
|
return -1;
|
|
|
|
if (STRNEQ(outXmlData, actual)) {
|
|
virTestDifferenceFull(stderr, outXmlData, outxml, actual, inxml);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct testInfo {
|
|
const char *inxml;
|
|
const char *outxml;
|
|
long long creationTime;
|
|
unsigned int flags;
|
|
};
|
|
static long long mocktime;
|
|
|
|
static int
|
|
testCheckpointPostParse(virDomainMomentDefPtr def)
|
|
{
|
|
if (!mocktime)
|
|
return 0;
|
|
if (def->creationTime)
|
|
return -1;
|
|
def->creationTime = mocktime;
|
|
if (!def->name &&
|
|
virAsprintf(&def->name, "%lld", def->creationTime) < 0)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
testCompareXMLToXMLHelper(const void *data)
|
|
{
|
|
const struct testInfo *info = data;
|
|
|
|
mocktime = info->creationTime;
|
|
return testCompareXMLToXMLFiles(info->inxml, info->outxml, info->flags);
|
|
}
|
|
|
|
|
|
static int
|
|
mymain(void)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (qemuTestDriverInit(&driver) < 0)
|
|
return EXIT_FAILURE;
|
|
|
|
virDomainXMLOptionSetMomentPostParse(driver.xmlopt,
|
|
testCheckpointPostParse);
|
|
|
|
# define DO_TEST(prefix, name, inpath, outpath, time, flags) \
|
|
do { \
|
|
const struct testInfo info = {abs_srcdir "/" inpath "/" name ".xml", \
|
|
abs_srcdir "/" outpath "/" name ".xml", \
|
|
time, flags}; \
|
|
if (virTestRun("CHECKPOINT XML-2-XML " prefix " " name, \
|
|
testCompareXMLToXMLHelper, &info) < 0) \
|
|
ret = -1; \
|
|
} while (0)
|
|
|
|
# define DO_TEST_INOUT(name, time, flags) \
|
|
DO_TEST("in->out", name, \
|
|
"qemudomaincheckpointxml2xmlin", \
|
|
"qemudomaincheckpointxml2xmlout", \
|
|
time, flags)
|
|
# define DO_TEST_OUT(name, flags) \
|
|
DO_TEST("out->out", name, \
|
|
"qemudomaincheckpointxml2xmlout", \
|
|
"qemudomaincheckpointxml2xmlout", \
|
|
0, flags | TEST_REDEFINE)
|
|
# define DO_TEST_INVALID(name) \
|
|
DO_TEST("in->out", name, \
|
|
"qemudomaincheckpointxml2xmlin", \
|
|
"qemudomaincheckpointxml2xmlout", \
|
|
0, TEST_INVALID)
|
|
|
|
/* Unset or set all envvars here that are copied in qemudBuildCommandLine
|
|
* using ADD_ENV_COPY, otherwise these tests may fail due to unexpected
|
|
* values for these envvars */
|
|
setenv("PATH", "/bin", 1);
|
|
|
|
/* Test a normal user redefine */
|
|
DO_TEST_OUT("redefine", 0);
|
|
|
|
/* Tests of valid user input, and resulting output */
|
|
DO_TEST_INOUT("empty", 1525889631, TEST_VDA_BITMAP);
|
|
DO_TEST_INOUT("disk-default", 1525889631, TEST_PARENT | TEST_VDA_BITMAP);
|
|
DO_TEST_INOUT("sample", 1525889631, TEST_PARENT | TEST_VDA_BITMAP);
|
|
DO_TEST_INOUT("size", 1553648510,
|
|
TEST_PARENT | TEST_VDA_BITMAP | TEST_SIZE);
|
|
|
|
/* Tests of invalid user input */
|
|
DO_TEST_INVALID("disk-invalid");
|
|
DO_TEST_INVALID("name-invalid");
|
|
|
|
qemuTestDriverFree(&driver);
|
|
|
|
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
|
|
}
|
|
|
|
VIR_TEST_MAIN(mymain)
|
|
|
|
#else
|
|
|
|
int
|
|
main(void)
|
|
{
|
|
return EXIT_AM_SKIP;
|
|
}
|
|
|
|
#endif /* WITH_QEMU */
|