Devel
Threads by month
- ----- 2026 -----
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- 19 participants
- 40177 discussions
[libvirt] [PATCH] python: Fix export of virDomainSnapshotListChildrenNames
by Peter Krempa 13 Dec '11
by Peter Krempa 13 Dec '11
13 Dec '11
Commit f2013c9dd1ce468b8620ee35c232a93ef7026fb0 added implementation of
virDomainSnapshotListChildrenNames override export, but registration of
the newly exported function was not added.
*python/libvirt-override.c: - register export of function
---
python/libvirt-override.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/python/libvirt-override.c b/python/libvirt-override.c
index 9e98918..a16a7d1 100644
--- a/python/libvirt-override.c
+++ b/python/libvirt-override.c
@@ -5106,6 +5106,7 @@ static PyMethodDef libvirtMethods[] = {
{(char *) "virConnectBaselineCPU", libvirt_virConnectBaselineCPU, METH_VARARGS, NULL},
{(char *) "virDomainGetJobInfo", libvirt_virDomainGetJobInfo, METH_VARARGS, NULL},
{(char *) "virDomainSnapshotListNames", libvirt_virDomainSnapshotListNames, METH_VARARGS, NULL},
+ {(char *) "virDomainSnapshotListChildrenNames", libvirt_virDomainSnapshotListChildrenNames, METH_VARARGS, NULL},
{(char *) "virDomainRevertToSnapshot", libvirt_virDomainRevertToSnapshot, METH_VARARGS, NULL},
{(char *) "virDomainGetBlockJobInfo", libvirt_virDomainGetBlockJobInfo, METH_VARARGS, NULL},
{(char *) "virDomainSetBlockIoTune", libvirt_virDomainSetBlockIoTune, METH_VARARGS, NULL},
--
1.7.3.4
2
2
13 Dec '11
Macro for translating escape sequence to char expects it to be
all uppercase. Without this, various lowercase sequences are
malformed: e.g. ^e gets translated to %.
---
tools/virsh.c | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index d58b827..ff8b3d2 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -17776,6 +17776,11 @@ vshParseArgv(vshControl *ctl, int argc, char **argv)
if ((len == 2 && *optarg == '^') ||
(len == 1 && *optarg != '^')) {
ctl->escapeChar = optarg;
+ while (*optarg) {
+ if (islower(*optarg))
+ *optarg = toupper(*optarg);
+ optarg++;
+ }
} else {
vshError(ctl, _("Invalid string '%s' for escape sequence"),
optarg);
--
1.7.3.4
2
1
13 Dec '11
Changes since v1
- With Eric's comments squashed in.
This chunk of code below repeated in several functions, factor it into
a helper method virDomainLiveConfigHelperMethod to eliminate duplicated code
based on Eric and Adam's suggestion. I have tested it for all the
relevant APIs changed.
Signed-off-by: Eric Blake <eblake(a)redhat.com>
Signed-off-by: Lei Li <lilei(a)linux.vnet.ibm.com>
---
src/conf/domain_conf.c | 51 ++++++++
src/conf/domain_conf.h | 7 +
src/libvirt_private.syms | 1 +
src/qemu/qemu_driver.c | 288 ++++------------------------------------------
4 files changed, 81 insertions(+), 266 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index d68ab10..da98a22 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -1670,6 +1670,57 @@ virDomainObjGetPersistentDef(virCapsPtr caps,
}
/*
+ * Helper method for --current --live --config option, and check with
+ * whether domain is active or can get persistent domain configuration.
+ *
+ * Return 0 if success, also change the flags and get the persistent
+ * domain configuration if needed. Return -1 on error.
+ */
+int
+virDomainLiveConfigHelperMethod(virCapsPtr caps,
+ virDomainObjPtr dom,
+ unsigned int *flags,
+ virDomainDefPtr *persistentDef)
+{
+ bool isActive;
+ int ret = -1;
+
+ isActive = virDomainObjIsActive(dom);
+
+ if ((*flags & (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG)) ==
+ VIR_DOMAIN_AFFECT_CURRENT) {
+ if (isActive)
+ *flags |= VIR_DOMAIN_AFFECT_LIVE;
+ else
+ *flags |= VIR_DOMAIN_AFFECT_CONFIG;
+ }
+
+ if (!isActive && (*flags & VIR_DOMAIN_AFFECT_LIVE)) {
+ virDomainReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("domain is not running"));
+ goto cleanup;
+ }
+
+ if (*flags & VIR_DOMAIN_AFFECT_CONFIG) {
+ if (!dom->persistent) {
+ virDomainReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("cannot change persistent config of a transient domain"));
+ goto cleanup;
+ }
+ if (!(*persistentDef = virDomainObjGetPersistentDef(caps, dom))) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Get persistent config failed"));
+ goto cleanup;
+ }
+ }
+
+ ret = 0;
+
+cleanup:
+ return ret;
+}
+
+/*
* The caller must hold a lock on the driver owning 'doms',
* and must also have locked 'dom', to ensure no one else
* is either waiting for 'dom' or still using it
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index d6ed898..3229a6f 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1737,6 +1737,13 @@ int virDomainObjSetDefTransient(virCapsPtr caps,
virDomainDefPtr
virDomainObjGetPersistentDef(virCapsPtr caps,
virDomainObjPtr domain);
+
+int
+virDomainLiveConfigHelperMethod(virCapsPtr caps,
+ virDomainObjPtr dom,
+ unsigned int *flags,
+ virDomainDefPtr *persistentDef);
+
virDomainDefPtr
virDomainObjCopyPersistentDef(virCapsPtr caps, virDomainObjPtr dom);
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index a81c230..48ffdf2 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -358,6 +358,7 @@ virDomainLifecycleCrashTypeFromString;
virDomainLifecycleCrashTypeToString;
virDomainLifecycleTypeFromString;
virDomainLifecycleTypeToString;
+virDomainLiveConfigHelperMethod;
virDomainLoadAllConfigs;
virDomainMemballoonModelTypeFromString;
virDomainMemballoonModelTypeToString;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 10a289e..aa92573 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -1822,12 +1822,6 @@ static int qemudDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem,
isActive = virDomainObjIsActive(vm);
- if (flags == VIR_DOMAIN_AFFECT_CURRENT) {
- if (isActive)
- flags = VIR_DOMAIN_AFFECT_LIVE;
- else
- flags = VIR_DOMAIN_AFFECT_CONFIG;
- }
if (flags == VIR_DOMAIN_MEM_MAXIMUM) {
if (isActive)
flags = VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_MEM_MAXIMUM;
@@ -1835,21 +1829,8 @@ static int qemudDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem,
flags = VIR_DOMAIN_AFFECT_CONFIG | VIR_DOMAIN_MEM_MAXIMUM;
}
- if (!isActive && (flags & VIR_DOMAIN_AFFECT_LIVE)) {
- qemuReportError(VIR_ERR_OPERATION_INVALID,
- "%s", _("domain is not running"));
+ if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags, &persistentDef) < 0)
goto endjob;
- }
-
- if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
- if (!vm->persistent) {
- qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("cannot change persistent config of a transient domain"));
- goto endjob;
- }
- if (!(persistentDef = virDomainObjGetPersistentDef(driver->caps, vm)))
- goto endjob;
- }
if (flags & VIR_DOMAIN_MEM_MAXIMUM) {
/* resize the maximum memory */
@@ -3271,7 +3252,6 @@ qemuDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
const char * type;
int max;
int ret = -1;
- bool isActive;
bool maximum;
virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
@@ -3299,16 +3279,11 @@ qemuDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
goto cleanup;
- isActive = virDomainObjIsActive(vm);
maximum = (flags & VIR_DOMAIN_VCPU_MAXIMUM) != 0;
flags &= ~VIR_DOMAIN_VCPU_MAXIMUM;
- if (flags == VIR_DOMAIN_AFFECT_CURRENT) {
- if (isActive)
- flags |= VIR_DOMAIN_AFFECT_LIVE;
- else
- flags |= VIR_DOMAIN_AFFECT_CONFIG;
- }
+ if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags, &persistentDef) < 0)
+ goto endjob;
/* MAXIMUM cannot be mixed with LIVE. */
if (maximum && (flags & VIR_DOMAIN_AFFECT_LIVE)) {
@@ -3317,18 +3292,6 @@ qemuDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
goto endjob;
}
- if (!isActive && (flags & VIR_DOMAIN_AFFECT_LIVE)) {
- qemuReportError(VIR_ERR_OPERATION_INVALID,
- "%s", _("domain is not running"));
- goto endjob;
- }
-
- if (!vm->persistent && (flags & VIR_DOMAIN_AFFECT_CONFIG)) {
- qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("cannot change persistent config of a transient domain"));
- goto endjob;
- }
-
if (!(type = virDomainVirtTypeToString(vm->def->virtType))) {
qemuReportError(VIR_ERR_INTERNAL_ERROR,
_("unknown virt type in domain definition '%d'"),
@@ -3353,9 +3316,6 @@ qemuDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
goto endjob;
}
- if (!(persistentDef = virDomainObjGetPersistentDef(driver->caps, vm)))
- goto endjob;
-
switch (flags) {
case VIR_DOMAIN_AFFECT_CONFIG:
if (maximum) {
@@ -3414,7 +3374,6 @@ qemudDomainPinVcpuFlags(virDomainPtr dom,
int maxcpu, hostcpus;
virNodeInfo nodeinfo;
int ret = -1;
- bool isActive;
qemuDomainObjPrivatePtr priv;
bool canResetting = true;
int pcpu;
@@ -3434,20 +3393,8 @@ qemudDomainPinVcpuFlags(virDomainPtr dom,
goto cleanup;
}
- isActive = virDomainObjIsActive(vm);
- if (flags == VIR_DOMAIN_AFFECT_CURRENT) {
- if (isActive)
- flags = VIR_DOMAIN_AFFECT_LIVE;
- else
- flags = VIR_DOMAIN_AFFECT_CONFIG;
- }
-
- if (!isActive && (flags & VIR_DOMAIN_AFFECT_LIVE)) {
- qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("a domain is inactive; can change only "
- "persistent config"));
+ if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags, &persistentDef) < 0)
goto cleanup;
- }
priv = vm->privateData;
@@ -3458,16 +3405,6 @@ qemudDomainPinVcpuFlags(virDomainPtr dom,
goto cleanup;
}
- if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
- if (!vm->persistent) {
- qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("cannot change persistent config of a transient domain"));
- goto cleanup;
- }
- if (!(persistentDef = virDomainObjGetPersistentDef(driver->caps, vm)))
- goto cleanup;
- }
-
if (nodeGetInfo(dom->conn, &nodeinfo) < 0)
goto cleanup;
hostcpus = VIR_NODEINFO_MAXCPUS(nodeinfo);
@@ -3567,7 +3504,6 @@ qemudDomainGetVcpuPinInfo(virDomainPtr dom,
virNodeInfo nodeinfo;
virDomainDefPtr targetDef = NULL;
int ret = -1;
- bool isActive;
int maxcpu, hostcpus, vcpu, pcpu;
int n;
virDomainVcpuPinDefPtr *vcpupin_list;
@@ -3589,33 +3525,13 @@ qemudDomainGetVcpuPinInfo(virDomainPtr dom,
goto cleanup;
}
- isActive = virDomainObjIsActive(vm);
- if (flags == VIR_DOMAIN_AFFECT_CURRENT) {
- if (isActive)
- flags = VIR_DOMAIN_AFFECT_LIVE;
- else
- flags = VIR_DOMAIN_AFFECT_CONFIG;
- }
+ if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags, &targetDef) < 0)
+ goto cleanup;
if (flags & VIR_DOMAIN_AFFECT_LIVE) {
- if (!isActive) {
- qemuReportError(VIR_ERR_OPERATION_INVALID,
- "%s", _("domain is not running"));
- goto cleanup;
- }
targetDef = vm->def;
}
- if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
- if (!vm->persistent) {
- qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("cannot get persistent config of a transient domain"));
- goto cleanup;
- }
- if (!(targetDef = virDomainObjGetPersistentDef(driver->caps, vm)))
- goto cleanup;
- }
-
/* Coverity didn't realize that targetDef must be set if we got here. */
sa_assert(targetDef);
@@ -3760,7 +3676,6 @@ qemudDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
virDomainObjPtr vm;
virDomainDefPtr def;
int ret = -1;
- bool active;
virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
VIR_DOMAIN_AFFECT_CONFIG |
@@ -3778,34 +3693,11 @@ qemudDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
goto cleanup;
}
- active = virDomainObjIsActive(vm);
-
- if ((flags & (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG)) == 0) {
- if (active)
- flags |= VIR_DOMAIN_VCPU_LIVE;
- else
- flags |= VIR_DOMAIN_VCPU_CONFIG;
- }
- if ((flags & VIR_DOMAIN_AFFECT_LIVE) && (flags & VIR_DOMAIN_AFFECT_CONFIG)) {
- qemuReportError(VIR_ERR_INVALID_ARG,
- _("invalid flag combination: (0x%x)"), flags);
- return -1;
- }
+ if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags, &def) < 0)
+ goto cleanup;
if (flags & VIR_DOMAIN_AFFECT_LIVE) {
- if (!active) {
- qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("domain not active"));
- goto cleanup;
- }
def = vm->def;
- } else {
- if (!vm->persistent) {
- qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("domain is transient"));
- goto cleanup;
- }
- def = vm->newDef ? vm->newDef : vm->def;
}
ret = (flags & VIR_DOMAIN_VCPU_MAXIMUM) ? def->maxvcpus : def->vcpus;
@@ -6014,7 +5906,6 @@ static int qemuDomainSetBlkioParameters(virDomainPtr dom,
virDomainObjPtr vm = NULL;
virDomainDefPtr persistentDef = NULL;
int ret = -1;
- bool isActive;
virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
VIR_DOMAIN_AFFECT_CONFIG, -1);
@@ -6028,22 +5919,10 @@ static int qemuDomainSetBlkioParameters(virDomainPtr dom,
goto cleanup;
}
- isActive = virDomainObjIsActive(vm);
-
- if (flags == VIR_DOMAIN_AFFECT_CURRENT) {
- if (isActive)
- flags = VIR_DOMAIN_AFFECT_LIVE;
- else
- flags = VIR_DOMAIN_AFFECT_CONFIG;
- }
+ if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags, &persistentDef) < 0)
+ goto cleanup;
if (flags & VIR_DOMAIN_AFFECT_LIVE) {
- if (!isActive) {
- qemuReportError(VIR_ERR_OPERATION_INVALID,
- "%s", _("domain is not running"));
- goto cleanup;
- }
-
if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_BLKIO)) {
qemuReportError(VIR_ERR_OPERATION_INVALID, _("blkio cgroup isn't mounted"));
goto cleanup;
@@ -6056,16 +5935,6 @@ static int qemuDomainSetBlkioParameters(virDomainPtr dom,
}
}
- if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
- if (!vm->persistent) {
- qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("cannot change persistent config of a transient domain"));
- goto cleanup;
- }
- if (!(persistentDef = virDomainObjGetPersistentDef(driver->caps, vm)))
- goto cleanup;
- }
-
ret = 0;
if (flags & VIR_DOMAIN_AFFECT_LIVE) {
for (i = 0; i < nparams; i++) {
@@ -6220,7 +6089,6 @@ static int qemuDomainGetBlkioParameters(virDomainPtr dom,
unsigned int val;
int ret = -1;
int rc;
- bool isActive;
virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
VIR_DOMAIN_AFFECT_CONFIG |
@@ -6247,22 +6115,10 @@ static int qemuDomainGetBlkioParameters(virDomainPtr dom,
goto cleanup;
}
- isActive = virDomainObjIsActive(vm);
-
- if (flags == VIR_DOMAIN_AFFECT_CURRENT) {
- if (isActive)
- flags = VIR_DOMAIN_AFFECT_LIVE;
- else
- flags = VIR_DOMAIN_AFFECT_CONFIG;
- }
+ if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags, &persistentDef) < 0)
+ goto cleanup;
if (flags & VIR_DOMAIN_AFFECT_LIVE) {
- if (!isActive) {
- qemuReportError(VIR_ERR_OPERATION_INVALID,
- "%s", _("domain is not running"));
- goto cleanup;
- }
-
if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_BLKIO)) {
qemuReportError(VIR_ERR_OPERATION_INVALID, _("blkio cgroup isn't mounted"));
goto cleanup;
@@ -6275,16 +6131,6 @@ static int qemuDomainGetBlkioParameters(virDomainPtr dom,
}
}
- if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
- if (!vm->persistent) {
- qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("cannot change persistent config of a transient domain"));
- goto cleanup;
- }
- if (!(persistentDef = virDomainObjGetPersistentDef(driver->caps, vm)))
- goto cleanup;
- }
-
if (flags & VIR_DOMAIN_AFFECT_LIVE) {
for (i = 0; i < *nparams && i < QEMU_NB_BLKIO_PARAM; i++) {
virTypedParameterPtr param = ¶ms[i];
@@ -6440,7 +6286,6 @@ static int qemuDomainSetMemoryParameters(virDomainPtr dom,
virCgroupPtr group = NULL;
virDomainObjPtr vm = NULL;
int ret = -1;
- bool isActive;
virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
VIR_DOMAIN_AFFECT_CONFIG, -1);
@@ -6455,22 +6300,10 @@ static int qemuDomainSetMemoryParameters(virDomainPtr dom,
goto cleanup;
}
- isActive = virDomainObjIsActive(vm);
-
- if (flags == VIR_DOMAIN_AFFECT_CURRENT) {
- if (isActive)
- flags = VIR_DOMAIN_AFFECT_LIVE;
- else
- flags = VIR_DOMAIN_AFFECT_CONFIG;
- }
+ if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags, &persistentDef) < 0)
+ goto cleanup;
if (flags & VIR_DOMAIN_AFFECT_LIVE) {
- if (!isActive) {
- qemuReportError(VIR_ERR_OPERATION_INVALID,
- "%s", _("domain is not running"));
- goto cleanup;
- }
-
if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_MEMORY)) {
qemuReportError(VIR_ERR_OPERATION_INVALID,
"%s", _("cgroup memory controller is not mounted"));
@@ -6484,16 +6317,6 @@ static int qemuDomainSetMemoryParameters(virDomainPtr dom,
}
}
- if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
- if (!vm->persistent) {
- qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("cannot change persistent config of a transient domain"));
- goto cleanup;
- }
- if (!(persistentDef = virDomainObjGetPersistentDef(driver->caps, vm)))
- goto cleanup;
- }
-
ret = 0;
for (i = 0; i < nparams; i++) {
virTypedParameterPtr param = ¶ms[i];
@@ -6598,7 +6421,6 @@ static int qemuDomainGetMemoryParameters(virDomainPtr dom,
unsigned long long val;
int ret = -1;
int rc;
- bool isActive;
virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
VIR_DOMAIN_AFFECT_CONFIG |
@@ -6617,22 +6439,10 @@ static int qemuDomainGetMemoryParameters(virDomainPtr dom,
goto cleanup;
}
- isActive = virDomainObjIsActive(vm);
-
- if (flags == VIR_DOMAIN_AFFECT_CURRENT) {
- if (isActive)
- flags = VIR_DOMAIN_AFFECT_LIVE;
- else
- flags = VIR_DOMAIN_AFFECT_CONFIG;
- }
+ if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags, &persistentDef) < 0)
+ goto cleanup;
if (flags & VIR_DOMAIN_AFFECT_LIVE) {
- if (!isActive) {
- qemuReportError(VIR_ERR_OPERATION_INVALID,
- "%s", _("domain is not running"));
- goto cleanup;
- }
-
if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_MEMORY)) {
qemuReportError(VIR_ERR_OPERATION_INVALID,
"%s", _("cgroup memory controller is not mounted"));
@@ -6646,16 +6456,6 @@ static int qemuDomainGetMemoryParameters(virDomainPtr dom,
}
}
- if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
- if (!vm->persistent) {
- qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("cannot change persistent config of a transient domain"));
- goto cleanup;
- }
- if (!(persistentDef = virDomainObjGetPersistentDef(driver->caps, vm)))
- goto cleanup;
- }
-
if ((*nparams) == 0) {
/* Current number of memory parameters supported by cgroups */
*nparams = QEMU_NB_MEM_PARAM;
@@ -11126,7 +10926,6 @@ qemuDomainSetBlockIoTune(virDomainPtr dom,
const char *device = NULL;
int ret = -1;
int i;
- bool isActive;
int idx = -1;
virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
@@ -11151,33 +10950,8 @@ qemuDomainSetBlockIoTune(virDomainPtr dom,
if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
goto cleanup;
- isActive = virDomainObjIsActive(vm);
-
- if (flags == VIR_DOMAIN_AFFECT_CURRENT) {
- if (isActive)
- flags = VIR_DOMAIN_AFFECT_LIVE;
- else
- flags = VIR_DOMAIN_AFFECT_CONFIG;
- }
-
- if (!isActive && (flags & VIR_DOMAIN_AFFECT_LIVE)) {
- qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("domain is not running"));
+ if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags, &persistentDef) < 0)
goto endjob;
- }
-
- if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
- if (!vm->persistent) {
- qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("cannot change persistent config of a transient domain"));
- goto endjob;
- }
- if (!(persistentDef = virDomainObjGetPersistentDef(driver->caps, vm)))
- goto endjob;
- idx = virDomainDiskIndexByName(persistentDef, disk, true);
- if (idx < 0)
- goto endjob;
- }
for (i = 0; i < nparams; i++) {
virTypedParameterPtr param = ¶ms[i];
@@ -11238,7 +11012,10 @@ qemuDomainSetBlockIoTune(virDomainPtr dom,
}
if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
- sa_assert(persistentDef && idx >= 0);
+ sa_assert(persistentDef);
+ idx = virDomainDiskIndexByName(persistentDef, disk, true);
+ if (idx < 0)
+ goto endjob;
persistentDef->disks[idx]->blkdeviotune = info;
ret = virDomainSaveConfig(driver->configDir, persistentDef);
if (ret < 0) {
@@ -11276,7 +11053,6 @@ qemuDomainGetBlockIoTune(virDomainPtr dom,
const char *device = NULL;
int ret = -1;
int i;
- bool isActive;
virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
VIR_DOMAIN_AFFECT_CONFIG |
@@ -11310,20 +11086,8 @@ qemuDomainGetBlockIoTune(virDomainPtr dom,
if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
goto cleanup;
- isActive = virDomainObjIsActive(vm);
-
- if (flags == VIR_DOMAIN_AFFECT_CURRENT) {
- if (isActive)
- flags = VIR_DOMAIN_AFFECT_LIVE;
- else
- flags = VIR_DOMAIN_AFFECT_CONFIG;
- }
-
- if (!isActive && (flags & VIR_DOMAIN_AFFECT_LIVE)) {
- qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("domain is not running"));
+ if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags, &persistentDef) < 0)
goto endjob;
- }
if (flags & VIR_DOMAIN_AFFECT_LIVE) {
priv = vm->privateData;
@@ -11335,14 +11099,6 @@ qemuDomainGetBlockIoTune(virDomainPtr dom,
}
if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
- if (!vm->persistent) {
- qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
- _("domain is transient"));
- goto endjob;
- }
- if (!(persistentDef = virDomainObjGetPersistentDef(driver->caps, vm)))
- goto endjob;
-
int idx = virDomainDiskIndexByName(vm->def, disk, true);
if (idx < 0)
goto endjob;
--
1.7.1
2
1
Hi,
today I was trying to use the --copy-storage-all feature of virsh
migrate, in an attempt to migrate KVM-instances to another storage
backend. Doing so, I ran into some trouble:
First of all, it turned out the disk image-file has to be present on the
receiving end of the migration. When, just to check, this disk image is
smaller than the original image, migration suddenly stops (after filling
the maximum size of the too small disk image). This is expected
behaviour ofcourse.
But when I fix the disk image to the right size and start the migration
again, the migration fails immediately, the domain is -undefined- and
crashes. Qemu log showed:
kvm: block.c:2889: bdrv_set_in_use: Assertion `bs->in_use != in_use' failed.
2011-12-09 10:58:16.211: shutting down
Is this behaviour known to you guys?
Also, when I migrate a domain (10G qcow2 disk image, which is only used
for 1GB), the qcow2 image on the receiving end shows 10G for both
'virtual disk' and 'disk size', while this was 10G and 1G respectively
on the sending end. Why is the image expanded? Or is this a limitation
of the copy-storage-all?
How does the copy-storage-all function works for raw disk images? Does
it send incremental copies of blocks which are written too since the
migration is started?
Thanks in advance for your help!
Reinier Schoof
--
TransIP BV | https://www.transip.nl/
2
1
13 Dec '11
Hi,
Whether libvirt is ported to FreeBSD, if yes where can I find libvirt
source code for FreeBSD ?
Appreciate your help.
Thanks,
Chandrashekhar
2
3
13 Dec '11
---
python/generator.py | 1 +
python/libvirt-override-api.xml | 9 +++++++++
python/libvirt-override.c | 35 +++++++++++++++++++++++++++++++++++
3 files changed, 45 insertions(+), 0 deletions(-)
diff --git a/python/generator.py b/python/generator.py
index 88c52b9..1657f4f 100755
--- a/python/generator.py
+++ b/python/generator.py
@@ -262,6 +262,7 @@ py_types = {
'unsigned char *': ('z', None, "charPtr", "char *"),
'char *': ('z', None, "charPtr", "char *"),
'const char *': ('z', None, "charPtrConst", "const char *"),
+ 'size_t': ('n', None, "size_t", "size_t"),
'virDomainPtr': ('O', "virDomain", "virDomainPtr", "virDomainPtr"),
'const virDomainPtr': ('O', "virDomain", "virDomainPtr", "virDomainPtr"),
diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml
index 7c18763..87db67b 100644
--- a/python/libvirt-override-api.xml
+++ b/python/libvirt-override-api.xml
@@ -405,5 +405,14 @@
<arg name='flags' type='unsigned int' info='an OR'ed set of virDomainModificationImpact'/>
<return type='int' info='0 in case of success, -1 in case of failure'/>
</function>
+ <function name='virDomainBlockPeek' file='python'>
+ <info>Read the contents of domain's disk device</info>
+ <arg name='dom' type='virDomainPtr' info='pointer to the domain'/>
+ <arg name='disk' type='const char *' info='disk name'/>
+ <arg name='offset' type='unsigned long long' info='offset within block device'/>
+ <arg name='size' type='size_t' info='size to read'/>
+ <arg name='flags' type='unsigned int' info='unused, always passed 0'/>
+ <return type='char *' info='the returned buffer or None in case of error'/>
+ </function>
</symbols>
</api>
diff --git a/python/libvirt-override.c b/python/libvirt-override.c
index 9e98918..4839e08 100644
--- a/python/libvirt-override.c
+++ b/python/libvirt-override.c
@@ -5017,6 +5017,40 @@ libvirt_virDomainMigrateGetMaxSpeed(PyObject *self ATTRIBUTE_UNUSED, PyObject *a
return(py_retval);
}
+static PyObject *
+libvirt_virDomainBlockPeek(PyObject *self ATTRIBUTE_UNUSED,
+ PyObject *args) {
+ PyObject *py_retval;
+ int c_retval;
+ virDomainPtr domain;
+ PyObject *pyobj_domain;
+ const char *disk;
+ unsigned long long offset;
+ size_t size;
+ char *buf;
+ unsigned int flags;
+ int i;
+
+ if (!PyArg_ParseTuple(args, (char *)"OzLni:virDomainBlockPeek", &pyobj_domain,
+ &disk, &offset, &size, &flags))
+ return(NULL);
+
+ domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
+
+ if ((buf = malloc(size)) == NULL)
+ return VIR_PY_NONE;
+
+ LIBVIRT_BEGIN_ALLOW_THREADS;
+ c_retval = virDomainBlockPeek(domain, disk, offset, size, buf, flags);
+ LIBVIRT_END_ALLOW_THREADS;
+
+ if (c_retval < 0)
+ return VIR_PY_NONE;
+
+ py_retval = libvirt_charPtrWrap(buf);
+ return py_retval;
+}
+
/************************************************************************
* *
* The registration stuff *
@@ -5112,6 +5146,7 @@ static PyMethodDef libvirtMethods[] = {
{(char *) "virDomainGetBlockIoTune", libvirt_virDomainGetBlockIoTune, METH_VARARGS, NULL},
{(char *) "virDomainSendKey", libvirt_virDomainSendKey, METH_VARARGS, NULL},
{(char *) "virDomainMigrateGetMaxSpeed", libvirt_virDomainMigrateGetMaxSpeed, METH_VARARGS, NULL},
+ {(char *) "virDomainBlockPeek", libvirt_virDomainBlockPeek, METH_VARARGS, NULL},
{NULL, NULL, 0, NULL}
};
--
1.7.1
2
2
Hi,
I'd like to know if libvirt sends an event to audit system when a guest
is suspended.
I took a look at source code and I noticed that libvirt already have a
good support for auditing life cycle events, but I couldn't find any
events being sent to audit system when a guest is suspended.
Thanks,
Marcelo
2
1
Hi,
Actually udev renames the eth0 interface in guest to eth1 because
macvtap0 has different mac address then eth0 on host..
Is there some way so that we can prevent changing this rename of eth0 to
eth1 on guest. I don't want to change udev files.
________________________________
From: xhu [mailto:xhu@redhat.com]
Sent: Tuesday, December 13, 2011 3:01 PM
To: Amit Tewari
Cc: libvir-list(a)redhat.com
Subject: Re: [libvirt] macvtap not working on kvm
On 12/13/2011 12:59 PM, Amit Tewari wrote:
Hi all,
My test environment
Host os=rhel6.1
Guest os = rhel6.1
Libvirt=0.9.8
Kvm hypervisor
I have made this entry in guest xml file
<interface type='direct'>
<source dev='eth0' mode='bridge'/>
<model type='virtio'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03'
function='0x0'/>
</interface>
Now when I start the guest
#virsh start guest
Following macvtap0 is created on host and is shown below
#ip link show macvtap0
51: macvtap0@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq
state UNKNOWN qlen 500
link/ether 52:54:00:55:AE:B5brd ff:ff:ff:ff:ff:ff
but when the guest is up and I try to perform
# ifup eth0
It gives following message
"Bringing up interface eth0: Device eth0 does not seem to be present,
delaying initialization.
[FAILED]"
The interface name may change to ethN(N may be 1 or 2 ...) due to the
change of guest interface mac address.
You can log in guest and use command: "ip link show" to get the value
of N.
Then create ifcfg-ethN for it and use "ifup ethN" to start it in guest.
Guest eth interface does not create. What is the problem?
When I checked dmesg on host it gives following message-"macvatp0: ipv6
routers not present"
Please let me know how macvtap work on kvm.
DISCLAIMER:
------------------------------------------------------------------------
-----------------------------------------------
The contents of this e-mail and any attachment(s) are confidential and
intended
for the named recipient(s) only.
It shall not attach any liability on the originator or NECHCL or its
affiliates. Any views or opinions presented in
this email are solely those of the author and may not necessarily
reflect the
opinions of NECHCL or its affiliates.
Any form of reproduction, dissemination, copying, disclosure,
modification,
distribution and / or publication of
this message without the prior written consent of the author of this
e-mail is
strictly prohibited. If you have
received this email in error please delete it and notify the sender
immediately. .
------------------------------------------------------------------------
-----------------------------------------------
--
libvir-list mailing list
libvir-list(a)redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
DISCLAIMER:
-----------------------------------------------------------------------------------------------------------------------
The contents of this e-mail and any attachment(s) are confidential and
intended
for the named recipient(s) only.
It shall not attach any liability on the originator or NECHCL or its
affiliates. Any views or opinions presented in
this email are solely those of the author and may not necessarily reflect the
opinions of NECHCL or its affiliates.
Any form of reproduction, dissemination, copying, disclosure, modification,
distribution and / or publication of
this message without the prior written consent of the author of this e-mail is
strictly prohibited. If you have
received this email in error please delete it and notify the sender
immediately. .
-----------------------------------------------------------------------------------------------------------------------
1
0
Hi all,
My test environment
Host os=rhel6.1
Guest os = rhel6.1
Libvirt=0.9.8
Kvm hypervisor
I have made this entry in guest xml file
<interface type='direct'>
<source dev='eth0' mode='bridge'/>
<model type='virtio'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03'
function='0x0'/>
</interface>
Now when I start the guest
#virsh start guest
Following macvtap0 is created on host and is shown below
#ip link show macvtap0
51: macvtap0@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq
state UNKNOWN qlen 500
link/ether 52:54:00:55:AE:B5brd ff:ff:ff:ff:ff:ff
but when the guest is up and I try to perform
# ifup eth0
It gives following message
"Bringing up interface eth0: Device eth0 does not seem to be present,
delaying initialization.
[FAILED]"
Guest eth interface does not create. What is the problem?
When I checked dmesg on host it gives following message-"macvatp0: ipv6
routers not present"
Please let me know how macvtap work on kvm.
DISCLAIMER:
-----------------------------------------------------------------------------------------------------------------------
The contents of this e-mail and any attachment(s) are confidential and
intended
for the named recipient(s) only.
It shall not attach any liability on the originator or NECHCL or its
affiliates. Any views or opinions presented in
this email are solely those of the author and may not necessarily reflect the
opinions of NECHCL or its affiliates.
Any form of reproduction, dissemination, copying, disclosure, modification,
distribution and / or publication of
this message without the prior written consent of the author of this e-mail is
strictly prohibited. If you have
received this email in error please delete it and notify the sender
immediately. .
-----------------------------------------------------------------------------------------------------------------------
2
1
13 Dec '11
From: Alex Jia <ajia(a)redhat.com>
Detected by valgrind. Leak introduced in commit 82ff25e.
* tests/nodeinfotest.c: avoid memory leak on nodeinfo test case.
* how to reproduce?
% cd tests && valgrind -v --leak-check=full ./nodeinfotest
* actual valgrind result:
==22147== 65 bytes in 1 blocks are definitely lost in loss record 14 of 29
==22147== at 0x4A0610F: realloc (vg_replace_malloc.c:525)
==22147== by 0x330D6FED94: __vasprintf_chk (in /lib64/libc-2.12.so)
==22147== by 0x426697: virVasprintf (stdio2.h:199)
==22147== by 0x426757: virAsprintf (util.c:1695)
==22147== by 0x41585F: linuxTestNodeInfo (nodeinfotest.c:108)
==22147== by 0x416B21: virtTestRun (testutils.c:141)
==22147== by 0x4157EA: mymain (nodeinfotest.c:140)
==22147== by 0x416217: virtTestMain (testutils.c:696)
==22147== by 0x330D61ECDC: (below main) (in /lib64/libc-2.12.so)
==22147==
==22147== LEAK SUMMARY:
==22147== definitely lost: 65 bytes in 1 blocks
==22147== indirectly lost: 0 bytes in 0 blocks
==22147== possibly lost: 0 bytes in 0 blocks
==22147== still reachable: 126,126 bytes in 1,341 blocks
Signed-off-by: Alex Jia <ajia(a)redhat.com>
---
tests/nodeinfotest.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/tests/nodeinfotest.c b/tests/nodeinfotest.c
index 74f7b47..0952a6b 100644
--- a/tests/nodeinfotest.c
+++ b/tests/nodeinfotest.c
@@ -119,6 +119,7 @@ linuxTestNodeInfo(const void *data)
cleanup:
free(cpuinfo);
free(output);
+ free(sysfs_cpuinfo);
return result;
}
--
1.7.1
2
1
[libvirt] add a qemu-specific event register API, to passthough the new events come from qemu
by shaohefï¼ linux.vnet.ibm.com 13 Dec '11
by shaohefï¼ linux.vnet.ibm.com 13 Dec '11
13 Dec '11
From: Shao He Feng <shaohef(a)linux.vnet.ibm.com>
Basically, this feature can go along with qemu monitor passthrough.
That way, if we use new commands in the monitor that generate new events, we want some way to receive those new events too.
In order to test this patch, see the attached python test case. When domains are started, it will be able to catch RESUME events.
Signed-off-by: Shao He Feng <shaohef(a)linux.vnet.ibm.com>
---
daemon/libvirtd.h | 12 +-
daemon/remote.c | 195 ++++++++++++++++++-
include/libvirt/libvirt-qemu.h | 11 +
include/libvirt/libvirt.h.in | 17 ++-
python/generator.py | 26 ++-
python/libvirt-override-virConnect.py | 14 ++-
python/libvirt-qemu-override.c | 140 +++++++++++++
python/libvirt-qemu-override.py | 41 ++++
src/conf/domain_event.c | 347 +++++++++++++++++++++++++++++++--
src/conf/domain_event.h | 49 +++++-
src/driver.h | 14 ++
src/libvirt-qemu.c | 190 ++++++++++++++++++
src/libvirt_private.syms | 6 +
src/libvirt_qemu.syms | 5 +
src/qemu/qemu_driver.c | 42 ++++
src/qemu/qemu_monitor.c | 10 +
src/qemu/qemu_monitor.h | 8 +
src/qemu/qemu_monitor_json.c | 36 ++++
src/qemu/qemu_process.c | 24 +++
src/remote/qemu_protocol.x | 33 +++-
src/remote/remote_driver.c | 153 ++++++++++++++-
src/remote/remote_protocol.x | 9 +-
src/remote_protocol-structs | 5 +
23 files changed, 1353 insertions(+), 34 deletions(-)
mode change 100644 => 100755 python/libvirt-override-virConnect.py
mode change 100644 => 100755 python/libvirt-override-virStream.py
mode change 100644 => 100755 python/libvirt-override.py
create mode 100644 python/libvirt-qemu-override.py
diff --git a/daemon/libvirtd.h b/daemon/libvirtd.h
index c8d3ca2..e3e1c40 100644
--- a/daemon/libvirtd.h
+++ b/daemon/libvirtd.h
@@ -38,6 +38,16 @@
# endif
# include "virnetserverprogram.h"
+/* limit the number unknow event of an conncet can register */
+#define VIR_DOMAIN_EVENT_NAME_LAST 512
+struct domainEventNameCallBackStatus {
+ /* counter the number of unknow event registered */
+ int eventNameCallBackCounter;
+ /* Stores the ID of the unknow event registered */
+ int eventNameCallback[VIR_DOMAIN_EVENT_NAME_LAST];
+};
+typedef struct domainEventNameCallBackStatus domainEventNameCallBackStatus;
+
typedef struct daemonClientStream daemonClientStream;
typedef daemonClientStream *daemonClientStreamPtr;
typedef struct daemonClientPrivate daemonClientPrivate;
@@ -49,7 +59,7 @@ struct daemonClientPrivate {
virMutex lock;
int domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LAST];
-
+ domainEventNameCallBackStatus domainEventNameCallBack;
# if HAVE_SASL
virNetSASLSessionPtr sasl;
# endif
diff --git a/daemon/remote.c b/daemon/remote.c
index e1d208c..bc8455d 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -421,6 +421,54 @@ mem_error:
return -1;
}
+static int remoteRelayDomainEventUnknown(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virDomainPtr dom,
+ const char *eventName, /* The JSON event name */
+ const char *eventArgs, /* The JSON string of args */
+ void *opaque)
+{
+ virNetServerClientPtr client = opaque;
+ remote_domain_event_default_event_msg data;
+
+ if (!client)
+ return -1;
+
+ VIR_DEBUG("Relaying domain: %s id: %d, unknown event: %s arguments: %s",
+ dom->name, dom->id, eventName, eventArgs);
+
+ /* build return data */
+ memset(&data, 0, sizeof data);
+ if (eventName == NULL)
+ goto mem_error3;
+ data.eventName = (char *)strdup(eventName);
+ if (data.eventName == NULL)
+ goto mem_error2;
+ if (eventArgs != NULL) {
+ data.eventArgs = (char *)strdup(eventArgs);
+ if (data.eventArgs == NULL)
+ goto mem_error1;
+ }
+ else {
+ data.eventArgs = (char *)strdup("NULL");
+ if (data.eventArgs == NULL)
+ goto mem_error1;
+ }
+ make_nonnull_domain(&data.dom, dom);
+ remoteDispatchDomainEventSend(client, remoteProgram,
+ REMOTE_PROC_QEMU_DOMAIN_EVENT_UNKNOWN_EVENT,
+ (xdrproc_t)xdr_remote_domain_event_default_event_msg, &data);
+
+ return 0;
+
+mem_error1:
+ VIR_FREE(data.eventArgs);
+mem_error2:
+ VIR_FREE(data.eventName);
+mem_error3:
+ virReportOOMError();
+ return -1;
+}
+
static int remoteRelayDomainEventControlError(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainPtr dom,
@@ -509,6 +557,7 @@ static virConnectDomainEventGenericCallback domainEventCallbacks[] = {
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventControlError),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBlockJob),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDiskChange),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventUnknown),
};
verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST);
@@ -526,10 +575,21 @@ static void remoteClientFreeFunc(void *data)
/* Deregister event delivery callback */
if (priv->conn) {
- int i;
+ int i, j;
for (i = 0 ; i < VIR_DOMAIN_EVENT_ID_LAST ; i++) {
- if (priv->domainEventCallbackID[i] != -1) {
+ if (i == VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN && priv->domainEventCallbackID[i] != -1) {
+ for (j = 0 ; j < VIR_DOMAIN_EVENT_NAME_LAST ; j++){
+ if (priv->domainEventNameCallBack.eventNameCallback[j] != -1) {
+ VIR_DEBUG("Deregistering to relay remote events %d", i);
+ virConnectDomainQemuEventDeregister(priv->conn,
+ priv->domainEventNameCallBack.eventNameCallback[j]);
+ }
+ priv->domainEventNameCallBack.eventNameCallback[j] == -1;
+ }
+ priv->domainEventNameCallBack.eventNameCallBackCounter = 0;
+ }
+ else if (priv->domainEventCallbackID[i] != -1) {
VIR_DEBUG("Deregistering to relay remote events %d", i);
virConnectDomainEventDeregisterAny(priv->conn,
priv->domainEventCallbackID[i]);
@@ -572,6 +632,10 @@ int remoteClientInitHook(virNetServerPtr srv ATTRIBUTE_UNUSED,
for (i = 0 ; i < VIR_DOMAIN_EVENT_ID_LAST ; i++)
priv->domainEventCallbackID[i] = -1;
+ priv->domainEventNameCallBack.eventNameCallBackCounter = 0;
+ for (i = 0 ; i < VIR_DOMAIN_EVENT_NAME_LAST ; i++)
+ priv->domainEventNameCallBack.eventNameCallback[i] = -1;
+
virNetServerClientSetPrivateData(client, priv,
remoteClientFreeFunc);
virNetServerClientSetCloseHook(client, remoteClientCloseFunc);
@@ -2991,6 +3055,133 @@ cleanup:
}
static int
+qemuDispatchDomainEventsRegister(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ qemu_domain_events_register_args *args,
+ qemu_domain_events_register_ret *ret ATTRIBUTE_UNUSED)
+{
+ int callbackID = -1;
+ int rv = -1;
+ int eventIdx = 0;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+ if (!priv->conn) {
+ virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ virMutexLock(&priv->lock);
+
+ if (args->eventName == NULL) {
+ virNetError(VIR_ERR_INTERNAL_ERROR, _("event Name is NULL"));
+ goto cleanup;
+ }
+ if (priv->domainEventNameCallBack.eventNameCallBackCounter >= VIR_DOMAIN_EVENT_NAME_LAST) {
+ virNetError(VIR_ERR_INTERNAL_ERROR,
+ _("domain event %s is not registered, the register number has exceeded limit number %d"),
+ args->eventName,
+ VIR_DOMAIN_EVENT_NAME_LAST);
+ goto cleanup;
+ }
+
+ if ((callbackID = virConnectDomainQemuEventRegister(priv->conn,
+ NULL,
+ args->eventName,
+ (virConnectDomainQemuEventCallback)remoteRelayDomainEventUnknown,
+ client,
+ NULL)) < 0)
+ goto cleanup;
+
+ for (eventIdx = 0 ; eventIdx < VIR_DOMAIN_EVENT_NAME_LAST ; eventIdx++) {
+ if (priv->domainEventNameCallBack.eventNameCallback[eventIdx] == -1) {
+ priv->domainEventNameCallBack.eventNameCallback[eventIdx] = callbackID;
+ priv->domainEventNameCallBack.eventNameCallBackCounter++;
+ ret->callbackID = eventIdx;
+ break;
+ }
+ }
+ priv->domainEventCallbackID[VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN] = callbackID;
+
+ rv = 0;
+
+cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virMutexUnlock(&priv->lock);
+ return rv;
+}
+
+static int
+remoteDispatchQemuDomainEventUnknownEvent(virNetServerPtr server,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg,
+ virNetMessageErrorPtr rerr)
+{
+ int rv = -1;
+ return rv;
+}
+
+static int
+qemuDispatchDomainEventsUnknownEvent(virNetServerPtr server,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg,
+ virNetMessageErrorPtr rerr,
+ qemu_domain_events_unknown_event_args *args,
+ qemu_domain_events_unknown_event_ret *ret)
+{
+ int rv = -1;
+ return rv;
+}
+
+static int
+qemuDispatchDomainEventsDeregister(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ qemu_domain_events_deregister_args *args,
+ qemu_domain_events_deregister_ret *ret ATTRIBUTE_UNUSED)
+{
+ int callbackID = -1;
+ int rv = -1;
+ int eventIdx = args->callbackID;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ virMutexLock(&priv->lock);
+
+ if (eventIdx >= VIR_DOMAIN_EVENT_NAME_LAST ||
+ (callbackID = priv->domainEventNameCallBack.eventNameCallback[eventIdx]) < 0) {
+
+ virNetError(VIR_ERR_INTERNAL_ERROR, _("callbakcID %d is not register"), eventIdx);
+ goto cleanup;
+ }
+
+ if (virConnectDomainQemuEventDeregister(priv->conn, callbackID) < 0)
+ goto cleanup;
+ ret->cb_deregistered = callbackID;
+
+ priv->domainEventNameCallBack.eventNameCallback[eventIdx] = -1;
+ priv->domainEventNameCallBack.eventNameCallBackCounter--;
+ if (priv->domainEventNameCallBack.eventNameCallBackCounter == 0)
+ priv->domainEventCallbackID[VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN] = -1;
+
+ rv = 0;
+
+cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virMutexUnlock(&priv->lock);
+ return rv;
+}
+
+static int
qemuDispatchMonitorCommand(virNetServerPtr server ATTRIBUTE_UNUSED,
virNetServerClientPtr client ATTRIBUTE_UNUSED,
virNetMessagePtr msg ATTRIBUTE_UNUSED,
diff --git a/include/libvirt/libvirt-qemu.h b/include/libvirt/libvirt-qemu.h
index 7f12e4f..74efe79 100644
--- a/include/libvirt/libvirt-qemu.h
+++ b/include/libvirt/libvirt-qemu.h
@@ -32,6 +32,17 @@ virDomainPtr virDomainQemuAttach(virConnectPtr domain,
unsigned int pid,
unsigned int flags);
+int
+virConnectDomainQemuEventRegister(virConnectPtr conn,
+ virDomainPtr dom, /* option to filter */
+ const char *eventName, /* JSON event name */
+ virConnectDomainQemuEventCallback cb,
+ void *opaque,
+ virFreeCallback freecb);
+int
+virConnectDomainQemuEventDeregister(virConnectPtr conn,
+ int callbackID);
+
# ifdef __cplusplus
}
# endif
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 2480add..99e1c5d 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -3207,7 +3207,21 @@ typedef void (*virConnectDomainEventBlockJobCallback)(virConnectPtr conn,
int type,
int status,
void *opaque);
-
+/**
+ * virConnectDomainQemuEventCallback:
+ * @conn: connection object
+ * @dom: domain on which the event occurred
+ * @eventName : the name of the unknow or un-implementation event
+ * @eventArgs: the content of the unknow or un-implementation event
+ *
+ * The callback signature to use when registering for an event of type
+ * VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN with virConnectDomainQemuEventRegister()
+ */
+typedef void (*virConnectDomainQemuEventCallback)(virConnectPtr conn,
+ virDomainPtr dom,
+ const char *eventName, /* The JSON event name */
+ const char *eventArgs, /* The JSON string of args */
+ void *opaque);
/**
* virConnectDomainEventDiskChangeReason:
*
@@ -3263,6 +3277,7 @@ typedef enum {
VIR_DOMAIN_EVENT_ID_CONTROL_ERROR = 7, /* virConnectDomainEventGenericCallback */
VIR_DOMAIN_EVENT_ID_BLOCK_JOB = 8, /* virConnectDomainEventBlockJobCallback */
VIR_DOMAIN_EVENT_ID_DISK_CHANGE = 9, /* virConnectDomainEventDiskChangeCallback */
+ VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN = 10, /* virConnectDomainEventDefaultCallback */
/*
* NB: this enum value will increase over time as new events are
diff --git a/python/generator.py b/python/generator.py
index 88c52b9..3d13622 100755
--- a/python/generator.py
+++ b/python/generator.py
@@ -234,6 +234,7 @@ skipped_types = {
# 'int *': "usually a return type",
'virConnectDomainEventCallback': "No function types in python",
'virConnectDomainEventGenericCallback': "No function types in python",
+ 'virConnectDomainQemuEventCallback': "No function types in python",
'virConnectDomainEventRTCChangeCallback': "No function types in python",
'virConnectDomainEventWatchdogCallback': "No function types in python",
'virConnectDomainEventIOErrorCallback': "No function types in python",
@@ -476,6 +477,8 @@ skip_function = (
qemu_skip_function = (
#"virDomainQemuAttach",
+ 'virConnectDomainQemuEventRegister', # overridden in libvirt_qemu_override.py
+ 'virConnectDomainQemuEventDeregister', # overridden in libvirt_qemu_override.py
)
# Generate C code, but skip python impl
@@ -1656,17 +1659,18 @@ def qemuBuildWrappers(module):
if extra != None:
extra.close()
- fd.write("try:\n")
- fd.write(" import libvirtmod_qemu\n")
- fd.write("except ImportError, lib_e:\n")
- fd.write(" try:\n")
- fd.write(" import cygvirtmod_qemu as libvirtmod_qemu\n")
- fd.write(" except ImportError, cyg_e:\n")
- fd.write(" if str(cyg_e).count(\"No module named\"):\n")
- fd.write(" raise lib_e\n\n")
-
- fd.write("import libvirt\n\n");
- fd.write("#\n# Functions from module %s\n#\n\n" % module)
+ if extra == None:
+ fd.write("try:\n")
+ fd.write(" import libvirtmod_qemu\n")
+ fd.write("except ImportError, lib_e:\n")
+ fd.write(" try:\n")
+ fd.write(" import cygvirtmod_qemu as libvirtmod_qemu\n")
+ fd.write(" except ImportError, cyg_e:\n")
+ fd.write(" if str(cyg_e).count(\"No module named\"):\n")
+ fd.write(" raise lib_e\n\n")
+
+ fd.write("import libvirt\n\n");
+ fd.write("#\n# Functions from module %s\n#\n\n" % module)
#
# Generate functions directly, no classes
#
diff --git a/python/libvirt-override-virConnect.py b/python/libvirt-override-virConnect.py
old mode 100644
new mode 100755
index b908b32..ce34bcf
--- a/python/libvirt-override-virConnect.py
+++ b/python/libvirt-override-virConnect.py
@@ -134,8 +134,20 @@
cb(self, virDomain(self, _obj=dom), oldSrcPath, newSrcPath, devAlias, reason, opaque)
return 0;
+ def _dispatchDomainEventUnknownCallback(self, dom, eventName, eventArgs, cbData):
+ """Dispatches events to python user unknown event callbacks
+ """
+ try:
+ cb = cbData["cb"]
+ opaque = cbData["opaque"]
+
+ cb(self, virDomain(self, _obj=dom), eventName, eventArgs, opaque)
+ return 0
+ except AttributeError:
+ pass
+
def domainEventDeregisterAny(self, callbackID):
- """Removes a Domain Event Callback. De-registering for a
+ """Removes a QEMU Domain Event Callback. De-registering for a
domain callback will disable delivery of this event type """
try:
ret = libvirtmod.virConnectDomainEventDeregisterAny(self._o, callbackID)
diff --git a/python/libvirt-override-virStream.py b/python/libvirt-override-virStream.py
old mode 100644
new mode 100755
diff --git a/python/libvirt-override.py b/python/libvirt-override.py
old mode 100644
new mode 100755
diff --git a/python/libvirt-qemu-override.c b/python/libvirt-qemu-override.c
index 485c809..f5a8c09 100644
--- a/python/libvirt-qemu-override.c
+++ b/python/libvirt-qemu-override.c
@@ -18,6 +18,7 @@
#include <Python.h>
#include "libvirt/libvirt-qemu.h"
+#include "libvirt/libvirt.h"
#include "libvirt/virterror.h"
#include "typewrappers.h"
#include "libvirt-qemu.h"
@@ -96,6 +97,143 @@ libvirt_qemu_virDomainQemuMonitorCommand(PyObject *self ATTRIBUTE_UNUSED,
return(py_retval);
}
+static void
+libvirt_qemu_virConnectDomainEventFreeFunc(void *opaque)
+{
+ PyObject *pyobj_conn = (PyObject*)opaque;
+ LIBVIRT_ENSURE_THREAD_STATE;
+ Py_DECREF(pyobj_conn);
+ LIBVIRT_RELEASE_THREAD_STATE;
+}
+
+static int
+libvirt_qemu_virConnectDomainEventUnknownCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virDomainPtr dom,
+ const char *eventName,
+ const char *eventArgs,
+ void *opaque)
+{
+ PyObject *pyobj_cbData = (PyObject*)opaque;
+ PyObject *pyobj_dom;
+ PyObject *pyobj_ret;
+ PyObject *pyobj_conn;
+ PyObject *dictKey;
+ int ret = -1;
+
+ LIBVIRT_ENSURE_THREAD_STATE;
+
+ /* Create a python instance of this virDomainPtr */
+ virDomainRef(dom);
+ pyobj_dom = libvirt_virDomainPtrWrap(dom);
+ Py_INCREF(pyobj_cbData);
+
+ dictKey = libvirt_constcharPtrWrap("conn");
+ pyobj_conn = PyDict_GetItem(pyobj_cbData, dictKey);
+ Py_DECREF(dictKey);
+
+ /* Call the Callback Dispatcher */
+ pyobj_ret = PyObject_CallMethod(pyobj_conn,
+ (char*)"_dispatchDomainEventUnknownCallback",
+ (char*)"OssO",
+ pyobj_dom, eventName, eventArgs, pyobj_cbData);
+
+ Py_DECREF(pyobj_cbData);
+ Py_DECREF(pyobj_dom);
+
+ if (!pyobj_ret) {
+#if DEBUG_ERROR
+ printf("%s - ret:%p\n", __FUNCTION__, pyobj_ret);
+#endif
+ PyErr_Print();
+ } else {
+ Py_DECREF(pyobj_ret);
+ ret = 0;
+ }
+
+ LIBVIRT_RELEASE_THREAD_STATE;
+ return ret;
+}
+
+static PyObject *
+libvirt_qemu_virConnectDomainQemuEventRegister(ATTRIBUTE_UNUSED PyObject * self,
+ PyObject * args)
+{
+ PyObject *py_retval; /* return value */
+ PyObject *pyobj_conn; /* virConnectPtr */
+ PyObject *pyobj_dom;
+ PyObject *pyobj_cbData; /* hash of callback data */
+ char *eventName;
+ virConnectPtr conn;
+ int ret = 0;
+
+ virConnectDomainQemuEventCallback cb = NULL;
+ virDomainPtr dom;
+
+ if (!PyArg_ParseTuple
+ (args, (char *) "OOsO:virConnectDomainQemuEventRegister",
+ &pyobj_conn, &pyobj_dom, &eventName, &pyobj_cbData)) {
+ DEBUG("%s failed parsing tuple\n", __FUNCTION__);
+ return VIR_PY_INT_FAIL;
+ }
+
+ if (eventName == NULL)
+ return VIR_PY_INT_FAIL;
+
+ DEBUG("libvirt_qemu_virConnectDomainQemuEventRegister(%p %p %s %p) called\n",
+ pyobj_conn, pyobj_dom, eventName, pyobj_cbData);
+ conn = PyvirConnect_Get(pyobj_conn);
+ if (pyobj_dom == Py_None)
+ dom = NULL;
+ else
+ dom = PyvirDomain_Get(pyobj_dom);
+
+ cb = (virConnectDomainQemuEventCallback)(libvirt_qemu_virConnectDomainEventUnknownCallback);
+ if (!cb) {
+ return VIR_PY_INT_FAIL;
+ }
+
+ Py_INCREF(pyobj_cbData);
+
+ LIBVIRT_BEGIN_ALLOW_THREADS;
+ ret = virConnectDomainQemuEventRegister(conn, dom, eventName,
+ cb, pyobj_cbData,
+ libvirt_qemu_virConnectDomainEventFreeFunc);
+ LIBVIRT_END_ALLOW_THREADS;
+ if (ret < 0) {
+ Py_DECREF(pyobj_cbData);
+ }
+ py_retval = libvirt_intWrap(ret);
+ return (py_retval);
+}
+
+static PyObject *
+libvirt_qemu_virConnectDomainQemuEventDeregister(ATTRIBUTE_UNUSED PyObject * self,
+ PyObject * args)
+{
+ PyObject *py_retval;
+ PyObject *pyobj_conn;
+ int callbackID;
+ virConnectPtr conn;
+ int ret = 0;
+
+ if (!PyArg_ParseTuple
+ (args, (char *) "Oi:virConnectDomainQemuEventDeregister",
+ &pyobj_conn, &callbackID))
+ return (NULL);
+
+ DEBUG("libvirt_qemu_virConnectDomainQemuEventDeregister(%p) called\n", pyobj_conn);
+
+ conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn);
+
+ LIBVIRT_BEGIN_ALLOW_THREADS;
+
+ ret = virConnectDomainQemuEventDeregister(conn, callbackID);
+
+ LIBVIRT_END_ALLOW_THREADS;
+ py_retval = libvirt_intWrap(ret);
+ return (py_retval);
+}
+
/************************************************************************
* *
* The registration stuff *
@@ -104,6 +242,8 @@ libvirt_qemu_virDomainQemuMonitorCommand(PyObject *self ATTRIBUTE_UNUSED,
static PyMethodDef libvirtQemuMethods[] = {
#include "libvirt-qemu-export.c"
{(char *) "virDomainQemuMonitorCommand", libvirt_qemu_virDomainQemuMonitorCommand, METH_VARARGS, NULL},
+ {(char *) "virConnectDomainQemuEventRegister", libvirt_qemu_virConnectDomainQemuEventRegister, METH_VARARGS, NULL},
+ {(char *) "virConnectDomainQemuEventDeregister", libvirt_qemu_virConnectDomainQemuEventDeregister, METH_VARARGS, NULL},
{NULL, NULL, 0, NULL}
};
diff --git a/python/libvirt-qemu-override.py b/python/libvirt-qemu-override.py
new file mode 100644
index 0000000..0f5694c
--- /dev/null
+++ b/python/libvirt-qemu-override.py
@@ -0,0 +1,41 @@
+#
+# Manually written part of python bindings for libvirt_qemu
+#
+
+# On cygwin, the DLL is called cygvirtmod.dll
+try:
+ import libvirtmod_qemu
+except ImportError, lib_e:
+ try:
+ import cygvirtmod_qemu as libvirtmod_qemu
+ except ImportError, cyg_e:
+ if str(cyg_e).count("No module named"):
+ raise lib_e
+
+import libvirt
+import types
+
+def domainQemuEventDeregister(conn, callbackID):
+ """Removes a Domain Event Callback. De-registering for a
+ domain callback will disable delivery of this event type """
+ try:
+ ret = libvirtmod_qemu.virConnectDomainQemuEventDeregister(conn._o, callbackID)
+ if ret == -1: raise libvirt.libvirtError ('virConnectDomainQemuEventDeregister() failed', conn)
+ del conn.domainEventCallbackID[callbackID]
+ except AttributeError:
+ pass
+
+def domainQemuEventRegister(conn, dom, eventName, cb, opaque):
+ """Adds a Domain Event Callback. Registering for a domain
+ callback will enable delivery of the events """
+ if not hasattr(conn, 'domainEventCallbackID'):
+ conn.domainEventCallbackID = {}
+ cbData = { "cb": cb, "conn": conn, "opaque": opaque }
+ if dom is None:
+ ret = libvirtmod_qemu.virConnectDomainQemuEventRegister(conn._o, None, eventName, cbData)
+ else:
+ ret = libvirtmod_qemu.virConnectDomainQemuEventRegister(conn._o, dom._o, eventName, cbData)
+ if ret == -1:
+ raise libvirt.libvirtError ('virConnectDomainQemuEventRegister() failed', conn)
+ conn.domainEventCallbackID[ret] = opaque
+ return ret
diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c
index 614ab97..b6a763a 100644
--- a/src/conf/domain_event.c
+++ b/src/conf/domain_event.c
@@ -45,7 +45,9 @@ typedef virDomainMeta *virDomainMetaPtr;
struct _virDomainEventCallback {
int callbackID;
+ int qemuCallbackID;
int eventID;
+ char *eventName;
virConnectPtr conn;
virDomainMetaPtr dom;
virConnectDomainEventGenericCallback cb;
@@ -94,6 +96,10 @@ struct _virDomainEvent {
char *devAlias;
int reason;
} diskChange;
+ struct {
+ char *eventName;
+ char *eventArgs;
+ }qemuUnknownEvent;
} data;
};
@@ -112,6 +118,8 @@ virDomainEventCallbackListFree(virDomainEventCallbackListPtr list)
for (i=0; i<list->count; i++) {
virFreeCallback freecb = list->callbacks[i]->freecb;
+ if (list->callbacks[i]->eventName)
+ VIR_FREE(list->callbacks[i]->eventName);
if (freecb)
(*freecb)(list->callbacks[i]->opaque);
VIR_FREE(list->callbacks[i]);
@@ -143,7 +151,6 @@ virDomainEventCallbackListRemove(virConnectPtr conn,
(*freecb)(cbList->callbacks[i]->opaque);
virUnrefConnect(cbList->callbacks[i]->conn);
VIR_FREE(cbList->callbacks[i]);
-
if (i < (cbList->count - 1))
memmove(cbList->callbacks + i,
cbList->callbacks + i + 1,
@@ -187,8 +194,11 @@ virDomainEventCallbackListRemoveID(virConnectPtr conn,
if (freecb)
(*freecb)(cbList->callbacks[i]->opaque);
virUnrefConnect(cbList->callbacks[i]->conn);
+ if (cbList->callbacks[i]->eventID == VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN) {
+ if (cbList->callbacks[i]->eventName)
+ VIR_FREE(cbList->callbacks[i]->eventName);
+ }
VIR_FREE(cbList->callbacks[i]);
-
if (i < (cbList->count - 1))
memmove(cbList->callbacks + i,
cbList->callbacks + i + 1,
@@ -212,6 +222,52 @@ virDomainEventCallbackListRemoveID(virConnectPtr conn,
/**
+ * virDomainQemuEventCallbackListRemoveID:
+ * @conn: pointer to the connection
+ * @cbList: the list
+ * @callback: the callback to remove
+ *
+ * Internal function to remove a callback from a virDomainEventCallbackListPtr
+ */
+int
+virDomainQemuEventCallbackListRemoveID(virConnectPtr conn,
+ virDomainEventCallbackListPtr cbList,
+ int callbackID)
+{
+ int i;
+ for (i = 0 ; i < cbList->count ; i++) {
+ if (cbList->callbacks[i]->callbackID == callbackID &&
+ cbList->callbacks[i]->conn == conn &&
+ cbList->callbacks[i]->eventID == VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN) {
+ virFreeCallback freecb = cbList->callbacks[i]->freecb;
+ if (freecb)
+ (*freecb)(cbList->callbacks[i]->opaque);
+ VIR_FREE(cbList->callbacks[i]->eventName);
+ virUnrefConnect(cbList->callbacks[i]->conn);
+ VIR_FREE(cbList->callbacks[i]);
+
+ if (i < (cbList->count - 1))
+ memmove(cbList->callbacks + i,
+ cbList->callbacks + i + 1,
+ sizeof(*(cbList->callbacks)) *
+ (cbList->count - (i + 1)));
+
+ if (VIR_REALLOC_N(cbList->callbacks,
+ cbList->count - 1) < 0) {
+ ; /* Failure to reduce memory allocation isn't fatal */
+ }
+ cbList->count--;
+ return 0;
+ }
+ }
+
+ eventReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("could not find event callback for removal"));
+ return -1;
+}
+
+
+/**
* virDomainEventCallbackListRemoveConn:
* @conn: pointer to the connection
* @cbList: the list
@@ -231,8 +287,11 @@ virDomainEventCallbackListRemoveConn(virConnectPtr conn,
if (freecb)
(*freecb)(cbList->callbacks[i]->opaque);
virUnrefConnect(cbList->callbacks[i]->conn);
+ if (cbList->callbacks[i]->eventID == VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN) {
+ if (cbList->callbacks[i]->eventName)
+ VIR_FREE(cbList->callbacks[i]->eventName);
+ }
VIR_FREE(cbList->callbacks[i]);
-
if (i < (cbList->count - 1))
memmove(cbList->callbacks + i,
cbList->callbacks + i + 1,
@@ -299,8 +358,11 @@ int virDomainEventCallbackListPurgeMarked(virDomainEventCallbackListPtr cbList)
if (freecb)
(*freecb)(cbList->callbacks[i]->opaque);
virUnrefConnect(cbList->callbacks[i]->conn);
+ if (cbList->callbacks[i]->eventID == VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN) {
+ if (cbList->callbacks[i]->eventName)
+ VIR_FREE(cbList->callbacks[i]->eventName);
+ }
VIR_FREE(cbList->callbacks[i]);
-
if (i < (cbList->count - 1))
memmove(cbList->callbacks + i,
cbList->callbacks + i + 1,
@@ -404,7 +466,98 @@ virDomainEventCallbackListAddID(virConnectPtr conn,
cbList->callbacks[cbList->count] = event;
cbList->count++;
+ event->callbackID = cbList->nextID++;
+
+ return event->callbackID;
+
+no_memory:
+ virReportOOMError();
+
+ if (event) {
+ if (event->dom)
+ VIR_FREE(event->dom->name);
+ VIR_FREE(event->dom);
+ }
+ VIR_FREE(event);
+ return -1;
+}
+
+
+
+/**
+ * virDomainEventCallbackListAddName:
+ * @conn: pointer to the connection
+ * @cbList: the list
+ * @eventName: the event eventName
+ * @callback: the callback to add
+ * @eventID: the specific eventID
+ * @opaque: opaque data tio pass to callback
+ *
+ * Internal function to add a callback from a virDomainEventCallbackListPtr
+ */
+int
+virDomainEventCallbackListAddName(virConnectPtr conn,
+ virDomainEventCallbackListPtr cbList,
+ virDomainPtr dom,
+ const char* eventName,
+ int eventID,
+ virConnectDomainEventGenericCallback callback,
+ void *opaque,
+ virFreeCallback freecb)
+{
+ virDomainEventCallbackPtr event;
+ int i;
+
+ /* Check incoming */
+ if ( !cbList ) {
+ return -1;
+ }
+
+ /* check if we already have this callback on our list */
+ for (i = 0 ; i < cbList->count ; i++) {
+ if (cbList->callbacks[i]->cb == VIR_DOMAIN_EVENT_CALLBACK(callback) &&
+ !strcmp(cbList->callbacks[i]->eventName, eventName) &&
+ cbList->callbacks[i]->eventID == eventID &&
+ cbList->callbacks[i]->conn == conn) {
+ eventReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("event callback already tracked"));
+ return -1;
+ }
+ }
+ if (eventID > VIR_DOMAIN_EVENT_ID_LAST || eventID < VIR_DOMAIN_EVENT_ID_LIFECYCLE) {
+ eventReportError(VIR_ERR_INTERNAL_ERROR, "%s: %d",
+ _("not suport this kind of eventID"), eventID);
+ }
+ /* Allocate new event */
+ if (VIR_ALLOC(event) < 0)
+ goto no_memory;
+ event->conn = conn;
+ event->cb = callback;
+ if (eventName == NULL)
+ goto no_memory;
+ event->eventName = strdup(eventName);
+ if ( event->eventName == NULL)
+ goto no_memory;
+ event->opaque = opaque;
+ event->freecb = freecb;
+ event->eventID = eventID;
+ if (dom) {
+ if (VIR_ALLOC(event->dom) < 0)
+ goto no_memory;
+ if (!(event->dom->name = strdup(dom->name)))
+ goto no_memory;
+ memcpy(event->dom->uuid, dom->uuid, VIR_UUID_BUFLEN);
+ event->dom->id = dom->id;
+ }
+
+ /* Make space on list */
+ if (VIR_REALLOC_N(cbList->callbacks, cbList->count + 1) < 0)
+ goto no_memory;
+
+ event->conn->refs++;
+ cbList->callbacks[cbList->count] = event;
+ cbList->count++;
event->callbackID = cbList->nextID++;
return event->callbackID;
@@ -416,11 +569,41 @@ no_memory:
if (event->dom)
VIR_FREE(event->dom->name);
VIR_FREE(event->dom);
+ if (event->eventName)
+ VIR_FREE(event->eventName);
}
VIR_FREE(event);
return -1;
}
+/**
+ * virDomainEventCallbackListAddQemuCallbackID:
+ * @conn: pointer to the connection
+ * @cbList: the list
+ * @callbackID: the libvirt callback ID
+ * @qemuCallbackID: the libvirtd callback ID to add
+ *
+ * Internal function to add a Daemon libvirtd callbackID
+ */
+int
+virDomainEventCallbackListAddQemuCallbackID(virConnectPtr conn,
+ virDomainEventCallbackListPtr cbList,
+ int callbackID,
+ int qemuCallbackID)
+{
+ int i;
+ for (i = 0 ; i < cbList->count ; i++) {
+ if (cbList->callbacks[i]->callbackID == callbackID &&
+ cbList->callbacks[i]->conn == conn) {
+ cbList->callbacks[i]->qemuCallbackID = qemuCallbackID;
+ return 0;
+ }
+ }
+
+ eventReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("could not find event callback for deletion"));
+ return -1;
+}
int virDomainEventCallbackListCountID(virConnectPtr conn,
virDomainEventCallbackListPtr cbList,
@@ -442,6 +625,27 @@ int virDomainEventCallbackListCountID(virConnectPtr conn,
}
+int
+virDomainEventCallbackListCountName(virConnectPtr conn,
+ virDomainEventCallbackListPtr cbList,
+ const char *eventName)
+{
+ int i;
+ int count = 0;
+
+ for (i = 0 ; i < cbList->count ; i++) {
+ if (cbList->callbacks[i]->deleted)
+ continue;
+
+ if (!strcmp(cbList->callbacks[i]->eventName,eventName) &&
+ cbList->callbacks[i]->conn == conn)
+ count++;
+ }
+
+ return count;
+}
+
+
int virDomainEventCallbackListEventID(virConnectPtr conn,
virDomainEventCallbackListPtr cbList,
int callbackID)
@@ -461,6 +665,44 @@ int virDomainEventCallbackListEventID(virConnectPtr conn,
}
+const char*
+virDomainEventCallbackListEventName(virConnectPtr conn,
+ virDomainEventCallbackListPtr cbList,
+ int callbackID)
+{
+ int i;
+
+ for (i = 0 ; i < cbList->count ; i++) {
+ if (cbList->callbacks[i]->deleted)
+ continue;
+
+ if (cbList->callbacks[i]->callbackID == callbackID &&
+ cbList->callbacks[i]->conn == conn)
+ return cbList->callbacks[i]->eventName;
+ }
+
+ return NULL;
+}
+
+int
+virDomainEventCallbackListEventQemuCallbackID(virConnectPtr conn,
+ virDomainEventCallbackListPtr cbList,
+ int callbackID)
+{
+ int i;
+
+ for (i = 0 ; i < cbList->count ; i++) {
+ if (cbList->callbacks[i]->deleted)
+ continue;
+
+ if (cbList->callbacks[i]->callbackID == callbackID &&
+ cbList->callbacks[i]->conn == conn)
+ return cbList->callbacks[i]->qemuCallbackID;
+ }
+
+ return -1;
+}
+
int virDomainEventCallbackListCount(virDomainEventCallbackListPtr cbList)
{
int i;
@@ -521,6 +763,11 @@ void virDomainEventFree(virDomainEventPtr event)
VIR_FREE(event->data.diskChange.newSrcPath);
VIR_FREE(event->data.diskChange.devAlias);
break;
+
+ case VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN:
+ VIR_FREE(event->data.qemuUnknownEvent.eventName);
+ VIR_FREE(event->data.qemuUnknownEvent.eventArgs);
+ break;
}
VIR_FREE(event->dom.name);
@@ -956,6 +1203,51 @@ virDomainEventPtr virDomainEventBlockJobNewFromDom(virDomainPtr dom,
path, type, status);
}
+static virDomainEventPtr
+virDomainEventUnknownNew(int id, const char *name, unsigned char *uuid,
+ const char *eventName, const char *eventArgs)
+{
+ virDomainEventPtr ev =
+ virDomainEventNewInternal(VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN,
+ id, name, uuid);
+ if (ev) {
+ if (!(ev->data.qemuUnknownEvent.eventName = strdup(eventName))) {
+ virReportOOMError();
+ VIR_FREE(ev->dom.name);
+ VIR_FREE(ev);
+ return NULL;
+ }
+ if (eventArgs) {
+ if (!(ev->data.qemuUnknownEvent.eventArgs = strdup(eventArgs))) {
+ virReportOOMError();
+ VIR_FREE(ev->data.qemuUnknownEvent.eventName);
+ VIR_FREE(ev->dom.name);
+ VIR_FREE(ev);
+ return NULL;
+ }
+ }
+ }
+
+ return ev;
+}
+
+virDomainEventPtr virDomainEventUnknownNewFromObj(virDomainObjPtr obj,
+ const char *eventName,
+ const char *eventArgs)
+{
+
+ return virDomainEventUnknownNew(obj->def->id, obj->def->name,
+ obj->def->uuid, eventName, eventArgs);
+}
+
+virDomainEventPtr virDomainEventUnknownNewFromDom(virDomainPtr dom,
+ const char *eventName,
+ const char *eventArgs)
+{
+ return virDomainEventUnknownNew(dom->id, dom->name, dom->uuid,
+ eventName, eventArgs);
+}
+
virDomainEventPtr virDomainEventControlErrorNewFromDom(virDomainPtr dom)
{
virDomainEventPtr ev =
@@ -1095,11 +1387,12 @@ virDomainEventQueuePush(virDomainEventQueuePtr evtQueue,
}
-void virDomainEventDispatchDefaultFunc(virConnectPtr conn,
- virDomainEventPtr event,
- virConnectDomainEventGenericCallback cb,
- void *cbopaque,
- void *opaque ATTRIBUTE_UNUSED)
+void
+virDomainEventDispatchDefaultFunc(virConnectPtr conn,
+ virDomainEventPtr event,
+ virConnectDomainEventGenericCallback cb,
+ void *cbopaque,
+ void *opaque ATTRIBUTE_UNUSED)
{
virDomainPtr dom = virGetDomain(conn, event->dom.name, event->dom.uuid);
if (!dom)
@@ -1180,6 +1473,13 @@ void virDomainEventDispatchDefaultFunc(virConnectPtr conn,
cbopaque);
break;
+ case VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN:
+ ((virConnectDomainQemuEventCallback)cb)(conn, dom,
+ event->data.qemuUnknownEvent.eventName,
+ event->data.qemuUnknownEvent.eventArgs,
+ cbopaque);
+ break;
+
default:
VIR_WARN("Unexpected event ID %d", event->eventID);
break;
@@ -1189,8 +1489,9 @@ void virDomainEventDispatchDefaultFunc(virConnectPtr conn,
}
-static int virDomainEventDispatchMatchCallback(virDomainEventPtr event,
- virDomainEventCallbackPtr cb)
+static int
+virDomainEventDispatchMatchCallback(virDomainEventPtr event,
+ virDomainEventCallbackPtr cb)
{
if (!cb)
return 0;
@@ -1198,7 +1499,12 @@ static int virDomainEventDispatchMatchCallback(virDomainEventPtr event,
return 0;
if (cb->eventID != event->eventID)
return 0;
-
+ if (event->eventID == VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN) {
+ if(event->data.qemuUnknownEvent.eventName == NULL ||
+ cb->eventName == NULL ||
+ strcmp(cb->eventName, event->data.qemuUnknownEvent.eventName) != 0)
+ return 0;
+ }
if (cb->dom) {
/* Deliberately ignoring 'id' for matching, since that
* will cause problems when a domain switches between
@@ -1341,3 +1647,20 @@ virDomainEventStateDeregisterAny(virConnectPtr conn,
virDomainEventStateUnlock(state);
return ret;
}
+int
+virDomainQemuEventStateDeregister(virConnectPtr conn,
+ virDomainEventStatePtr state,
+ int callbackID)
+{
+ int ret;
+
+ virDomainEventStateLock(state);
+ if (state->isDispatching)
+ ret = virDomainEventCallbackListMarkDeleteID(conn,
+ state->callbacks, callbackID);
+ else
+ ret = virDomainQemuEventCallbackListRemoveID(conn,
+ state->callbacks, callbackID);
+ virDomainEventStateUnlock(state);
+ return ret;
+}
diff --git a/src/conf/domain_event.h b/src/conf/domain_event.h
index 3ba418e..c0edfac 100644
--- a/src/conf/domain_event.h
+++ b/src/conf/domain_event.h
@@ -26,7 +26,6 @@
# define __DOMAIN_EVENT_H__
# include "domain_conf.h"
-
typedef struct _virDomainEventCallback virDomainEventCallback;
typedef virDomainEventCallback *virDomainEventCallbackPtr;
@@ -83,6 +82,15 @@ int virDomainEventCallbackListAddID(virConnectPtr conn,
virFreeCallback freecb)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(5);
+int virDomainEventCallbackListAddName(virConnectPtr conn,
+ virDomainEventCallbackListPtr cbList,
+ virDomainPtr dom,
+ const char* eventName,
+ int eventID,
+ virConnectDomainEventGenericCallback callback,
+ void *opaque,
+ virFreeCallback freecb)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(6);
int virDomainEventCallbackListRemove(virConnectPtr conn,
virDomainEventCallbackListPtr cbList,
@@ -92,6 +100,10 @@ int virDomainEventCallbackListRemoveID(virConnectPtr conn,
virDomainEventCallbackListPtr cbList,
int callbackID)
ATTRIBUTE_NONNULL(1);
+int virDomainQemuEventCallbackListRemoveID(virConnectPtr conn,
+ virDomainEventCallbackListPtr cbList,
+ int callbackID)
+ ATTRIBUTE_NONNULL(1);
int virDomainEventCallbackListRemoveConn(virConnectPtr conn,
virDomainEventCallbackListPtr cbList)
ATTRIBUTE_NONNULL(1);
@@ -106,9 +118,14 @@ int virDomainEventCallbackListMarkDeleteID(virConnectPtr conn,
int callbackID)
ATTRIBUTE_NONNULL(1);
-
int virDomainEventCallbackListPurgeMarked(virDomainEventCallbackListPtr cbList);
+int virDomainEventCallbackListAddQemuCallbackID(virConnectPtr conn,
+ virDomainEventCallbackListPtr cbList,
+ int callbackID,
+ int qemuCallbackID)
+ ATTRIBUTE_NONNULL(1);
+
int virDomainEventCallbackListCount(virDomainEventCallbackListPtr cbList);
int virDomainEventCallbackListCountID(virConnectPtr conn,
virDomainEventCallbackListPtr cbList,
@@ -119,6 +136,21 @@ int virDomainEventCallbackListEventID(virConnectPtr conn,
int callbackID)
ATTRIBUTE_NONNULL(1);
+int virDomainEventCallbackListCountName(virConnectPtr conn,
+ virDomainEventCallbackListPtr cbList,
+ const char *eventName)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3);
+
+int virDomainEventCallbackListEventQemuCallbackID(virConnectPtr conn,
+ virDomainEventCallbackListPtr cbList,
+ int callbackID)
+ ATTRIBUTE_NONNULL(1);
+
+const char* virDomainEventCallbackListEventName(virConnectPtr conn,
+ virDomainEventCallbackListPtr cbList,
+ int callbackID)
+ ATTRIBUTE_NONNULL(1);
+
virDomainEventQueuePtr virDomainEventQueueNew(void);
virDomainEventPtr virDomainEventNew(int id, const char *name, const unsigned char *uuid, int type, int detail);
@@ -190,6 +222,13 @@ virDomainEventPtr virDomainEventDiskChangeNewFromDom(virDomainPtr dom,
const char *devAlias,
int reason);
+virDomainEventPtr virDomainEventUnknownNewFromObj(virDomainObjPtr obj,
+ const char *eventName,
+ const char *eventArgs);
+virDomainEventPtr virDomainEventUnknownNewFromDom(virDomainPtr dom,
+ const char *eventName,
+ const char *eventArgs);
+
int virDomainEventQueuePush(virDomainEventQueuePtr evtQueue,
virDomainEventPtr event);
@@ -246,5 +285,9 @@ virDomainEventStateDeregisterAny(virConnectPtr conn,
virDomainEventStatePtr state,
int callbackID)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
-
+int
+virDomainQemuEventStateDeregister(virConnectPtr conn,
+ virDomainEventStatePtr state,
+ int callbackID)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
#endif
diff --git a/src/driver.h b/src/driver.h
index 941ff51..51164a9 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -635,6 +635,18 @@ typedef virDomainPtr
unsigned int flags);
typedef int
+ (*virDrvDomainQemuEventRegister)(virConnectPtr conn,
+ virDomainPtr dom, /* option to filter */
+ const char *eventName, /* JSON event name */
+ virConnectDomainEventGenericCallback cb,
+ void *opaque,
+ virFreeCallback freecb);
+
+typedef int
+ (*virDrvDomainQemuEventDeregister)(virConnectPtr conn,
+ int callbackID);
+
+typedef int
(*virDrvDomainOpenConsole)(virDomainPtr dom,
const char *dev_name,
virStreamPtr st,
@@ -915,6 +927,8 @@ struct _virDriver {
virDrvDomainSnapshotDelete domainSnapshotDelete;
virDrvDomainQemuMonitorCommand qemuDomainMonitorCommand;
virDrvDomainQemuAttach qemuDomainAttach;
+ virDrvDomainQemuEventRegister qemuDomainQemuEventRegister;
+ virDrvDomainQemuEventDeregister qemuDomainQemuEventDeregister;
virDrvDomainOpenConsole domainOpenConsole;
virDrvDomainOpenGraphics domainOpenGraphics;
virDrvDomainInjectNMI domainInjectNMI;
diff --git a/src/libvirt-qemu.c b/src/libvirt-qemu.c
index 248cc33..c84375c 100644
--- a/src/libvirt-qemu.c
+++ b/src/libvirt-qemu.c
@@ -36,6 +36,77 @@
virReportErrorHelper(VIR_FROM_DOM, error, NULL, __FUNCTION__, \
__LINE__, info)
+/* Helper macros to implement VIR_DOMAIN_DEBUG using just C99. This
+ * assumes you pass fewer than 15 arguments to VIR_DOMAIN_DEBUG, but
+ * can easily be expanded if needed.
+ *
+ * Note that gcc provides extensions of "define a(b...) b" or
+ * "define a(b,...) b,##__VA_ARGS__" as a means of eliding a comma
+ * when no var-args are present, but we don't want to require gcc.
+ */
+#define VIR_ARG15(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, ...) _15
+#define VIR_HAS_COMMA(...) VIR_ARG15(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0)
+
+/* Form the name VIR_DOMAIN_DEBUG_[01], then call that macro,
+ * according to how many arguments are present. Two-phase due to
+ * macro expansion rules. */
+#define VIR_DOMAIN_DEBUG_EXPAND(a, b, ...) \
+ VIR_DOMAIN_DEBUG_PASTE(a, b, __VA_ARGS__)
+#define VIR_DOMAIN_DEBUG_PASTE(a, b, ...) \
+ a##b(__VA_ARGS__)
+
+/* Internal use only, when VIR_DOMAIN_DEBUG has one argument. */
+#define VIR_DOMAIN_DEBUG_0(dom) \
+ VIR_DOMAIN_DEBUG_2(dom, "%s", "")
+
+/* Internal use only, when VIR_DOMAIN_DEBUG has three or more arguments. */
+#define VIR_DOMAIN_DEBUG_1(dom, fmt, ...) \
+ VIR_DOMAIN_DEBUG_2(dom, ", " fmt, __VA_ARGS__)
+
+/* Internal use only, with final format. */
+#define VIR_DOMAIN_DEBUG_2(dom, fmt, ...) \
+ do { \
+ char _uuidstr[VIR_UUID_STRING_BUFLEN]; \
+ const char *_domname = NULL; \
+ \
+ if (!VIR_IS_DOMAIN(dom)) { \
+ memset(_uuidstr, 0, sizeof(_uuidstr)); \
+ } else { \
+ virUUIDFormat((dom)->uuid, _uuidstr); \
+ _domname = (dom)->name; \
+ } \
+ \
+ VIR_DEBUG("dom=%p, (VM: name=%s, uuid=%s)" fmt, \
+ dom, NULLSTR(_domname), _uuidstr, __VA_ARGS__); \
+ } while (0)
+
+/**
+ * VIR_DOMAIN_DEBUG:
+ * @dom: domain
+ * @fmt: optional format for additional information
+ * @...: optional arguments corresponding to @fmt.
+ */
+#define VIR_DOMAIN_DEBUG(...) \
+ VIR_DOMAIN_DEBUG_EXPAND(VIR_DOMAIN_DEBUG_, \
+ VIR_HAS_COMMA(__VA_ARGS__), \
+ __VA_ARGS__)
+
+/**
+ * VIR_UUID_DEBUG:
+ * @conn: connection
+ * @uuid: possibly null UUID array
+ */
+#define VIR_UUID_DEBUG(conn, uuid) \
+ do { \
+ if (uuid) { \
+ char _uuidstr[VIR_UUID_STRING_BUFLEN]; \
+ virUUIDFormat(uuid, _uuidstr); \
+ VIR_DEBUG("conn=%p, uuid=%s", conn, _uuidstr); \
+ } else { \
+ VIR_DEBUG("conn=%p, uuid=(null)", conn); \
+ } \
+ } while (0)
+
/**
* virDomainQemuMonitorCommand:
* @domain: a domain object
@@ -178,3 +249,122 @@ error:
virDispatchError(conn);
return NULL;
}
+
+/**
+ * virConnectDomainQemuEventRegister:
+ * @conn: pointer to the connection
+ * @dom: pointer to the domain
+ * @eventName: the event Name to receive
+ * @cb: callback to the function handling domain events
+ * @opaque: opaque data to pass on to the callback
+ * @freecb: optional function to deallocate opaque when not used anymore
+ *
+ * Adds a callback to receive notifications of arbitrary qemu domain events
+ * occurring on a domain.
+ *
+ * If dom is NULL, then events will be monitored for any domain. If dom
+ * is non-NULL, then only the specific domain will be monitored
+ *
+ * Most types of event have a callback providing a custom set of parameters
+ * for the event. When registering an event, it is thus neccessary to use
+ * the VIR_DOMAIN_EVENT_CALLBACK() macro to cast the supplied function pointer
+ * to match the signature of this method.
+ *
+ * The virDomainPtr object handle passed into the callback upon delivery
+ * of an event is only valid for the duration of execution of the callback.
+ * If the callback wishes to keep the domain object after the callback returns,
+ * it shall take a reference to it, by calling virDomainRef.
+ * The reference can be released once the object is no longer required
+ * by calling virDomainFree.
+ *
+ * The return value from this method is a positive integer identifier
+ * for the callback. To unregister a callback, this callback ID should
+ * be passed to the virConnectDomainQemuEventDeregister method
+ *
+ * Returns a callback identifier on success, -1 on failure
+ */
+int
+virConnectDomainQemuEventRegister(virConnectPtr conn,
+ virDomainPtr dom, /* option to filter */
+ const char *eventName, /* JSON event name */
+ virConnectDomainQemuEventCallback cb,
+ void *opaque,
+ virFreeCallback freecb)
+{
+ VIR_DOMAIN_DEBUG(dom, "conn=%p, eventName=%s, cb=%p, opaque=%p, freecb=%p",
+ conn, eventName, cb, opaque, freecb);
+
+ virResetLastError();
+
+ if (!VIR_IS_CONNECT(conn)) {
+ virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ virLibConnError(conn, VIR_ERR_INVALID_CONN, "my_test_fuction");
+ virDispatchError(NULL);
+ return -1;
+ }
+ if (dom != NULL &&
+ !(VIR_IS_CONNECTED_DOMAIN(dom) && dom->conn == conn)) {
+ virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ virDispatchError(conn);
+ return -1;
+ }
+ if (eventName == NULL || cb == NULL) {
+ virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto error;
+ }
+
+ if ((conn->driver) && (conn->driver->qemuDomainQemuEventRegister)) {
+ int ret;
+ ret = conn->driver->qemuDomainQemuEventRegister(conn, dom, eventName, cb, opaque, freecb);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virLibConnError(conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+error:
+ virDispatchError(conn);
+ return -1;
+}
+
+/**
+ * virConnectDomainQemuEventDeregister:
+ * @conn: pointer to the connection
+ * @callbackID: the callback identifier
+ *
+ * Removes an event callback. The callbackID parameter should be the
+ * vaule obtained from a previous virConnectDomainQemuEventDeregister method.
+ *
+ * Returns 0 on success, -1 on failure
+ */
+int
+virConnectDomainQemuEventDeregister(virConnectPtr conn,
+ int callbackID)
+{
+
+ VIR_DEBUG("conn=%p, callbackID=%d", conn, callbackID);
+
+ virResetLastError();
+
+ if (!VIR_IS_CONNECT(conn)) {
+ virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ virDispatchError(NULL);
+ return -1;
+ }
+ if (callbackID < 0) {
+ virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto error;
+ }
+ if ((conn->driver) && (conn->driver->qemuDomainQemuEventDeregister)) {
+ int ret;
+ ret = conn->driver->qemuDomainQemuEventDeregister(conn, callbackID);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virLibConnError(conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+error:
+ virDispatchError(conn);
+ return -1;
+}
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index a81c230..b92ce71 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -470,11 +470,16 @@ virDomainWatchdogModelTypeToString;
# domain_event.h
virDomainEventBlockJobNewFromObj;
virDomainEventBlockJobNewFromDom;
+virDomainEventUnknownNewFromObj;
+virDomainEventunknownNewFromDom;
virDomainEventCallbackListAdd;
virDomainEventCallbackListAddID;
+virDomainEventCallbackListAddName;
virDomainEventCallbackListCount;
virDomainEventCallbackListCountID;
+virDomainEventCallbackListCountName;
virDomainEventCallbackListEventID;
+virDomainEventCallbackListEventName;
virDomainEventCallbackListFree;
virDomainEventCallbackListMarkDelete;
virDomainEventCallbackListMarkDeleteID;
@@ -511,6 +516,7 @@ virDomainEventRebootNewFromDom;
virDomainEventRebootNewFromObj;
virDomainEventStateDeregister;
virDomainEventStateDeregisterAny;
+virDomainQemuEventStateDeregister;
virDomainEventStateFlush;
virDomainEventStateFree;
virDomainEventStateNew;
diff --git a/src/libvirt_qemu.syms b/src/libvirt_qemu.syms
index 8447730..a17e387 100644
--- a/src/libvirt_qemu.syms
+++ b/src/libvirt_qemu.syms
@@ -19,3 +19,8 @@ LIBVIRT_QEMU_0.9.4 {
global:
virDomainQemuAttach;
} LIBVIRT_QEMU_0.8.3;
+LIBVIRT_QEMU_0.9.9 {
+ global:
+ virConnectDomainQemuEventRegister;
+ virConnectDomainQemuEventDeregister;
+} LIBVIRT_QEMU_0.9.4;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index ceb9f47..31fe966 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -8217,6 +8217,46 @@ qemuDomainEventDeregisterAny(virConnectPtr conn,
}
+static int
+qemuDomainQemuEventRegister(virConnectPtr conn,
+ virDomainPtr dom,
+ const char *eventName,
+ virConnectDomainEventGenericCallback callback,
+ void *opaque,
+ virFreeCallback freecb)
+{
+ struct qemud_driver *driver = conn->privateData;
+ int ret;
+
+ qemuDriverLock(driver);
+ ret = virDomainEventCallbackListAddName(conn,
+ driver->domainEventState->callbacks,
+ dom, eventName,
+ VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN,
+ callback, opaque, freecb);
+ qemuDriverUnlock(driver);
+
+ return ret;
+}
+
+
+static int
+qemuDomainQemuEventDeregister(virConnectPtr conn,
+ int callbackID)
+{
+ struct qemud_driver *driver = conn->privateData;
+ int ret;
+
+ qemuDriverLock(driver);
+ ret = virDomainQemuEventStateDeregister(conn,
+ driver->domainEventState,
+ callbackID);
+ qemuDriverUnlock(driver);
+
+ return ret;
+}
+
+
/*******************************************************************
* Migration Protocol Version 2
*******************************************************************/
@@ -11564,6 +11604,8 @@ static virDriver qemuDriver = {
.domainMigrateGetMaxSpeed = qemuDomainMigrateGetMaxSpeed, /* 0.9.5 */
.domainEventRegisterAny = qemuDomainEventRegisterAny, /* 0.8.0 */
.domainEventDeregisterAny = qemuDomainEventDeregisterAny, /* 0.8.0 */
+ .qemuDomainQemuEventRegister = qemuDomainQemuEventRegister, /* 0.9.9 */
+ .qemuDomainQemuEventDeregister = qemuDomainQemuEventDeregister, /* 0.9.9 */
.domainManagedSave = qemuDomainManagedSave, /* 0.8.0 */
.domainHasManagedSaveImage = qemuDomainHasManagedSaveImage, /* 0.8.0 */
.domainManagedSaveRemove = qemuDomainManagedSaveRemove, /* 0.8.0 */
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 4141fb7..e6cd39c 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -959,6 +959,16 @@ int qemuMonitorEmitBlockJob(qemuMonitorPtr mon,
return ret;
}
+int qemuMonitorEmitUnknownEvent(qemuMonitorPtr mon,
+ const char *eventName,
+ const char *eventArgs)
+{
+ int ret = -1;
+ VIR_DEBUG("mon=%p", mon);
+ QEMU_MONITOR_CALLBACK(mon, ret, domainUnknownEvent, mon->vm,
+ eventName, eventArgs);
+ return ret;
+}
int qemuMonitorSetCapabilities(qemuMonitorPtr mon)
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 15acf8b..d3685b4 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -123,6 +123,10 @@ struct _qemuMonitorCallbacks {
const char *diskAlias,
int type,
int status);
+ int (*domainUnknownEvent)(qemuMonitorPtr mon,
+ virDomainObjPtr vm,
+ const char *eventName,
+ const char *eventArgs);
};
@@ -193,6 +197,10 @@ int qemuMonitorEmitBlockJob(qemuMonitorPtr mon,
int type,
int status);
+int qemuMonitorEmitUnknownEvent(qemuMonitorPtr mon,
+ const char *eventName,
+ const char *eventArgs);
+
int qemuMonitorStartCPUs(qemuMonitorPtr mon,
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 1ef3e84..a5fc1e6 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -58,6 +58,7 @@ static void qemuMonitorJSONHandleVNCConnect(qemuMonitorPtr mon, virJSONValuePtr
static void qemuMonitorJSONHandleVNCInitialize(qemuMonitorPtr mon, virJSONValuePtr data);
static void qemuMonitorJSONHandleVNCDisconnect(qemuMonitorPtr mon, virJSONValuePtr data);
static void qemuMonitorJSONHandleBlockJob(qemuMonitorPtr mon, virJSONValuePtr data);
+static void qemuMonitorJSONHandleUnmatchedEvent(qemuMonitorPtr mon, virJSONValuePtr obj);
struct {
const char *type;
@@ -74,6 +75,7 @@ struct {
{ "VNC_INITIALIZED", qemuMonitorJSONHandleVNCInitialize, },
{ "VNC_DISCONNECTED", qemuMonitorJSONHandleVNCDisconnect, },
{ "BLOCK_JOB_COMPLETED", qemuMonitorJSONHandleBlockJob, },
+ { "DEFAULT_UNKNOW_EVENT", qemuMonitorJSONHandleUnmatchedEvent, },
};
@@ -83,6 +85,7 @@ qemuMonitorJSONIOProcessEvent(qemuMonitorPtr mon,
{
const char *type;
int i;
+ int findEventFlag = -1;
VIR_DEBUG("mon=%p obj=%p", mon, obj);
type = virJSONValueObjectGetString(obj, "event");
@@ -98,9 +101,24 @@ qemuMonitorJSONIOProcessEvent(qemuMonitorPtr mon,
VIR_DEBUG("handle %s handler=%p data=%p", type,
eventHandlers[i].handler, data);
(eventHandlers[i].handler)(mon, data);
+ findEventFlag = 0;
break;
}
}
+ if (findEventFlag != 0) {
+ if (!STREQ(eventHandlers[ARRAY_CARDINALITY(eventHandlers)-1].type, "DEFAULT_UNKNOW_EVENT")) {
+ VIR_ERROR("the last element is not the default event handler");
+ }
+ else {
+ char *event = NULL;
+ event = virJSONValueToString(obj);
+ if (event != NULL) {
+ VIR_DEBUG("Unknow event,call default event handler %s",event);
+ free(event);
+ }
+ (eventHandlers[ARRAY_CARDINALITY(eventHandlers)-1].handler)(mon, obj);
+ }
+ }
return 0;
}
@@ -724,6 +742,24 @@ out:
}
+static void
+qemuMonitorJSONHandleUnmatchedEvent(qemuMonitorPtr mon, virJSONValuePtr obj)
+{
+ const char *eventArgsStr = NULL;
+ const char *type = NULL;
+ virJSONValuePtr data = NULL;
+ type = virJSONValueObjectGetString(obj, "event");
+ data = virJSONValueObjectGet(obj, "data");
+ if (data) {
+ eventArgsStr = virJSONValueToString(data);
+ }
+ if (eventArgsStr == NULL) {
+ VIR_ERROR("no data string from JSONValue");
+ }
+ qemuMonitorEmitUnknownEvent(mon, type, eventArgsStr);
+}
+
+
int
qemuMonitorJSONHumanCommandWithFd(qemuMonitorPtr mon,
const char *cmd_str,
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 9123f4c..55e5464 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -755,6 +755,29 @@ qemuProcessHandleBlockJob(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
}
static int
+qemuProcessHandleUnknownEvent(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
+ virDomainObjPtr vm,
+ const char *eventName,
+ const char *eventArgs)
+{
+ struct qemud_driver *driver = qemu_driver;
+ virDomainEventPtr event = NULL;
+
+ virDomainObjLock(vm);
+ event = virDomainEventUnknownNewFromObj(vm, eventName, eventArgs);
+
+ virDomainObjUnlock(vm);
+
+ if (event) {
+ qemuDriverLock(driver);
+ qemuDomainEventQueue(driver, event);
+ qemuDriverUnlock(driver);
+ }
+
+ return 0;
+}
+
+static int
qemuProcessHandleGraphics(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
virDomainObjPtr vm,
int phase,
@@ -871,6 +894,7 @@ static qemuMonitorCallbacks monitorCallbacks = {
.domainIOError = qemuProcessHandleIOError,
.domainGraphics = qemuProcessHandleGraphics,
.domainBlockJob = qemuProcessHandleBlockJob,
+ .domainUnknownEvent = qemuProcessHandleUnknownEvent,
};
static int
diff --git a/src/remote/qemu_protocol.x b/src/remote/qemu_protocol.x
index 39f9adf..5f4ed61 100644
--- a/src/remote/qemu_protocol.x
+++ b/src/remote/qemu_protocol.x
@@ -47,6 +47,34 @@ struct qemu_domain_attach_ret {
remote_nonnull_domain dom;
};
+struct qemu_domain_events_register_args {
+ remote_nonnull_string eventName;
+};
+
+struct qemu_domain_events_deregister_args {
+ remote_nonnull_string eventName;
+ int callbackID;
+};
+
+struct qemu_domain_events_register_ret {
+ int callbackID;
+};
+
+struct qemu_domain_events_deregister_ret {
+ int cb_deregistered;
+};
+
+struct qemu_domain_events_unknown_event_args {
+ remote_nonnull_domain dom;
+ remote_nonnull_string eventName;
+ remote_nonnull_string eventArgs;
+};
+
+struct qemu_domain_events_unknown_event_ret {
+ int event_ret;
+};
+
+
/* Define the program number, protocol version and procedure numbers here. */
const QEMU_PROGRAM = 0x20008087;
const QEMU_PROTOCOL_VERSION = 1;
@@ -61,5 +89,8 @@ enum qemu_procedure {
* are some exceptions to this rule, e.g. domainDestroy. Other APIs MAY
* be marked as high priority. If in doubt, it's safe to choose low. */
QEMU_PROC_MONITOR_COMMAND = 1, /* skipgen skipgen priority:low */
- QEMU_PROC_DOMAIN_ATTACH = 2 /* autogen autogen priority:low */
+ QEMU_PROC_DOMAIN_ATTACH = 2, /* autogen autogen priority:low */
+ QEMU_PROC_DOMAIN_EVENTS_REGISTER = 3, /* skipgen skipgen priority:low */
+ QEMU_PROC_DOMAIN_EVENTS_DEREGISTER = 4, /* skipgen skipgen priority:low */
+ QEMU_PROC_DOMAIN_EVENTS_UNKNOWN_EVENT = 5 /* skipgen skipgen priority:low */
};
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index ff2d4b4..1f7b25d 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -238,6 +238,10 @@ static void
remoteDomainBuildEventDiskChange(virNetClientProgramPtr prog,
virNetClientPtr client,
void *evdata, void *opaque);
+static void
+remoteQemuDomainBuildEventDefaultEvent(virNetClientProgramPtr prog,
+ virNetClientPtr client,
+ void *evdata, void *opaque);
static virNetClientProgramEvent remoteDomainEvents[] = {
{ REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE,
@@ -280,6 +284,10 @@ static virNetClientProgramEvent remoteDomainEvents[] = {
remoteDomainBuildEventDiskChange,
sizeof(remote_domain_event_disk_change_msg),
(xdrproc_t)xdr_remote_domain_event_disk_change_msg },
+ { REMOTE_PROC_QEMU_DOMAIN_EVENT_UNKNOWN_EVENT,
+ remoteQemuDomainBuildEventDefaultEvent,
+ sizeof(remote_domain_event_default_event_msg),
+ (xdrproc_t)xdr_remote_domain_event_default_event_msg },
};
enum virDrvOpenRemoteFlags {
@@ -3345,6 +3353,28 @@ remoteDomainBuildEventBlockJob(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
}
static void
+remoteQemuDomainBuildEventDefaultEvent(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+ virNetClientPtr client ATTRIBUTE_UNUSED,
+ void *evdata, void *opaque)
+{
+ virConnectPtr conn = opaque;
+ struct private_data *priv = conn->privateData;
+ remote_domain_event_default_event_msg *msg = evdata;
+ virDomainPtr dom;
+ virDomainEventPtr event = NULL;
+
+ dom = get_nonnull_domain(conn, msg->dom);
+ if (!dom)
+ return;
+
+ event = virDomainEventUnknownNewFromDom(dom, msg->eventName, msg->eventArgs);
+
+ virDomainFree(dom);
+
+ remoteDomainEventQueue(priv, event);
+}
+
+static void
remoteDomainBuildEventGraphics(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
virNetClientPtr client ATTRIBUTE_UNUSED,
void *evdata, void *opaque)
@@ -3800,7 +3830,6 @@ done:
return rv;
}
-
static int remoteDomainEventDeregisterAny(virConnectPtr conn,
int callbackID)
{
@@ -3843,6 +3872,126 @@ done:
return rv;
}
+static int
+remoteDomainQemuEventRegister(virConnectPtr conn,
+ virDomainPtr dom,
+ const char *eventName,
+ virConnectDomainEventGenericCallback callback,
+ void *opaque,
+ virFreeCallback freecb)
+{
+ int rv = -1;
+ struct private_data *priv = conn->privateData;
+ qemu_domain_events_register_args args;
+ qemu_domain_events_register_ret ret;
+ int callbackID;
+
+ remoteDriverLock(priv);
+
+ if (priv->domainEventState->timer < 0) {
+ remoteError(VIR_ERR_NO_SUPPORT, "%s", _("no event support"));
+ goto done;
+ }
+
+ if ((callbackID = virDomainEventCallbackListAddName(conn,
+ priv->domainEventState->callbacks,
+ dom, eventName,
+ VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN,
+ callback, opaque, freecb)) < 0) {
+ remoteError(VIR_ERR_RPC, "%s", _("adding cb to list"));
+ goto done;
+ }
+
+ /* If this is the first callback for this eventID, we need to enable
+ * events on the server */
+ if (virDomainEventCallbackListCountName(conn,
+ priv->domainEventState->callbacks,
+ eventName) == 1) {
+ args.eventName= (char *)eventName;
+
+ if (call (conn, priv, REMOTE_CALL_QEMU, QEMU_PROC_DOMAIN_EVENTS_REGISTER,
+ (xdrproc_t) xdr_qemu_domain_events_register_args, (char *) &args,
+ (xdrproc_t) xdr_qemu_domain_events_register_ret, (char *) &ret) == -1) {
+ virDomainEventCallbackListRemoveID(conn,
+ priv->domainEventState->callbacks,
+ callbackID);
+ goto done;
+ }
+ }
+ virDomainEventCallbackListAddQemuCallbackID(conn,
+ priv->domainEventState->callbacks,
+ callbackID,
+ ret.callbackID);
+ rv = callbackID;
+
+done:
+ remoteDriverUnlock(priv);
+ return rv;
+}
+
+static int remoteDomainQemuEventDeregister(virConnectPtr conn,
+ int callbackID)
+{
+ struct private_data *priv = conn->privateData;
+ int rv = -1;
+ qemu_domain_events_deregister_args args;
+ qemu_domain_events_deregister_ret ret;
+ char *eventName = NULL;
+ ret.cb_deregistered = -1;
+
+ remoteDriverLock(priv);
+
+ if ((eventName = (char *)virDomainEventCallbackListEventName(conn,
+ priv->domainEventState->callbacks,
+ callbackID)) == NULL) {
+ remoteError(VIR_ERR_RPC, _("unable to find callback ID %d"), callbackID);
+ goto done;
+ }
+ eventName = strdup(eventName);
+ if (eventName == NULL)
+ goto done;
+
+ if ((args.callbackID = virDomainEventCallbackListEventQemuCallbackID(conn,
+ priv->domainEventState->callbacks,
+ callbackID)) == -1) {
+ remoteError(VIR_ERR_RPC, _("unable to find callback ID %d"), callbackID);
+ goto done;
+ }
+
+ if (virDomainQemuEventStateDeregister(conn,
+ priv->domainEventState,
+ callbackID) < 0)
+ goto done;
+
+ /* If that was the last callback for this eventName, we need to disable
+ * events on the server */
+ if (virDomainEventCallbackListCountName(conn,
+ priv->domainEventState->callbacks,
+ eventName) == 0) {
+ args.eventName = eventName;
+
+ if (call (conn, priv, REMOTE_CALL_QEMU, QEMU_PROC_DOMAIN_EVENTS_DEREGISTER,
+ (xdrproc_t) xdr_qemu_domain_events_deregister_args, (char *) &args,
+ (xdrproc_t) xdr_qemu_domain_events_deregister_ret, (char *) &ret) == -1) {
+ goto done;
+ }
+
+ if ( ret.cb_deregistered == -1 ) {
+ remoteError(VIR_ERR_RPC, _("remote sever deregeiter remote callbackID:%d, and the client callbackID%d"),
+ args.callbackID,
+ callbackID);
+ goto done;
+ }
+ rv = ret.cb_deregistered;
+ }
+
+
+done:
+ remoteDriverUnlock(priv);
+ if (eventName != NULL)
+ VIR_FREE(eventName);
+ return rv;
+}
/*----------------------------------------------------------------------*/
@@ -4627,6 +4776,8 @@ static virDriver remote_driver = {
.nodeGetFreeMemory = remoteNodeGetFreeMemory, /* 0.3.3 */
.domainEventRegister = remoteDomainEventRegister, /* 0.5.0 */
.domainEventDeregister = remoteDomainEventDeregister, /* 0.5.0 */
+ .qemuDomainQemuEventRegister = remoteDomainQemuEventRegister, /* 0.9.9 */
+ .qemuDomainQemuEventDeregister = remoteDomainQemuEventDeregister, /* 0.9.9 */
.domainMigratePrepare2 = remoteDomainMigratePrepare2, /* 0.5.0 */
.domainMigrateFinish2 = remoteDomainMigrateFinish2, /* 0.5.0 */
.nodeDeviceDettach = remoteNodeDeviceDettach, /* 0.6.1 */
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index 509a20b..4239db8 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -2049,6 +2049,12 @@ struct remote_domain_event_disk_change_msg {
int reason;
};
+struct remote_domain_event_default_event_msg {
+ remote_nonnull_domain dom;
+ remote_nonnull_string eventName;
+ remote_nonnull_string eventArgs;
+};
+
struct remote_domain_managed_save_args {
remote_nonnull_domain dom;
unsigned int flags;
@@ -2605,7 +2611,8 @@ enum remote_procedure {
REMOTE_PROC_DOMAIN_BLOCK_RESIZE = 251, /* autogen autogen */
REMOTE_PROC_DOMAIN_SET_BLOCK_IO_TUNE = 252, /* autogen autogen */
- REMOTE_PROC_DOMAIN_GET_BLOCK_IO_TUNE = 253 /* skipgen skipgen */
+ REMOTE_PROC_DOMAIN_GET_BLOCK_IO_TUNE = 253, /* skipgen skipgen */
+ REMOTE_PROC_QEMU_DOMAIN_EVENT_UNKNOWN_EVENT = 254 /* skipgen skipgen */
/*
* Notice how the entries are grouped in sets of 10 ?
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
index a9d4296..17b3896 100644
--- a/src/remote_protocol-structs
+++ b/src/remote_protocol-structs
@@ -1546,6 +1546,10 @@ struct remote_domain_event_disk_change_msg {
remote_nonnull_string devAlias;
int reason;
};
+struct remote_domain_event_default_event_msg {
+ remote_nonnull_domain dom;
+ remote_nonnull_string rawEvent;
+};
struct remote_domain_managed_save_args {
remote_nonnull_domain dom;
u_int flags;
@@ -2044,4 +2048,5 @@ enum remote_procedure {
REMOTE_PROC_DOMAIN_BLOCK_RESIZE = 251,
REMOTE_PROC_DOMAIN_SET_BLOCK_IO_TUNE = 252,
REMOTE_PROC_DOMAIN_GET_BLOCK_IO_TUNE = 253,
+ REMOTE_PROC_QEMU_DOMAIN_EVENT_UNKNOWN_EVENT = 254,
};
--
1.7.5.4
2
1
Hi all,
My test environment
Host os=rhel6.1
Guest os = rhel6.1
Libvirt=0.9.8
Kvm hypervisor
I have made this entry in guest xml file
<interface type='direct'>
<source dev='eth0' mode='bridge'/>
<model type='virtio'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03'
function='0x0'/>
</interface>
Now when I start the guest
#virsh start guest
Following macvtap0 is created on host and is shown below
#ip link show macvtap0
51: macvtap0@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq
state UNKNOWN qlen 500
link/ether 52:54:00:55:AE:B5brd ff:ff:ff:ff:ff:ff
but when the guest is up and I try to perform
# ifup eth0
It gives following message
"Bringing up interface eth0: Device eth0 does not seem to be present,
delaying initialization.
[FAILED]"
Guest eth interface does not create. What is the problem?
When I checked dmesg on host it gives following message-"macvatp0: ipv6
routers not present"
Please let me know how macvtap work on kvm.
DISCLAIMER:
-----------------------------------------------------------------------------------------------------------------------
The contents of this e-mail and any attachment(s) are confidential and
intended
for the named recipient(s) only.
It shall not attach any liability on the originator or NECHCL or its
affiliates. Any views or opinions presented in
this email are solely those of the author and may not necessarily reflect the
opinions of NECHCL or its affiliates.
Any form of reproduction, dissemination, copying, disclosure, modification,
distribution and / or publication of
this message without the prior written consent of the author of this e-mail is
strictly prohibited. If you have
received this email in error please delete it and notify the sender
immediately. .
-----------------------------------------------------------------------------------------------------------------------
1
0
13 Dec '11
If the vol object is newly created, it increases the volumes count,
but doesn't decrease the volumes count when do cleanup. It can
cause libvirtd crash when one trying to free the volume objects
like:
for (i = 0; i < pool->volumes.count; i++)
virStorageVolDefFree(pool->volumes.objs[i]);
It's more reliale if we add the newly created vol object in the
end.
---
src/storage/storage_backend_logical.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/src/storage/storage_backend_logical.c b/src/storage/storage_backend_logical.c
index 61c89a2..1420ede 100644
--- a/src/storage/storage_backend_logical.c
+++ b/src/storage/storage_backend_logical.c
@@ -110,7 +110,6 @@ virStorageBackendLogicalMakeVol(virStoragePoolObjPtr pool,
virReportOOMError();
goto cleanup;
}
- pool->volumes.objs[pool->volumes.count++] = vol;
}
if (vol->target.path == NULL) {
@@ -254,6 +253,9 @@ virStorageBackendLogicalMakeVol(virStoragePoolObjPtr pool,
vol->source.nextent++;
}
+ if (is_new_vol)
+ pool->volumes.objs[pool->volumes.count++] = vol;
+
ret = 0;
cleanup:
--
1.7.1
2
2
Hi .well I am trying to use virtioballon driver on my KVM host . I have
assigned 400 MB current memory to my guest
The ballon size is 600MB but when I used all the 400MB of guest the RAM
of guest is not increasing.
I watch the ram usage by running following command
#free -m
But the guest is only using memory upto 400MB after that the process is
killed .
I don't see the ballon driver coming into picture. It is not doing
anything
The ballon driver is loaded in host as well as guest
DISCLAIMER:
-----------------------------------------------------------------------------------------------------------------------
The contents of this e-mail and any attachment(s) are confidential and
intended
for the named recipient(s) only.
It shall not attach any liability on the originator or NECHCL or its
affiliates. Any views or opinions presented in
this email are solely those of the author and may not necessarily reflect the
opinions of NECHCL or its affiliates.
Any form of reproduction, dissemination, copying, disclosure, modification,
distribution and / or publication of
this message without the prior written consent of the author of this e-mail is
strictly prohibited. If you have
received this email in error please delete it and notify the sender
immediately. .
-----------------------------------------------------------------------------------------------------------------------
3
4
Hi all,
Please ignore my previous mail..
This is my test scenario
My test environment
Host os=rhel6.1
Guest os = rhel6.1
Libvirt=0.9.8
Kvm hypervisor
I am creating a macvtap interface on host machine at eth0 interface
#ip link show macvtap0
51: macvtap0@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq
state UNKNOWN qlen 500
link/ether 1e:aa:f7:43:7e:3d brd ff:ff:ff:ff:ff:ff
I have made this entry in guest xml file
<interface type='direct'>
<mac address=1e:aa:f7:43:7e:3d'/>
<source dev='eth0' mode='bridge'/>
<model type='virtio'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03'
function='0x0'/>
</interface>
Now when I start the guest
#virsh start guest
It gives following message
error: Failed to start domain guest
error: Cannot set interface flags on 'macvtap1': Device or resource busy
Please let me know what else we need to do to make macvtap work on kvm.
________________________________
From: libvir-list-bounces(a)redhat.com
[mailto:libvir-list-bounces@redhat.com] On Behalf Of Amit Tewari
Sent: Monday, December 12, 2011 3:22 PM
To: libvir-list(a)redhat.com
Subject: [libvirt] macvtap support in libvirt 0.9.8
Hi all,
My test environment
Host os=rhel6.1
Guest os = rhel6.1
Libvirt=0.9.8
Kvm hypervisor
I am creating a macvtap interface on host machine at eth0 interface
#ip link show macvtap0
51: macvtap0@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq
state UNKNOWN qlen 500
link/ether 1e:aa:f7:43:7e:3d brd ff:ff:ff:ff:ff:ff
I have made this entry in guest xml file
<interface type='direct'>
<mac address=1e:aa:f7:43:7e:3d'/>
<source dev='eth0' mode='bridge'/>
<model type='virtio'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03'
function='0x0'/>
</interface>
Now when I start the guest
#virsh start guest
It gives following message
"Bringing up interface eth0: Device eth0 does not seem to be present,
delaying initialization.
[FAILED]"
Guest eth interface does not create. what is the problem.
Please let me know what else we need to do to make macvtap work on kvm.
DISCLAIMER:
------------------------------------------------------------------------
-----------------------------------------------
The contents of this e-mail and any attachment(s) are confidential and
intended
for the named recipient(s) only.
It shall not attach any liability on the originator or NECHCL or its
affiliates. Any views or opinions presented in
this email are solely those of the author and may not necessarily
reflect the
opinions of NECHCL or its affiliates.
Any form of reproduction, dissemination, copying, disclosure,
modification,
distribution and / or publication of
this message without the prior written consent of the author of this
e-mail is
strictly prohibited. If you have
received this email in error please delete it and notify the sender
immediately. .
------------------------------------------------------------------------
-----------------------------------------------
DISCLAIMER:
-----------------------------------------------------------------------------------------------------------------------
The contents of this e-mail and any attachment(s) are confidential and
intended
for the named recipient(s) only.
It shall not attach any liability on the originator or NECHCL or its
affiliates. Any views or opinions presented in
this email are solely those of the author and may not necessarily reflect the
opinions of NECHCL or its affiliates.
Any form of reproduction, dissemination, copying, disclosure, modification,
distribution and / or publication of
this message without the prior written consent of the author of this e-mail is
strictly prohibited. If you have
received this email in error please delete it and notify the sender
immediately. .
-----------------------------------------------------------------------------------------------------------------------
2
1
12 Dec '11
Improve the documentation of what forms a valid <address> element,
since these elements appear in numerous devices.
* docs/formatdomain.html.in (elementsAddress): New section.
(elementsControllers, elementsUSB, elementsNICS, elementsInput)
(elementsHub, elementsCharChannel, elementsSound): Refer to it.
---
I went ahead and assumed Michael's SPAPR-VIO patches go in, but
I was guessing on the content to use there.
docs/formatdomain.html.in | 133 +++++++++++++++++++++++++++++++++------------
1 files changed, 99 insertions(+), 34 deletions(-)
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index f9dbcda..035b9b8 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -1404,12 +1404,87 @@
</dd>
</dl>
+ <h4><a name="elementsAddress">Device Addresses</a></h4>
+
+ <p>
+ Many devices have an optional <code><address></code>
+ sub-element to describe where the device is placed on the
+ virtual bus presented to the guest. If an address is omitted on
+ input, libvirt will generate an appropriate address; but an
+ explicit address is required if more control over layout is
+ required. See below for device examples including an address
+ element.
+ </p>
+
+ <p>
+ Every address has a mandatory attribute <code>type</code> that
+ describes which bus the device is on. The choice of which
+ address to use for a given device is constrained in part by the
+ device and the architecture of the guest. For example,
+ a <code><disk></code> device
+ uses <code>type='disk'</code>, while
+ a <code><console></code> device would
+ use <code>type='pci'</code> on i686 or x86_64 guests,
+ or <code>type='spapr-vio'</code> on PowerPC64 pseries guests.
+ Each address type has further optional attributes that control
+ where on the bus the device will be placed:
+ </p>
+
+ <dl>
+ <dt><code>type='pci'</code></dt>
+ <dd>PCI addresses have the following additional
+ attributes: <code>domain</code> (a 2-byte hex integer, not
+ currently used by qemu), <code>bus</code> (a hex value between
+ 0 and 0xff, inclusive), <code>slot</code> (a hex value between
+ 0x0 and 0x1f, inclusive), and <code>function</code> (a value
+ between 0 and 7, inclusive). Also available is
+ the <code>multifunction</code> attribute, which controls
+ turning on the multifunction bit for a particular
+ slot/function in the PCI control register
+ (<span class="since">since 0.9.7, requires QEMU
+ 0.13</span>). <code>multifunction</code> defaults to 'off',
+ but should be set to 'on' for function 0 of a slot that will
+ have multiple functions used.
+ </dd>
+ <dt><code>type='drive'</code></dt>
+ <dd>Drive addresses have the following additional
+ attributes: <code>controller</code> (a 2-digit controller
+ number), <code>bus</code> (a 2-digit bus number),
+ and <code>unit</code> (a 2-digit unit number on the bus).
+ </dd>
+ <dt><code>type='virtio-serial'</code></dt>
+ <dd>Each virtio-serial address has the following additional
+ attributes: <code>controller</code> (a 2-digit controller
+ number), <code>bus</code> (a 2-digit bus number),
+ and <code>slot</code> (a 2-digit slot within the bus).
+ </dd>
+ <dt><code>type='ccid'</code></dt>
+ <dd>A CCID address, for smart-cards, has the following
+ additional attributes: <code>bus</code> (a 2-digit bus
+ number), and <code>slot</code> attribute (a 2-digit slot
+ within the bus). <span class="since">Since 0.8.8.</span>
+ <dt><code>type='usb'</code></dt>
+ <dd>USB addresses have the following additional
+ attributes: <code>bus</code> (a hex value between 0 and 0xfff,
+ inclusive), and <code>port</code> (a dotted notation of up to
+ four octets, such as 1.2 or 2.1.3.1).
+ </dd>
+ <dt><code>type='spapr-vio'</code></dt>
+ <dd>On PowerPC guests, devices are assigned on the SPAPR-VIO
+ bus, which is a flat 64-bit address space, where each address
+ should be aligned on a multiple of 0x1000. Each address has
+ the following additional attribute: <code>reg</code> (the hex
+ value address of the starting
+ register). <span class="since">Since 0.9.9.</span>
+ </dd>
+ </dl>
+
<h4><a name="elementsControllers">Controllers</a></h4>
<p>
- Many devices that have an <code><address></code>
- sub-element are designed to work with a controller to manage
- related devices. Normally, libvirt can automatically infer such
+ Depending on the guest architecture, some device busses can
+ appear more than once, with a group of virtual devices tied to a
+ virtual controller. Normally, libvirt can automatically infer such
controllers without requiring explicit XML markup, but sometimes
it is necessary to provide an explicit controller element.
</p>
@@ -1443,15 +1518,15 @@
A "usb" controller has an optional attribute <code>model</code>,
which is one of "piix3-uhci", "piix4-uhci", "ehci",
"ich9-ehci1", "ich9-uhci1", "ich9-uhci2", "ich9-uhci3",
- "vt82c686b-uhci" or "pci-ohci".
+ "vt82c686b-uhci" or "pci-ohci". The PowerPC64 "spapr-vio"
+ addresses do not have an associated controller.
</p>
<p>
For controllers that are themselves devices on a PCI or USB bus,
an optional sub-element <code><address></code> can specify
the exact relationship of the controller to its master bus, with
- semantics like any other device's <code>address</code>
- sub-element.
+ semantics <a href="#elementsAddress">given above</a>.
</p>
<p>
@@ -1608,19 +1683,9 @@
(starting with 0x) or octal (starting with 0) form.
For PCI devices the element carries 3 attributes allowing to designate
the device as can be found with the <code>lspci</code> or
- with <code>virsh nodedev-list</code>. The
- <code>bus</code> attribute allows the hexadecimal values 0 to ff, the
- <code>slot</code> attribute allows the hexadecimal values 0 to 1f, and
- the <code>function</code> attribute allows the hexadecimal values 0 to 7.
- The <code>multifunction</code> attribute controls turning on the
- multifunction bit for a particular slot/function in the PCI
- control register<span class="since">since 0.9.7, requires QEMU
- 0.13</span>. <code>multifunction</code> defaults to 'off', but
- should be set to 'on' for function 0 of a slot that will have
- multiple functions used.
- There is also an optional <code>domain</code> attribute for
- the PCI domain, with hexadecimal values 0 to ffff, but it is
- currently not used by qemu.</dd>
+ with <code>virsh
+ nodedev-list</code>. <a href="elementsAddress">See above</a> for
+ more details on the address element.
</dl>
<h4><a name="elementsRedir">Redirected devices</a></h4>
@@ -1756,12 +1821,9 @@
<p>
Each mode supports an optional
sub-element <code><address></code>, which fine-tunes the
- correlation between the smartcard and a ccid bus controller.
- If present, the element must have an attribute
- of <code>type='ccid'</code> as well as a <code>bus</code>
- attribute listing the index of the bus that the smartcard
- utilizes. An optional <code>slot</code> attribute lists which
- slot within the bus. For now, qemu only supports at most one
+ correlation between the smartcard and a ccid bus
+ controller, <a href="#elementsAddress">documented above</a>.
+ For now, qemu only supports at most one
smartcard, with an address of bus=0 slot=0.
</p>
@@ -1786,10 +1848,8 @@
each <code><interface></code> element has an
optional <code><address></code> sub-element that can tie
the interface to a particular pci slot, with
- attribute <code>type='pci'</code> and additional
- attributes <code>domain</code>, <code>bus</code>, <code>slot</code>,
- <code>function</code>, and <code>multifunction</code>
- <span class="since">since 0.9.7, requires QEMU 0.13</span> as appropriate.
+ attribute <code>type='pci'</code>
+ as <a href="#elementsAddress">documented above</a>.
</p>
<h5><a name="elementsNICSVirtual">Virtual network</a></h5>
@@ -2387,7 +2447,8 @@ qemu-kvm -net nic,model=? /dev/null
<p>
The <code>input</code> element has an optional
sub-element <code><address></code> which can tie the
- device to a particular PCI slot.
+ device to a particular PCI
+ slot, <a href="#elementsAddress">documented above</a>.
</p>
<h4><a name="elementsHub">Hub devices</a></h4>
@@ -2413,8 +2474,10 @@ qemu-kvm -net nic,model=? /dev/null
<p>
The <code>hub</code> element has an optional
- sub-element <code><address></code> which can tie the
- device to a particular controller.
+ sub-element <code><address></code>
+ with <code>type='usb'</code>which can tie the device to a
+ particular controller, <a href="#elementsAddress">documented
+ above</a>.
</p>
<h4><a name="elementsGraphics">Graphical framebuffers</a></h4>
@@ -2876,7 +2939,8 @@ qemu-kvm -net nic,model=? /dev/null
/dev/virtio-ports/$name (for more info, please see
<a href="http://fedoraproject.org/wiki/Features/VirtioSerial">http://fedoraproject.org/wiki/Features/VirtioSerial</a>). The
optional element <code>address</code> can tie the channel to a
- particular <code>type='virtio-serial'</code> controller.
+ particular <code>type='virtio-serial'</code>
+ controller, <a href="#elementsAddress">documented above</a>.
<span class="since">Since 0.7.7</span></dd>
<dt><code>spicevmc</code></dt>
@@ -3152,7 +3216,8 @@ qemu-kvm -net nic,model=? /dev/null
<p>
Each <code>sound</code> element has an optional
sub-element <code><address></code> which can tie the
- device to a particular PCI slot.
+ device to a particular PCI
+ slot, <a href="#elementsAddress">documented above</a>.
</p>
<h4><a name="elementsWatchdog">Watchdog device</a></h4>
--
1.7.7.3
3
4
[libvirt] [PATCH]add a qemu-specific event register API, to passthough the new events come from qemu
by ShaoHe Feng 12 Dec '11
by ShaoHe Feng 12 Dec '11
12 Dec '11
Basically, this feature can go along with qemu monitor passthrough.
That way, if we use new commands in the monitor that generate new
events, we want some way to receive those new events too.
In order to test this patch, see the attached python test case. When
domains are started, it will be able to catch RESUME events.
and the attached
0002-for-testing-the-new-qemu-specific-regiater-API.patch is used to
test the c code API.
# ./tools/virsh -c qemu:///system
virsh # register-event RESUME
virsh # start domain
Signed-off-by: Shao He Feng <shaohef(a)linux.vnet.ibm.com>
---
daemon/libvirtd.h | 12 +-
daemon/remote.c | 195 ++++++++++++++++++-
include/libvirt/libvirt-qemu.h | 11 +
include/libvirt/libvirt.h.in | 17 ++-
python/generator.py | 26 ++-
python/libvirt-override-virConnect.py | 14 ++-
python/libvirt-qemu-override.c | 140 +++++++++++++
python/libvirt-qemu-override.py | 41 ++++
src/conf/domain_event.c | 347
+++++++++++++++++++++++++++++++--
src/conf/domain_event.h | 49 +++++-
src/driver.h | 14 ++
src/libvirt-qemu.c | 190 ++++++++++++++++++
src/libvirt_private.syms | 6 +
src/libvirt_qemu.syms | 5 +
src/qemu/qemu_driver.c | 42 ++++
src/qemu/qemu_monitor.c | 10 +
src/qemu/qemu_monitor.h | 8 +
src/qemu/qemu_monitor_json.c | 36 ++++
src/qemu/qemu_process.c | 24 +++
src/remote/qemu_protocol.x | 33 +++-
src/remote/remote_driver.c | 153 ++++++++++++++-
src/remote/remote_protocol.x | 9 +-
src/remote_protocol-structs | 5 +
23 files changed, 1353 insertions(+), 34 deletions(-)
mode change 100644 => 100755 python/libvirt-override-virConnect.py
mode change 100644 => 100755 python/libvirt-override-virStream.py
mode change 100644 => 100755 python/libvirt-override.py
create mode 100644 python/libvirt-qemu-override.py
diff --git a/daemon/libvirtd.h b/daemon/libvirtd.h
index c8d3ca2..e3e1c40 100644
--- a/daemon/libvirtd.h
+++ b/daemon/libvirtd.h
@@ -38,6 +38,16 @@
# endif
# include "virnetserverprogram.h"
+/* limit the number unknow event of an conncet can register */
+#define VIR_DOMAIN_EVENT_NAME_LAST 512
+struct domainEventNameCallBackStatus {
+ /* counter the number of unknow event registered */
+ int eventNameCallBackCounter;
+ /* Stores the ID of the unknow event registered */
+ int eventNameCallback[VIR_DOMAIN_EVENT_NAME_LAST];
+};
+typedef struct domainEventNameCallBackStatus domainEventNameCallBackStatus;
+
typedef struct daemonClientStream daemonClientStream;
typedef daemonClientStream *daemonClientStreamPtr;
typedef struct daemonClientPrivate daemonClientPrivate;
@@ -49,7 +59,7 @@ struct daemonClientPrivate {
virMutex lock;
int domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LAST];
-
+ domainEventNameCallBackStatus domainEventNameCallBack;
# if HAVE_SASL
virNetSASLSessionPtr sasl;
# endif
diff --git a/daemon/remote.c b/daemon/remote.c
index e1d208c..bc8455d 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -421,6 +421,54 @@ mem_error:
return -1;
}
+static int remoteRelayDomainEventUnknown(virConnectPtr conn
ATTRIBUTE_UNUSED,
+ virDomainPtr dom,
+ const char *eventName, /* The
JSON event name */
+ const char *eventArgs, /* The
JSON string of args */
+ void *opaque)
+{
+ virNetServerClientPtr client = opaque;
+ remote_domain_event_default_event_msg data;
+
+ if (!client)
+ return -1;
+
+ VIR_DEBUG("Relaying domain: %s id: %d, unknown event: %s arguments:
%s",
+ dom->name, dom->id, eventName, eventArgs);
+
+ /* build return data */
+ memset(&data, 0, sizeof data);
+ if (eventName == NULL)
+ goto mem_error3;
+ data.eventName = (char *)strdup(eventName);
+ if (data.eventName == NULL)
+ goto mem_error2;
+ if (eventArgs != NULL) {
+ data.eventArgs = (char *)strdup(eventArgs);
+ if (data.eventArgs == NULL)
+ goto mem_error1;
+ }
+ else {
+ data.eventArgs = (char *)strdup("NULL");
+ if (data.eventArgs == NULL)
+ goto mem_error1;
+ }
+ make_nonnull_domain(&data.dom, dom);
+ remoteDispatchDomainEventSend(client, remoteProgram,
+
REMOTE_PROC_QEMU_DOMAIN_EVENT_UNKNOWN_EVENT,
+
(xdrproc_t)xdr_remote_domain_event_default_event_msg, &data);
+
+ return 0;
+
+mem_error1:
+ VIR_FREE(data.eventArgs);
+mem_error2:
+ VIR_FREE(data.eventName);
+mem_error3:
+ virReportOOMError();
+ return -1;
+}
+
static int remoteRelayDomainEventControlError(virConnectPtr conn
ATTRIBUTE_UNUSED,
virDomainPtr dom,
@@ -509,6 +557,7 @@ static virConnectDomainEventGenericCallback
domainEventCallbacks[] = {
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventControlError),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBlockJob),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDiskChange),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventUnknown),
};
verify(ARRAY_CARDINALITY(domainEventCallbacks) ==
VIR_DOMAIN_EVENT_ID_LAST);
@@ -526,10 +575,21 @@ static void remoteClientFreeFunc(void *data)
/* Deregister event delivery callback */
if (priv->conn) {
- int i;
+ int i, j;
for (i = 0 ; i < VIR_DOMAIN_EVENT_ID_LAST ; i++) {
- if (priv->domainEventCallbackID[i] != -1) {
+ if (i == VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN &&
priv->domainEventCallbackID[i] != -1) {
+ for (j = 0 ; j < VIR_DOMAIN_EVENT_NAME_LAST ; j++){
+ if
(priv->domainEventNameCallBack.eventNameCallback[j] != -1) {
+ VIR_DEBUG("Deregistering to relay remote events
%d", i);
+ virConnectDomainQemuEventDeregister(priv->conn,
+
priv->domainEventNameCallBack.eventNameCallback[j]);
+ }
+ priv->domainEventNameCallBack.eventNameCallback[j]
== -1;
+ }
+ priv->domainEventNameCallBack.eventNameCallBackCounter = 0;
+ }
+ else if (priv->domainEventCallbackID[i] != -1) {
VIR_DEBUG("Deregistering to relay remote events %d", i);
virConnectDomainEventDeregisterAny(priv->conn,
priv->domainEventCallbackID[i]);
@@ -572,6 +632,10 @@ int remoteClientInitHook(virNetServerPtr srv
ATTRIBUTE_UNUSED,
for (i = 0 ; i < VIR_DOMAIN_EVENT_ID_LAST ; i++)
priv->domainEventCallbackID[i] = -1;
+ priv->domainEventNameCallBack.eventNameCallBackCounter = 0;
+ for (i = 0 ; i < VIR_DOMAIN_EVENT_NAME_LAST ; i++)
+ priv->domainEventNameCallBack.eventNameCallback[i] = -1;
+
virNetServerClientSetPrivateData(client, priv,
remoteClientFreeFunc);
virNetServerClientSetCloseHook(client, remoteClientCloseFunc);
@@ -2991,6 +3055,133 @@ cleanup:
}
static int
+qemuDispatchDomainEventsRegister(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client
ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ qemu_domain_events_register_args *args,
+ qemu_domain_events_register_ret *ret
ATTRIBUTE_UNUSED)
+{
+ int callbackID = -1;
+ int rv = -1;
+ int eventIdx = 0;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+ if (!priv->conn) {
+ virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not
open"));
+ goto cleanup;
+ }
+
+ virMutexLock(&priv->lock);
+
+ if (args->eventName == NULL) {
+ virNetError(VIR_ERR_INTERNAL_ERROR, _("event Name is NULL"));
+ goto cleanup;
+ }
+ if (priv->domainEventNameCallBack.eventNameCallBackCounter >=
VIR_DOMAIN_EVENT_NAME_LAST) {
+ virNetError(VIR_ERR_INTERNAL_ERROR,
+ _("domain event %s is not registered, the register
number has exceeded limit number %d"),
+ args->eventName,
+ VIR_DOMAIN_EVENT_NAME_LAST);
+ goto cleanup;
+ }
+
+ if ((callbackID = virConnectDomainQemuEventRegister(priv->conn,
+ NULL,
+ args->eventName,
+
(virConnectDomainQemuEventCallback)remoteRelayDomainEventUnknown,
+ client,
+ NULL)) < 0)
+ goto cleanup;
+
+ for (eventIdx = 0 ; eventIdx < VIR_DOMAIN_EVENT_NAME_LAST ;
eventIdx++) {
+ if (priv->domainEventNameCallBack.eventNameCallback[eventIdx]
== -1) {
+ priv->domainEventNameCallBack.eventNameCallback[eventIdx] =
callbackID;
+ priv->domainEventNameCallBack.eventNameCallBackCounter++;
+ ret->callbackID = eventIdx;
+ break;
+ }
+ }
+ priv->domainEventCallbackID[VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN] =
callbackID;
+
+ rv = 0;
+
+cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virMutexUnlock(&priv->lock);
+ return rv;
+}
+
+static int
+remoteDispatchQemuDomainEventUnknownEvent(virNetServerPtr server,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg,
+ virNetMessageErrorPtr rerr)
+{
+ int rv = -1;
+ return rv;
+}
+
+static int
+qemuDispatchDomainEventsUnknownEvent(virNetServerPtr server,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg,
+ virNetMessageErrorPtr rerr,
+
qemu_domain_events_unknown_event_args *args,
+
qemu_domain_events_unknown_event_ret *ret)
+{
+ int rv = -1;
+ return rv;
+}
+
+static int
+qemuDispatchDomainEventsDeregister(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client
ATTRIBUTE_UNUSED,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ qemu_domain_events_deregister_args
*args,
+ qemu_domain_events_deregister_ret
*ret ATTRIBUTE_UNUSED)
+{
+ int callbackID = -1;
+ int rv = -1;
+ int eventIdx = args->callbackID;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not
open"));
+ goto cleanup;
+ }
+
+ virMutexLock(&priv->lock);
+
+ if (eventIdx >= VIR_DOMAIN_EVENT_NAME_LAST ||
+ (callbackID =
priv->domainEventNameCallBack.eventNameCallback[eventIdx]) < 0) {
+
+ virNetError(VIR_ERR_INTERNAL_ERROR, _("callbakcID %d is not
register"), eventIdx);
+ goto cleanup;
+ }
+
+ if (virConnectDomainQemuEventDeregister(priv->conn, callbackID) < 0)
+ goto cleanup;
+ ret->cb_deregistered = callbackID;
+
+ priv->domainEventNameCallBack.eventNameCallback[eventIdx] = -1;
+ priv->domainEventNameCallBack.eventNameCallBackCounter--;
+ if (priv->domainEventNameCallBack.eventNameCallBackCounter == 0)
+ priv->domainEventCallbackID[VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN] = -1;
+
+ rv = 0;
+
+cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virMutexUnlock(&priv->lock);
+ return rv;
+}
+
+static int
qemuDispatchMonitorCommand(virNetServerPtr server ATTRIBUTE_UNUSED,
virNetServerClientPtr client ATTRIBUTE_UNUSED,
virNetMessagePtr msg ATTRIBUTE_UNUSED,
diff --git a/include/libvirt/libvirt-qemu.h b/include/libvirt/libvirt-qemu.h
index 7f12e4f..74efe79 100644
--- a/include/libvirt/libvirt-qemu.h
+++ b/include/libvirt/libvirt-qemu.h
@@ -32,6 +32,17 @@ virDomainPtr virDomainQemuAttach(virConnectPtr domain,
unsigned int pid,
unsigned int flags);
+int
+virConnectDomainQemuEventRegister(virConnectPtr conn,
+ virDomainPtr dom, /* option to filter */
+ const char *eventName, /* JSON event
name */
+ virConnectDomainQemuEventCallback cb,
+ void *opaque,
+ virFreeCallback freecb);
+int
+virConnectDomainQemuEventDeregister(virConnectPtr conn,
+ int callbackID);
+
# ifdef __cplusplus
}
# endif
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 2480add..99e1c5d 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -3207,7 +3207,21 @@ typedef void
(*virConnectDomainEventBlockJobCallback)(virConnectPtr conn,
int type,
int status,
void *opaque);
-
+/**
+ * virConnectDomainQemuEventCallback:
+ * @conn: connection object
+ * @dom: domain on which the event occurred
+ * @eventName : the name of the unknow or un-implementation event
+ * @eventArgs: the content of the unknow or un-implementation event
+ *
+ * The callback signature to use when registering for an event of type
+ * VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN with
virConnectDomainQemuEventRegister()
+ */
+typedef void (*virConnectDomainQemuEventCallback)(virConnectPtr conn,
+ virDomainPtr dom,
+ const char
*eventName, /* The JSON event name */
+ const char
*eventArgs, /* The JSON string of args */
+ void *opaque);
/**
* virConnectDomainEventDiskChangeReason:
*
@@ -3263,6 +3277,7 @@ typedef enum {
VIR_DOMAIN_EVENT_ID_CONTROL_ERROR = 7, /*
virConnectDomainEventGenericCallback */
VIR_DOMAIN_EVENT_ID_BLOCK_JOB = 8, /*
virConnectDomainEventBlockJobCallback */
VIR_DOMAIN_EVENT_ID_DISK_CHANGE = 9, /*
virConnectDomainEventDiskChangeCallback */
+ VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN = 10, /*
virConnectDomainEventDefaultCallback */
/*
* NB: this enum value will increase over time as new events are
diff --git a/python/generator.py b/python/generator.py
index 88c52b9..3d13622 100755
--- a/python/generator.py
+++ b/python/generator.py
@@ -234,6 +234,7 @@ skipped_types = {
# 'int *': "usually a return type",
'virConnectDomainEventCallback': "No function types in python",
'virConnectDomainEventGenericCallback': "No function types in python",
+ 'virConnectDomainQemuEventCallback': "No function types in python",
'virConnectDomainEventRTCChangeCallback': "No function types in
python",
'virConnectDomainEventWatchdogCallback': "No function types in
python",
'virConnectDomainEventIOErrorCallback': "No function types in python",
@@ -476,6 +477,8 @@ skip_function = (
qemu_skip_function = (
#"virDomainQemuAttach",
+ 'virConnectDomainQemuEventRegister', # overridden in
libvirt_qemu_override.py
+ 'virConnectDomainQemuEventDeregister', # overridden in
libvirt_qemu_override.py
)
# Generate C code, but skip python impl
@@ -1656,17 +1659,18 @@ def qemuBuildWrappers(module):
if extra != None:
extra.close()
- fd.write("try:\n")
- fd.write(" import libvirtmod_qemu\n")
- fd.write("except ImportError, lib_e:\n")
- fd.write(" try:\n")
- fd.write(" import cygvirtmod_qemu as libvirtmod_qemu\n")
- fd.write(" except ImportError, cyg_e:\n")
- fd.write(" if str(cyg_e).count(\"No module named\"):\n")
- fd.write(" raise lib_e\n\n")
-
- fd.write("import libvirt\n\n");
- fd.write("#\n# Functions from module %s\n#\n\n" % module)
+ if extra == None:
+ fd.write("try:\n")
+ fd.write(" import libvirtmod_qemu\n")
+ fd.write("except ImportError, lib_e:\n")
+ fd.write(" try:\n")
+ fd.write(" import cygvirtmod_qemu as libvirtmod_qemu\n")
+ fd.write(" except ImportError, cyg_e:\n")
+ fd.write(" if str(cyg_e).count(\"No module named\"):\n")
+ fd.write(" raise lib_e\n\n")
+
+ fd.write("import libvirt\n\n");
+ fd.write("#\n# Functions from module %s\n#\n\n" % module)
#
# Generate functions directly, no classes
#
diff --git a/python/libvirt-override-virConnect.py
b/python/libvirt-override-virConnect.py
old mode 100644
new mode 100755
index b908b32..ce34bcf
--- a/python/libvirt-override-virConnect.py
+++ b/python/libvirt-override-virConnect.py
@@ -134,8 +134,20 @@
cb(self, virDomain(self, _obj=dom), oldSrcPath, newSrcPath,
devAlias, reason, opaque)
return 0;
+ def _dispatchDomainEventUnknownCallback(self, dom, eventName,
eventArgs, cbData):
+ """Dispatches events to python user unknown event callbacks
+ """
+ try:
+ cb = cbData["cb"]
+ opaque = cbData["opaque"]
+
+ cb(self, virDomain(self, _obj=dom), eventName, eventArgs,
opaque)
+ return 0
+ except AttributeError:
+ pass
+
def domainEventDeregisterAny(self, callbackID):
- """Removes a Domain Event Callback. De-registering for a
+ """Removes a QEMU Domain Event Callback. De-registering for a
domain callback will disable delivery of this event type """
try:
ret =
libvirtmod.virConnectDomainEventDeregisterAny(self._o, callbackID)
diff --git a/python/libvirt-override-virStream.py
b/python/libvirt-override-virStream.py
old mode 100644
new mode 100755
diff --git a/python/libvirt-override.py b/python/libvirt-override.py
old mode 100644
new mode 100755
diff --git a/python/libvirt-qemu-override.c b/python/libvirt-qemu-override.c
index 485c809..f5a8c09 100644
--- a/python/libvirt-qemu-override.c
+++ b/python/libvirt-qemu-override.c
@@ -18,6 +18,7 @@
#include <Python.h>
#include "libvirt/libvirt-qemu.h"
+#include "libvirt/libvirt.h"
#include "libvirt/virterror.h"
#include "typewrappers.h"
#include "libvirt-qemu.h"
@@ -96,6 +97,143 @@ libvirt_qemu_virDomainQemuMonitorCommand(PyObject
*self ATTRIBUTE_UNUSED,
return(py_retval);
}
+static void
+libvirt_qemu_virConnectDomainEventFreeFunc(void *opaque)
+{
+ PyObject *pyobj_conn = (PyObject*)opaque;
+ LIBVIRT_ENSURE_THREAD_STATE;
+ Py_DECREF(pyobj_conn);
+ LIBVIRT_RELEASE_THREAD_STATE;
+}
+
+static int
+libvirt_qemu_virConnectDomainEventUnknownCallback(virConnectPtr conn
ATTRIBUTE_UNUSED,
+ virDomainPtr dom,
+ const char *eventName,
+ const char *eventArgs,
+ void *opaque)
+{
+ PyObject *pyobj_cbData = (PyObject*)opaque;
+ PyObject *pyobj_dom;
+ PyObject *pyobj_ret;
+ PyObject *pyobj_conn;
+ PyObject *dictKey;
+ int ret = -1;
+
+ LIBVIRT_ENSURE_THREAD_STATE;
+
+ /* Create a python instance of this virDomainPtr */
+ virDomainRef(dom);
+ pyobj_dom = libvirt_virDomainPtrWrap(dom);
+ Py_INCREF(pyobj_cbData);
+
+ dictKey = libvirt_constcharPtrWrap("conn");
+ pyobj_conn = PyDict_GetItem(pyobj_cbData, dictKey);
+ Py_DECREF(dictKey);
+
+ /* Call the Callback Dispatcher */
+ pyobj_ret = PyObject_CallMethod(pyobj_conn,
+
(char*)"_dispatchDomainEventUnknownCallback",
+ (char*)"OssO",
+ pyobj_dom, eventName, eventArgs,
pyobj_cbData);
+
+ Py_DECREF(pyobj_cbData);
+ Py_DECREF(pyobj_dom);
+
+ if (!pyobj_ret) {
+#if DEBUG_ERROR
+ printf("%s - ret:%p\n", __FUNCTION__, pyobj_ret);
+#endif
+ PyErr_Print();
+ } else {
+ Py_DECREF(pyobj_ret);
+ ret = 0;
+ }
+
+ LIBVIRT_RELEASE_THREAD_STATE;
+ return ret;
+}
+
+static PyObject *
+libvirt_qemu_virConnectDomainQemuEventRegister(ATTRIBUTE_UNUSED
PyObject * self,
+ PyObject * args)
+{
+ PyObject *py_retval; /* return value */
+ PyObject *pyobj_conn; /* virConnectPtr */
+ PyObject *pyobj_dom;
+ PyObject *pyobj_cbData; /* hash of callback data */
+ char *eventName;
+ virConnectPtr conn;
+ int ret = 0;
+
+ virConnectDomainQemuEventCallback cb = NULL;
+ virDomainPtr dom;
+
+ if (!PyArg_ParseTuple
+ (args, (char *) "OOsO:virConnectDomainQemuEventRegister",
+ &pyobj_conn, &pyobj_dom, &eventName, &pyobj_cbData)) {
+ DEBUG("%s failed parsing tuple\n", __FUNCTION__);
+ return VIR_PY_INT_FAIL;
+ }
+
+ if (eventName == NULL)
+ return VIR_PY_INT_FAIL;
+
+ DEBUG("libvirt_qemu_virConnectDomainQemuEventRegister(%p %p %s %p)
called\n",
+ pyobj_conn, pyobj_dom, eventName, pyobj_cbData);
+ conn = PyvirConnect_Get(pyobj_conn);
+ if (pyobj_dom == Py_None)
+ dom = NULL;
+ else
+ dom = PyvirDomain_Get(pyobj_dom);
+
+ cb =
(virConnectDomainQemuEventCallback)(libvirt_qemu_virConnectDomainEventUnknownCallback);
+ if (!cb) {
+ return VIR_PY_INT_FAIL;
+ }
+
+ Py_INCREF(pyobj_cbData);
+
+ LIBVIRT_BEGIN_ALLOW_THREADS;
+ ret = virConnectDomainQemuEventRegister(conn, dom, eventName,
+ cb, pyobj_cbData,
+
libvirt_qemu_virConnectDomainEventFreeFunc);
+ LIBVIRT_END_ALLOW_THREADS;
+ if (ret < 0) {
+ Py_DECREF(pyobj_cbData);
+ }
+ py_retval = libvirt_intWrap(ret);
+ return (py_retval);
+}
+
+static PyObject *
+libvirt_qemu_virConnectDomainQemuEventDeregister(ATTRIBUTE_UNUSED
PyObject * self,
+ PyObject * args)
+{
+ PyObject *py_retval;
+ PyObject *pyobj_conn;
+ int callbackID;
+ virConnectPtr conn;
+ int ret = 0;
+
+ if (!PyArg_ParseTuple
+ (args, (char *) "Oi:virConnectDomainQemuEventDeregister",
+ &pyobj_conn, &callbackID))
+ return (NULL);
+
+ DEBUG("libvirt_qemu_virConnectDomainQemuEventDeregister(%p)
called\n", pyobj_conn);
+
+ conn = (virConnectPtr) PyvirConnect_Get(pyobj_conn);
+
+ LIBVIRT_BEGIN_ALLOW_THREADS;
+
+ ret = virConnectDomainQemuEventDeregister(conn, callbackID);
+
+ LIBVIRT_END_ALLOW_THREADS;
+ py_retval = libvirt_intWrap(ret);
+ return (py_retval);
+}
+
/************************************************************************
* *
* The registration stuff *
@@ -104,6 +242,8 @@ libvirt_qemu_virDomainQemuMonitorCommand(PyObject
*self ATTRIBUTE_UNUSED,
static PyMethodDef libvirtQemuMethods[] = {
#include "libvirt-qemu-export.c"
{(char *) "virDomainQemuMonitorCommand",
libvirt_qemu_virDomainQemuMonitorCommand, METH_VARARGS, NULL},
+ {(char *) "virConnectDomainQemuEventRegister",
libvirt_qemu_virConnectDomainQemuEventRegister, METH_VARARGS, NULL},
+ {(char *) "virConnectDomainQemuEventDeregister",
libvirt_qemu_virConnectDomainQemuEventDeregister, METH_VARARGS, NULL},
{NULL, NULL, 0, NULL}
};
diff --git a/python/libvirt-qemu-override.py
b/python/libvirt-qemu-override.py
new file mode 100644
index 0000000..0f5694c
--- /dev/null
+++ b/python/libvirt-qemu-override.py
@@ -0,0 +1,41 @@
+#
+# Manually written part of python bindings for libvirt_qemu
+#
+
+# On cygwin, the DLL is called cygvirtmod.dll
+try:
+ import libvirtmod_qemu
+except ImportError, lib_e:
+ try:
+ import cygvirtmod_qemu as libvirtmod_qemu
+ except ImportError, cyg_e:
+ if str(cyg_e).count("No module named"):
+ raise lib_e
+
+import libvirt
+import types
+
+def domainQemuEventDeregister(conn, callbackID):
+ """Removes a Domain Event Callback. De-registering for a
+ domain callback will disable delivery of this event type """
+ try:
+ ret =
libvirtmod_qemu.virConnectDomainQemuEventDeregister(conn._o, callbackID)
+ if ret == -1: raise libvirt.libvirtError
('virConnectDomainQemuEventDeregister() failed', conn)
+ del conn.domainEventCallbackID[callbackID]
+ except AttributeError:
+ pass
+
+def domainQemuEventRegister(conn, dom, eventName, cb, opaque):
+ """Adds a Domain Event Callback. Registering for a domain
+ callback will enable delivery of the events """
+ if not hasattr(conn, 'domainEventCallbackID'):
+ conn.domainEventCallbackID = {}
+ cbData = { "cb": cb, "conn": conn, "opaque": opaque }
+ if dom is None:
+ ret =
libvirtmod_qemu.virConnectDomainQemuEventRegister(conn._o, None,
eventName, cbData)
+ else:
+ ret =
libvirtmod_qemu.virConnectDomainQemuEventRegister(conn._o, dom._o,
eventName, cbData)
+ if ret == -1:
+ raise libvirt.libvirtError
('virConnectDomainQemuEventRegister() failed', conn)
+ conn.domainEventCallbackID[ret] = opaque
+ return ret
diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c
index 614ab97..b6a763a 100644
--- a/src/conf/domain_event.c
+++ b/src/conf/domain_event.c
@@ -45,7 +45,9 @@ typedef virDomainMeta *virDomainMetaPtr;
struct _virDomainEventCallback {
int callbackID;
+ int qemuCallbackID;
int eventID;
+ char *eventName;
virConnectPtr conn;
virDomainMetaPtr dom;
virConnectDomainEventGenericCallback cb;
@@ -94,6 +96,10 @@ struct _virDomainEvent {
char *devAlias;
int reason;
} diskChange;
+ struct {
+ char *eventName;
+ char *eventArgs;
+ }qemuUnknownEvent;
} data;
};
@@ -112,6 +118,8 @@
virDomainEventCallbackListFree(virDomainEventCallbackListPtr list)
for (i=0; i<list->count; i++) {
virFreeCallback freecb = list->callbacks[i]->freecb;
+ if (list->callbacks[i]->eventName)
+ VIR_FREE(list->callbacks[i]->eventName);
if (freecb)
(*freecb)(list->callbacks[i]->opaque);
VIR_FREE(list->callbacks[i]);
@@ -143,7 +151,6 @@ virDomainEventCallbackListRemove(virConnectPtr conn,
(*freecb)(cbList->callbacks[i]->opaque);
virUnrefConnect(cbList->callbacks[i]->conn);
VIR_FREE(cbList->callbacks[i]);
-
if (i < (cbList->count - 1))
memmove(cbList->callbacks + i,
cbList->callbacks + i + 1,
@@ -187,8 +194,11 @@ virDomainEventCallbackListRemoveID(virConnectPtr conn,
if (freecb)
(*freecb)(cbList->callbacks[i]->opaque);
virUnrefConnect(cbList->callbacks[i]->conn);
+ if (cbList->callbacks[i]->eventID ==
VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN) {
+ if (cbList->callbacks[i]->eventName)
+ VIR_FREE(cbList->callbacks[i]->eventName);
+ }
VIR_FREE(cbList->callbacks[i]);
-
if (i < (cbList->count - 1))
memmove(cbList->callbacks + i,
cbList->callbacks + i + 1,
@@ -212,6 +222,52 @@ virDomainEventCallbackListRemoveID(virConnectPtr conn,
/**
+ * virDomainQemuEventCallbackListRemoveID:
+ * @conn: pointer to the connection
+ * @cbList: the list
+ * @callback: the callback to remove
+ *
+ * Internal function to remove a callback from a
virDomainEventCallbackListPtr
+ */
+int
+virDomainQemuEventCallbackListRemoveID(virConnectPtr conn,
+ virDomainEventCallbackListPtr
cbList,
+ int callbackID)
+{
+ int i;
+ for (i = 0 ; i < cbList->count ; i++) {
+ if (cbList->callbacks[i]->callbackID == callbackID &&
+ cbList->callbacks[i]->conn == conn &&
+ cbList->callbacks[i]->eventID ==
VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN) {
+ virFreeCallback freecb = cbList->callbacks[i]->freecb;
+ if (freecb)
+ (*freecb)(cbList->callbacks[i]->opaque);
+ VIR_FREE(cbList->callbacks[i]->eventName);
+ virUnrefConnect(cbList->callbacks[i]->conn);
+ VIR_FREE(cbList->callbacks[i]);
+
+ if (i < (cbList->count - 1))
+ memmove(cbList->callbacks + i,
+ cbList->callbacks + i + 1,
+ sizeof(*(cbList->callbacks)) *
+ (cbList->count - (i + 1)));
+
+ if (VIR_REALLOC_N(cbList->callbacks,
+ cbList->count - 1) < 0) {
+ ; /* Failure to reduce memory allocation isn't fatal */
+ }
+ cbList->count--;
+ return 0;
+ }
+ }
+
+ eventReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("could not find event callback for removal"));
+ return -1;
+}
+
+
+/**
* virDomainEventCallbackListRemoveConn:
* @conn: pointer to the connection
* @cbList: the list
@@ -231,8 +287,11 @@ virDomainEventCallbackListRemoveConn(virConnectPtr
conn,
if (freecb)
(*freecb)(cbList->callbacks[i]->opaque);
virUnrefConnect(cbList->callbacks[i]->conn);
+ if (cbList->callbacks[i]->eventID ==
VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN) {
+ if (cbList->callbacks[i]->eventName)
+ VIR_FREE(cbList->callbacks[i]->eventName);
+ }
VIR_FREE(cbList->callbacks[i]);
-
if (i < (cbList->count - 1))
memmove(cbList->callbacks + i,
cbList->callbacks + i + 1,
@@ -299,8 +358,11 @@ int
virDomainEventCallbackListPurgeMarked(virDomainEventCallbackListPtr cbList)
if (freecb)
(*freecb)(cbList->callbacks[i]->opaque);
virUnrefConnect(cbList->callbacks[i]->conn);
+ if (cbList->callbacks[i]->eventID ==
VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN) {
+ if (cbList->callbacks[i]->eventName)
+ VIR_FREE(cbList->callbacks[i]->eventName);
+ }
VIR_FREE(cbList->callbacks[i]);
-
if (i < (cbList->count - 1))
memmove(cbList->callbacks + i,
cbList->callbacks + i + 1,
@@ -404,7 +466,98 @@ virDomainEventCallbackListAddID(virConnectPtr conn,
cbList->callbacks[cbList->count] = event;
cbList->count++;
+ event->callbackID = cbList->nextID++;
+
+ return event->callbackID;
+
+no_memory:
+ virReportOOMError();
+
+ if (event) {
+ if (event->dom)
+ VIR_FREE(event->dom->name);
+ VIR_FREE(event->dom);
+ }
+ VIR_FREE(event);
+ return -1;
+}
+
+
+
+/**
+ * virDomainEventCallbackListAddName:
+ * @conn: pointer to the connection
+ * @cbList: the list
+ * @eventName: the event eventName
+ * @callback: the callback to add
+ * @eventID: the specific eventID
+ * @opaque: opaque data tio pass to callback
+ *
+ * Internal function to add a callback from a virDomainEventCallbackListPtr
+ */
+int
+virDomainEventCallbackListAddName(virConnectPtr conn,
+ virDomainEventCallbackListPtr cbList,
+ virDomainPtr dom,
+ const char* eventName,
+ int eventID,
+ virConnectDomainEventGenericCallback
callback,
+ void *opaque,
+ virFreeCallback freecb)
+{
+ virDomainEventCallbackPtr event;
+ int i;
+
+ /* Check incoming */
+ if ( !cbList ) {
+ return -1;
+ }
+
+ /* check if we already have this callback on our list */
+ for (i = 0 ; i < cbList->count ; i++) {
+ if (cbList->callbacks[i]->cb ==
VIR_DOMAIN_EVENT_CALLBACK(callback) &&
+ !strcmp(cbList->callbacks[i]->eventName, eventName) &&
+ cbList->callbacks[i]->eventID == eventID &&
+ cbList->callbacks[i]->conn == conn) {
+ eventReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("event callback already tracked"));
+ return -1;
+ }
+ }
+ if (eventID > VIR_DOMAIN_EVENT_ID_LAST || eventID <
VIR_DOMAIN_EVENT_ID_LIFECYCLE) {
+ eventReportError(VIR_ERR_INTERNAL_ERROR, "%s: %d",
+ _("not suport this kind of eventID"), eventID);
+ }
+ /* Allocate new event */
+ if (VIR_ALLOC(event) < 0)
+ goto no_memory;
+ event->conn = conn;
+ event->cb = callback;
+ if (eventName == NULL)
+ goto no_memory;
+ event->eventName = strdup(eventName);
+ if ( event->eventName == NULL)
+ goto no_memory;
+ event->opaque = opaque;
+ event->freecb = freecb;
+ event->eventID = eventID;
+ if (dom) {
+ if (VIR_ALLOC(event->dom) < 0)
+ goto no_memory;
+ if (!(event->dom->name = strdup(dom->name)))
+ goto no_memory;
+ memcpy(event->dom->uuid, dom->uuid, VIR_UUID_BUFLEN);
+ event->dom->id = dom->id;
+ }
+
+ /* Make space on list */
+ if (VIR_REALLOC_N(cbList->callbacks, cbList->count + 1) < 0)
+ goto no_memory;
+
+ event->conn->refs++;
+ cbList->callbacks[cbList->count] = event;
+ cbList->count++;
event->callbackID = cbList->nextID++;
return event->callbackID;
@@ -416,11 +569,41 @@ no_memory:
if (event->dom)
VIR_FREE(event->dom->name);
VIR_FREE(event->dom);
+ if (event->eventName)
+ VIR_FREE(event->eventName);
}
VIR_FREE(event);
return -1;
}
+/**
+ * virDomainEventCallbackListAddQemuCallbackID:
+ * @conn: pointer to the connection
+ * @cbList: the list
+ * @callbackID: the libvirt callback ID
+ * @qemuCallbackID: the libvirtd callback ID to add
+ *
+ * Internal function to add a Daemon libvirtd callbackID
+ */
+int
+virDomainEventCallbackListAddQemuCallbackID(virConnectPtr conn,
+
virDomainEventCallbackListPtr cbList,
+ int callbackID,
+ int qemuCallbackID)
+{
+ int i;
+ for (i = 0 ; i < cbList->count ; i++) {
+ if (cbList->callbacks[i]->callbackID == callbackID &&
+ cbList->callbacks[i]->conn == conn) {
+ cbList->callbacks[i]->qemuCallbackID = qemuCallbackID;
+ return 0;
+ }
+ }
+
+ eventReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("could not find event callback for deletion"));
+ return -1;
+}
int virDomainEventCallbackListCountID(virConnectPtr conn,
virDomainEventCallbackListPtr cbList,
@@ -442,6 +625,27 @@ int virDomainEventCallbackListCountID(virConnectPtr
conn,
}
+int
+virDomainEventCallbackListCountName(virConnectPtr conn,
+ virDomainEventCallbackListPtr cbList,
+ const char *eventName)
+{
+ int i;
+ int count = 0;
+
+ for (i = 0 ; i < cbList->count ; i++) {
+ if (cbList->callbacks[i]->deleted)
+ continue;
+
+ if (!strcmp(cbList->callbacks[i]->eventName,eventName) &&
+ cbList->callbacks[i]->conn == conn)
+ count++;
+ }
+
+ return count;
+}
+
+
int virDomainEventCallbackListEventID(virConnectPtr conn,
virDomainEventCallbackListPtr cbList,
int callbackID)
@@ -461,6 +665,44 @@ int virDomainEventCallbackListEventID(virConnectPtr
conn,
}
+const char*
+virDomainEventCallbackListEventName(virConnectPtr conn,
+ virDomainEventCallbackListPtr cbList,
+ int callbackID)
+{
+ int i;
+
+ for (i = 0 ; i < cbList->count ; i++) {
+ if (cbList->callbacks[i]->deleted)
+ continue;
+
+ if (cbList->callbacks[i]->callbackID == callbackID &&
+ cbList->callbacks[i]->conn == conn)
+ return cbList->callbacks[i]->eventName;
+ }
+
+ return NULL;
+}
+
+int
+virDomainEventCallbackListEventQemuCallbackID(virConnectPtr conn,
+
virDomainEventCallbackListPtr cbList,
+ int callbackID)
+{
+ int i;
+
+ for (i = 0 ; i < cbList->count ; i++) {
+ if (cbList->callbacks[i]->deleted)
+ continue;
+
+ if (cbList->callbacks[i]->callbackID == callbackID &&
+ cbList->callbacks[i]->conn == conn)
+ return cbList->callbacks[i]->qemuCallbackID;
+ }
+
+ return -1;
+}
+
int virDomainEventCallbackListCount(virDomainEventCallbackListPtr cbList)
{
int i;
@@ -521,6 +763,11 @@ void virDomainEventFree(virDomainEventPtr event)
VIR_FREE(event->data.diskChange.newSrcPath);
VIR_FREE(event->data.diskChange.devAlias);
break;
+
+ case VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN:
+ VIR_FREE(event->data.qemuUnknownEvent.eventName);
+ VIR_FREE(event->data.qemuUnknownEvent.eventArgs);
+ break;
}
VIR_FREE(event->dom.name);
@@ -956,6 +1203,51 @@ virDomainEventPtr
virDomainEventBlockJobNewFromDom(virDomainPtr dom,
path, type, status);
}
+static virDomainEventPtr
+virDomainEventUnknownNew(int id, const char *name, unsigned char *uuid,
+ const char *eventName, const char *eventArgs)
+{
+ virDomainEventPtr ev =
+ virDomainEventNewInternal(VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN,
+ id, name, uuid);
+ if (ev) {
+ if (!(ev->data.qemuUnknownEvent.eventName = strdup(eventName))) {
+ virReportOOMError();
+ VIR_FREE(ev->dom.name);
+ VIR_FREE(ev);
+ return NULL;
+ }
+ if (eventArgs) {
+ if (!(ev->data.qemuUnknownEvent.eventArgs =
strdup(eventArgs))) {
+ virReportOOMError();
+ VIR_FREE(ev->data.qemuUnknownEvent.eventName);
+ VIR_FREE(ev->dom.name);
+ VIR_FREE(ev);
+ return NULL;
+ }
+ }
+ }
+
+ return ev;
+}
+
+virDomainEventPtr virDomainEventUnknownNewFromObj(virDomainObjPtr obj,
+ const char *eventName,
+ const char *eventArgs)
+{
+
+ return virDomainEventUnknownNew(obj->def->id, obj->def->name,
+ obj->def->uuid, eventName, eventArgs);
+}
+
+virDomainEventPtr virDomainEventUnknownNewFromDom(virDomainPtr dom,
+ const char *eventName,
+ const char *eventArgs)
+{
+ return virDomainEventUnknownNew(dom->id, dom->name, dom->uuid,
+ eventName, eventArgs);
+}
+
virDomainEventPtr virDomainEventControlErrorNewFromDom(virDomainPtr dom)
{
virDomainEventPtr ev =
@@ -1095,11 +1387,12 @@ virDomainEventQueuePush(virDomainEventQueuePtr
evtQueue,
}
-void virDomainEventDispatchDefaultFunc(virConnectPtr conn,
- virDomainEventPtr event,
-
virConnectDomainEventGenericCallback cb,
- void *cbopaque,
- void *opaque ATTRIBUTE_UNUSED)
+void
+virDomainEventDispatchDefaultFunc(virConnectPtr conn,
+ virDomainEventPtr event,
+ virConnectDomainEventGenericCallback cb,
+ void *cbopaque,
+ void *opaque ATTRIBUTE_UNUSED)
{
virDomainPtr dom = virGetDomain(conn, event->dom.name,
event->dom.uuid);
if (!dom)
@@ -1180,6 +1473,13 @@ void
virDomainEventDispatchDefaultFunc(virConnectPtr conn,
cbopaque);
break;
+ case VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN:
+ ((virConnectDomainQemuEventCallback)cb)(conn, dom,
+
event->data.qemuUnknownEvent.eventName,
+
event->data.qemuUnknownEvent.eventArgs,
+ cbopaque);
+ break;
+
default:
VIR_WARN("Unexpected event ID %d", event->eventID);
break;
@@ -1189,8 +1489,9 @@ void
virDomainEventDispatchDefaultFunc(virConnectPtr conn,
}
-static int virDomainEventDispatchMatchCallback(virDomainEventPtr event,
-
virDomainEventCallbackPtr cb)
+static int
+virDomainEventDispatchMatchCallback(virDomainEventPtr event,
+ virDomainEventCallbackPtr cb)
{
if (!cb)
return 0;
@@ -1198,7 +1499,12 @@ static int
virDomainEventDispatchMatchCallback(virDomainEventPtr event,
return 0;
if (cb->eventID != event->eventID)
return 0;
-
+ if (event->eventID == VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN) {
+ if(event->data.qemuUnknownEvent.eventName == NULL ||
+ cb->eventName == NULL ||
+ strcmp(cb->eventName,
event->data.qemuUnknownEvent.eventName) != 0)
+ return 0;
+ }
if (cb->dom) {
/* Deliberately ignoring 'id' for matching, since that
* will cause problems when a domain switches between
@@ -1341,3 +1647,20 @@ virDomainEventStateDeregisterAny(virConnectPtr conn,
virDomainEventStateUnlock(state);
return ret;
}
+int
+virDomainQemuEventStateDeregister(virConnectPtr conn,
+ virDomainEventStatePtr state,
+ int callbackID)
+{
+ int ret;
+
+ virDomainEventStateLock(state);
+ if (state->isDispatching)
+ ret = virDomainEventCallbackListMarkDeleteID(conn,
+ state->callbacks,
callbackID);
+ else
+ ret = virDomainQemuEventCallbackListRemoveID(conn,
+ state->callbacks,
callbackID);
+ virDomainEventStateUnlock(state);
+ return ret;
+}
diff --git a/src/conf/domain_event.h b/src/conf/domain_event.h
index 3ba418e..c0edfac 100644
--- a/src/conf/domain_event.h
+++ b/src/conf/domain_event.h
@@ -26,7 +26,6 @@
# define __DOMAIN_EVENT_H__
# include "domain_conf.h"
-
typedef struct _virDomainEventCallback virDomainEventCallback;
typedef virDomainEventCallback *virDomainEventCallbackPtr;
@@ -83,6 +82,15 @@ int virDomainEventCallbackListAddID(virConnectPtr conn,
virFreeCallback freecb)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(5);
+int virDomainEventCallbackListAddName(virConnectPtr conn,
+ virDomainEventCallbackListPtr cbList,
+ virDomainPtr dom,
+ const char* eventName,
+ int eventID,
+
virConnectDomainEventGenericCallback callback,
+ void *opaque,
+ virFreeCallback freecb)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(6);
int virDomainEventCallbackListRemove(virConnectPtr conn,
virDomainEventCallbackListPtr cbList,
@@ -92,6 +100,10 @@ int virDomainEventCallbackListRemoveID(virConnectPtr
conn,
virDomainEventCallbackListPtr
cbList,
int callbackID)
ATTRIBUTE_NONNULL(1);
+int virDomainQemuEventCallbackListRemoveID(virConnectPtr conn,
+
virDomainEventCallbackListPtr cbList,
+ int callbackID)
+ ATTRIBUTE_NONNULL(1);
int virDomainEventCallbackListRemoveConn(virConnectPtr conn,
virDomainEventCallbackListPtr
cbList)
ATTRIBUTE_NONNULL(1);
@@ -106,9 +118,14 @@ int
virDomainEventCallbackListMarkDeleteID(virConnectPtr conn,
int callbackID)
ATTRIBUTE_NONNULL(1);
-
int virDomainEventCallbackListPurgeMarked(virDomainEventCallbackListPtr
cbList);
+int virDomainEventCallbackListAddQemuCallbackID(virConnectPtr conn,
+
virDomainEventCallbackListPtr cbList,
+ int callbackID,
+ int qemuCallbackID)
+ ATTRIBUTE_NONNULL(1);
+
int virDomainEventCallbackListCount(virDomainEventCallbackListPtr cbList);
int virDomainEventCallbackListCountID(virConnectPtr conn,
virDomainEventCallbackListPtr cbList,
@@ -119,6 +136,21 @@ int virDomainEventCallbackListEventID(virConnectPtr
conn,
int callbackID)
ATTRIBUTE_NONNULL(1);
+int virDomainEventCallbackListCountName(virConnectPtr conn,
+ virDomainEventCallbackListPtr
cbList,
+ const char *eventName)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3);
+
+int virDomainEventCallbackListEventQemuCallbackID(virConnectPtr conn,
+
virDomainEventCallbackListPtr cbList,
+ int callbackID)
+ ATTRIBUTE_NONNULL(1);
+
+const char* virDomainEventCallbackListEventName(virConnectPtr conn,
+
virDomainEventCallbackListPtr cbList,
+ int callbackID)
+ ATTRIBUTE_NONNULL(1);
+
virDomainEventQueuePtr virDomainEventQueueNew(void);
virDomainEventPtr virDomainEventNew(int id, const char *name, const
unsigned char *uuid, int type, int detail);
@@ -190,6 +222,13 @@ virDomainEventPtr
virDomainEventDiskChangeNewFromDom(virDomainPtr dom,
const char *devAlias,
int reason);
+virDomainEventPtr virDomainEventUnknownNewFromObj(virDomainObjPtr obj,
+ const char *eventName,
+ const char *eventArgs);
+virDomainEventPtr virDomainEventUnknownNewFromDom(virDomainPtr dom,
+ const char *eventName,
+ const char *eventArgs);
+
int virDomainEventQueuePush(virDomainEventQueuePtr evtQueue,
virDomainEventPtr event);
@@ -246,5 +285,9 @@ virDomainEventStateDeregisterAny(virConnectPtr conn,
virDomainEventStatePtr state,
int callbackID)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
-
+int
+virDomainQemuEventStateDeregister(virConnectPtr conn,
+ virDomainEventStatePtr state,
+ int callbackID)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
#endif
diff --git a/src/driver.h b/src/driver.h
index 941ff51..51164a9 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -635,6 +635,18 @@ typedef virDomainPtr
unsigned int flags);
typedef int
+ (*virDrvDomainQemuEventRegister)(virConnectPtr conn,
+ virDomainPtr dom, /* option to
filter */
+ const char *eventName, /* JSON
event name */
+
virConnectDomainEventGenericCallback cb,
+ void *opaque,
+ virFreeCallback freecb);
+
+typedef int
+ (*virDrvDomainQemuEventDeregister)(virConnectPtr conn,
+ int callbackID);
+
+typedef int
(*virDrvDomainOpenConsole)(virDomainPtr dom,
const char *dev_name,
virStreamPtr st,
@@ -915,6 +927,8 @@ struct _virDriver {
virDrvDomainSnapshotDelete domainSnapshotDelete;
virDrvDomainQemuMonitorCommand qemuDomainMonitorCommand;
virDrvDomainQemuAttach qemuDomainAttach;
+ virDrvDomainQemuEventRegister qemuDomainQemuEventRegister;
+ virDrvDomainQemuEventDeregister qemuDomainQemuEventDeregister;
virDrvDomainOpenConsole domainOpenConsole;
virDrvDomainOpenGraphics domainOpenGraphics;
virDrvDomainInjectNMI domainInjectNMI;
diff --git a/src/libvirt-qemu.c b/src/libvirt-qemu.c
index 248cc33..c84375c 100644
--- a/src/libvirt-qemu.c
+++ b/src/libvirt-qemu.c
@@ -36,6 +36,77 @@
virReportErrorHelper(VIR_FROM_DOM, error, NULL, __FUNCTION__, \
__LINE__, info)
+/* Helper macros to implement VIR_DOMAIN_DEBUG using just C99. This
+ * assumes you pass fewer than 15 arguments to VIR_DOMAIN_DEBUG, but
+ * can easily be expanded if needed.
+ *
+ * Note that gcc provides extensions of "define a(b...) b" or
+ * "define a(b,...) b,##__VA_ARGS__" as a means of eliding a comma
+ * when no var-args are present, but we don't want to require gcc.
+ */
+#define VIR_ARG15(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12,
_13, _14, _15, ...) _15
+#define VIR_HAS_COMMA(...) VIR_ARG15(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 0)
+
+/* Form the name VIR_DOMAIN_DEBUG_[01], then call that macro,
+ * according to how many arguments are present. Two-phase due to
+ * macro expansion rules. */
+#define VIR_DOMAIN_DEBUG_EXPAND(a, b, ...) \
+ VIR_DOMAIN_DEBUG_PASTE(a, b, __VA_ARGS__)
+#define VIR_DOMAIN_DEBUG_PASTE(a, b, ...) \
+ a##b(__VA_ARGS__)
+
+/* Internal use only, when VIR_DOMAIN_DEBUG has one argument. */
+#define VIR_DOMAIN_DEBUG_0(dom) \
+ VIR_DOMAIN_DEBUG_2(dom, "%s", "")
+
+/* Internal use only, when VIR_DOMAIN_DEBUG has three or more
arguments. */
+#define VIR_DOMAIN_DEBUG_1(dom, fmt, ...) \
+ VIR_DOMAIN_DEBUG_2(dom, ", " fmt, __VA_ARGS__)
+
+/* Internal use only, with final format. */
+#define VIR_DOMAIN_DEBUG_2(dom, fmt, ...) \
+ do { \
+ char _uuidstr[VIR_UUID_STRING_BUFLEN]; \
+ const char *_domname = NULL; \
+ \
+ if (!VIR_IS_DOMAIN(dom)) { \
+ memset(_uuidstr, 0, sizeof(_uuidstr)); \
+ } else { \
+ virUUIDFormat((dom)->uuid, _uuidstr); \
+ _domname = (dom)->name; \
+ } \
+ \
+ VIR_DEBUG("dom=%p, (VM: name=%s, uuid=%s)" fmt, \
+ dom, NULLSTR(_domname), _uuidstr, __VA_ARGS__); \
+ } while (0)
+
+/**
+ * VIR_DOMAIN_DEBUG:
+ * @dom: domain
+ * @fmt: optional format for additional information
+ * @...: optional arguments corresponding to @fmt.
+ */
+#define VIR_DOMAIN_DEBUG(...) \
+ VIR_DOMAIN_DEBUG_EXPAND(VIR_DOMAIN_DEBUG_, \
+ VIR_HAS_COMMA(__VA_ARGS__), \
+ __VA_ARGS__)
+
+/**
+ * VIR_UUID_DEBUG:
+ * @conn: connection
+ * @uuid: possibly null UUID array
+ */
+#define VIR_UUID_DEBUG(conn, uuid) \
+ do { \
+ if (uuid) { \
+ char _uuidstr[VIR_UUID_STRING_BUFLEN]; \
+ virUUIDFormat(uuid, _uuidstr); \
+ VIR_DEBUG("conn=%p, uuid=%s", conn, _uuidstr); \
+ } else { \
+ VIR_DEBUG("conn=%p, uuid=(null)", conn); \
+ } \
+ } while (0)
+
/**
* virDomainQemuMonitorCommand:
* @domain: a domain object
@@ -178,3 +249,122 @@ error:
virDispatchError(conn);
return NULL;
}
+
+/**
+ * virConnectDomainQemuEventRegister:
+ * @conn: pointer to the connection
+ * @dom: pointer to the domain
+ * @eventName: the event Name to receive
+ * @cb: callback to the function handling domain events
+ * @opaque: opaque data to pass on to the callback
+ * @freecb: optional function to deallocate opaque when not used anymore
+ *
+ * Adds a callback to receive notifications of arbitrary qemu domain events
+ * occurring on a domain.
+ *
+ * If dom is NULL, then events will be monitored for any domain. If dom
+ * is non-NULL, then only the specific domain will be monitored
+ *
+ * Most types of event have a callback providing a custom set of parameters
+ * for the event. When registering an event, it is thus neccessary to use
+ * the VIR_DOMAIN_EVENT_CALLBACK() macro to cast the supplied function
pointer
+ * to match the signature of this method.
+ *
+ * The virDomainPtr object handle passed into the callback upon delivery
+ * of an event is only valid for the duration of execution of the callback.
+ * If the callback wishes to keep the domain object after the callback
returns,
+ * it shall take a reference to it, by calling virDomainRef.
+ * The reference can be released once the object is no longer required
+ * by calling virDomainFree.
+ *
+ * The return value from this method is a positive integer identifier
+ * for the callback. To unregister a callback, this callback ID should
+ * be passed to the virConnectDomainQemuEventDeregister method
+ *
+ * Returns a callback identifier on success, -1 on failure
+ */
+int
+virConnectDomainQemuEventRegister(virConnectPtr conn,
+ virDomainPtr dom, /* option to filter */
+ const char *eventName, /* JSON event
name */
+ virConnectDomainQemuEventCallback cb,
+ void *opaque,
+ virFreeCallback freecb)
+{
+ VIR_DOMAIN_DEBUG(dom, "conn=%p, eventName=%s, cb=%p, opaque=%p,
freecb=%p",
+ conn, eventName, cb, opaque, freecb);
+
+ virResetLastError();
+
+ if (!VIR_IS_CONNECT(conn)) {
+ virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ virLibConnError(conn, VIR_ERR_INVALID_CONN, "my_test_fuction");
+ virDispatchError(NULL);
+ return -1;
+ }
+ if (dom != NULL &&
+ !(VIR_IS_CONNECTED_DOMAIN(dom) && dom->conn == conn)) {
+ virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ virDispatchError(conn);
+ return -1;
+ }
+ if (eventName == NULL || cb == NULL) {
+ virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto error;
+ }
+
+ if ((conn->driver) && (conn->driver->qemuDomainQemuEventRegister)) {
+ int ret;
+ ret = conn->driver->qemuDomainQemuEventRegister(conn, dom,
eventName, cb, opaque, freecb);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virLibConnError(conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+error:
+ virDispatchError(conn);
+ return -1;
+}
+
+/**
+ * virConnectDomainQemuEventDeregister:
+ * @conn: pointer to the connection
+ * @callbackID: the callback identifier
+ *
+ * Removes an event callback. The callbackID parameter should be the
+ * vaule obtained from a previous virConnectDomainQemuEventDeregister
method.
+ *
+ * Returns 0 on success, -1 on failure
+ */
+int
+virConnectDomainQemuEventDeregister(virConnectPtr conn,
+ int callbackID)
+{
+
+ VIR_DEBUG("conn=%p, callbackID=%d", conn, callbackID);
+
+ virResetLastError();
+
+ if (!VIR_IS_CONNECT(conn)) {
+ virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ virDispatchError(NULL);
+ return -1;
+ }
+ if (callbackID < 0) {
+ virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto error;
+ }
+ if ((conn->driver) && (conn->driver->qemuDomainQemuEventDeregister)) {
+ int ret;
+ ret = conn->driver->qemuDomainQemuEventDeregister(conn,
callbackID);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virLibConnError(conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+error:
+ virDispatchError(conn);
+ return -1;
+}
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index a81c230..b92ce71 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -470,11 +470,16 @@ virDomainWatchdogModelTypeToString;
# domain_event.h
virDomainEventBlockJobNewFromObj;
virDomainEventBlockJobNewFromDom;
+virDomainEventUnknownNewFromObj;
+virDomainEventunknownNewFromDom;
virDomainEventCallbackListAdd;
virDomainEventCallbackListAddID;
+virDomainEventCallbackListAddName;
virDomainEventCallbackListCount;
virDomainEventCallbackListCountID;
+virDomainEventCallbackListCountName;
virDomainEventCallbackListEventID;
+virDomainEventCallbackListEventName;
virDomainEventCallbackListFree;
virDomainEventCallbackListMarkDelete;
virDomainEventCallbackListMarkDeleteID;
@@ -511,6 +516,7 @@ virDomainEventRebootNewFromDom;
virDomainEventRebootNewFromObj;
virDomainEventStateDeregister;
virDomainEventStateDeregisterAny;
+virDomainQemuEventStateDeregister;
virDomainEventStateFlush;
virDomainEventStateFree;
virDomainEventStateNew;
diff --git a/src/libvirt_qemu.syms b/src/libvirt_qemu.syms
index 8447730..a17e387 100644
--- a/src/libvirt_qemu.syms
+++ b/src/libvirt_qemu.syms
@@ -19,3 +19,8 @@ LIBVIRT_QEMU_0.9.4 {
global:
virDomainQemuAttach;
} LIBVIRT_QEMU_0.8.3;
+LIBVIRT_QEMU_0.9.9 {
+ global:
+ virConnectDomainQemuEventRegister;
+ virConnectDomainQemuEventDeregister;
+} LIBVIRT_QEMU_0.9.4;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index ceb9f47..31fe966 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -8217,6 +8217,46 @@ qemuDomainEventDeregisterAny(virConnectPtr conn,
}
+static int
+qemuDomainQemuEventRegister(virConnectPtr conn,
+ virDomainPtr dom,
+ const char *eventName,
+ virConnectDomainEventGenericCallback callback,
+ void *opaque,
+ virFreeCallback freecb)
+{
+ struct qemud_driver *driver = conn->privateData;
+ int ret;
+
+ qemuDriverLock(driver);
+ ret = virDomainEventCallbackListAddName(conn,
+
driver->domainEventState->callbacks,
+ dom, eventName,
+
VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN,
+ callback, opaque, freecb);
+ qemuDriverUnlock(driver);
+
+ return ret;
+}
+
+
+static int
+qemuDomainQemuEventDeregister(virConnectPtr conn,
+ int callbackID)
+{
+ struct qemud_driver *driver = conn->privateData;
+ int ret;
+
+ qemuDriverLock(driver);
+ ret = virDomainQemuEventStateDeregister(conn,
+ driver->domainEventState,
+ callbackID);
+ qemuDriverUnlock(driver);
+
+ return ret;
+}
+
+
/*******************************************************************
* Migration Protocol Version 2
*******************************************************************/
@@ -11564,6 +11604,8 @@ static virDriver qemuDriver = {
.domainMigrateGetMaxSpeed = qemuDomainMigrateGetMaxSpeed, /* 0.9.5 */
.domainEventRegisterAny = qemuDomainEventRegisterAny, /* 0.8.0 */
.domainEventDeregisterAny = qemuDomainEventDeregisterAny, /* 0.8.0 */
+ .qemuDomainQemuEventRegister = qemuDomainQemuEventRegister, /* 0.9.9 */
+ .qemuDomainQemuEventDeregister = qemuDomainQemuEventDeregister, /*
0.9.9 */
.domainManagedSave = qemuDomainManagedSave, /* 0.8.0 */
.domainHasManagedSaveImage = qemuDomainHasManagedSaveImage, /* 0.8.0 */
.domainManagedSaveRemove = qemuDomainManagedSaveRemove, /* 0.8.0 */
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 4141fb7..e6cd39c 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -959,6 +959,16 @@ int qemuMonitorEmitBlockJob(qemuMonitorPtr mon,
return ret;
}
+int qemuMonitorEmitUnknownEvent(qemuMonitorPtr mon,
+ const char *eventName,
+ const char *eventArgs)
+{
+ int ret = -1;
+ VIR_DEBUG("mon=%p", mon);
+ QEMU_MONITOR_CALLBACK(mon, ret, domainUnknownEvent, mon->vm,
+ eventName, eventArgs);
+ return ret;
+}
int qemuMonitorSetCapabilities(qemuMonitorPtr mon)
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 15acf8b..d3685b4 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -123,6 +123,10 @@ struct _qemuMonitorCallbacks {
const char *diskAlias,
int type,
int status);
+ int (*domainUnknownEvent)(qemuMonitorPtr mon,
+ virDomainObjPtr vm,
+ const char *eventName,
+ const char *eventArgs);
};
@@ -193,6 +197,10 @@ int qemuMonitorEmitBlockJob(qemuMonitorPtr mon,
int type,
int status);
+int qemuMonitorEmitUnknownEvent(qemuMonitorPtr mon,
+ const char *eventName,
+ const char *eventArgs);
+
int qemuMonitorStartCPUs(qemuMonitorPtr mon,
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 1ef3e84..a5fc1e6 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -58,6 +58,7 @@ static void
qemuMonitorJSONHandleVNCConnect(qemuMonitorPtr mon, virJSONValuePtr
static void qemuMonitorJSONHandleVNCInitialize(qemuMonitorPtr mon,
virJSONValuePtr data);
static void qemuMonitorJSONHandleVNCDisconnect(qemuMonitorPtr mon,
virJSONValuePtr data);
static void qemuMonitorJSONHandleBlockJob(qemuMonitorPtr mon,
virJSONValuePtr data);
+static void qemuMonitorJSONHandleUnmatchedEvent(qemuMonitorPtr mon,
virJSONValuePtr obj);
struct {
const char *type;
@@ -74,6 +75,7 @@ struct {
{ "VNC_INITIALIZED", qemuMonitorJSONHandleVNCInitialize, },
{ "VNC_DISCONNECTED", qemuMonitorJSONHandleVNCDisconnect, },
{ "BLOCK_JOB_COMPLETED", qemuMonitorJSONHandleBlockJob, },
+ { "DEFAULT_UNKNOW_EVENT", qemuMonitorJSONHandleUnmatchedEvent, },
};
@@ -83,6 +85,7 @@ qemuMonitorJSONIOProcessEvent(qemuMonitorPtr mon,
{
const char *type;
int i;
+ int findEventFlag = -1;
VIR_DEBUG("mon=%p obj=%p", mon, obj);
type = virJSONValueObjectGetString(obj, "event");
@@ -98,9 +101,24 @@ qemuMonitorJSONIOProcessEvent(qemuMonitorPtr mon,
VIR_DEBUG("handle %s handler=%p data=%p", type,
eventHandlers[i].handler, data);
(eventHandlers[i].handler)(mon, data);
+ findEventFlag = 0;
break;
}
}
+ if (findEventFlag != 0) {
+ if
(!STREQ(eventHandlers[ARRAY_CARDINALITY(eventHandlers)-1].type,
"DEFAULT_UNKNOW_EVENT")) {
+ VIR_ERROR("the last element is not the default event handler");
+ }
+ else {
+ char *event = NULL;
+ event = virJSONValueToString(obj);
+ if (event != NULL) {
+ VIR_DEBUG("Unknow event,call default event handler
%s",event);
+ free(event);
+ }
+
(eventHandlers[ARRAY_CARDINALITY(eventHandlers)-1].handler)(mon, obj);
+ }
+ }
return 0;
}
@@ -724,6 +742,24 @@ out:
}
+static void
+qemuMonitorJSONHandleUnmatchedEvent(qemuMonitorPtr mon, virJSONValuePtr
obj)
+{
+ const char *eventArgsStr = NULL;
+ const char *type = NULL;
+ virJSONValuePtr data = NULL;
+ type = virJSONValueObjectGetString(obj, "event");
+ data = virJSONValueObjectGet(obj, "data");
+ if (data) {
+ eventArgsStr = virJSONValueToString(data);
+ }
+ if (eventArgsStr == NULL) {
+ VIR_ERROR("no data string from JSONValue");
+ }
+ qemuMonitorEmitUnknownEvent(mon, type, eventArgsStr);
+}
+
+
int
qemuMonitorJSONHumanCommandWithFd(qemuMonitorPtr mon,
const char *cmd_str,
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 9123f4c..55e5464 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -755,6 +755,29 @@ qemuProcessHandleBlockJob(qemuMonitorPtr mon
ATTRIBUTE_UNUSED,
}
static int
+qemuProcessHandleUnknownEvent(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
+ virDomainObjPtr vm,
+ const char *eventName,
+ const char *eventArgs)
+{
+ struct qemud_driver *driver = qemu_driver;
+ virDomainEventPtr event = NULL;
+
+ virDomainObjLock(vm);
+ event = virDomainEventUnknownNewFromObj(vm, eventName, eventArgs);
+
+ virDomainObjUnlock(vm);
+
+ if (event) {
+ qemuDriverLock(driver);
+ qemuDomainEventQueue(driver, event);
+ qemuDriverUnlock(driver);
+ }
+
+ return 0;
+}
+
+static int
qemuProcessHandleGraphics(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
virDomainObjPtr vm,
int phase,
@@ -871,6 +894,7 @@ static qemuMonitorCallbacks monitorCallbacks = {
.domainIOError = qemuProcessHandleIOError,
.domainGraphics = qemuProcessHandleGraphics,
.domainBlockJob = qemuProcessHandleBlockJob,
+ .domainUnknownEvent = qemuProcessHandleUnknownEvent,
};
static int
diff --git a/src/remote/qemu_protocol.x b/src/remote/qemu_protocol.x
index 39f9adf..5f4ed61 100644
--- a/src/remote/qemu_protocol.x
+++ b/src/remote/qemu_protocol.x
@@ -47,6 +47,34 @@ struct qemu_domain_attach_ret {
remote_nonnull_domain dom;
};
+struct qemu_domain_events_register_args {
+ remote_nonnull_string eventName;
+};
+
+struct qemu_domain_events_deregister_args {
+ remote_nonnull_string eventName;
+ int callbackID;
+};
+
+struct qemu_domain_events_register_ret {
+ int callbackID;
+};
+
+struct qemu_domain_events_deregister_ret {
+ int cb_deregistered;
+};
+
+struct qemu_domain_events_unknown_event_args {
+ remote_nonnull_domain dom;
+ remote_nonnull_string eventName;
+ remote_nonnull_string eventArgs;
+};
+
+struct qemu_domain_events_unknown_event_ret {
+ int event_ret;
+};
+
+
/* Define the program number, protocol version and procedure numbers
here. */
const QEMU_PROGRAM = 0x20008087;
const QEMU_PROTOCOL_VERSION = 1;
@@ -61,5 +89,8 @@ enum qemu_procedure {
* are some exceptions to this rule, e.g. domainDestroy. Other APIs MAY
* be marked as high priority. If in doubt, it's safe to choose low. */
QEMU_PROC_MONITOR_COMMAND = 1, /* skipgen skipgen priority:low */
- QEMU_PROC_DOMAIN_ATTACH = 2 /* autogen autogen priority:low */
+ QEMU_PROC_DOMAIN_ATTACH = 2, /* autogen autogen priority:low */
+ QEMU_PROC_DOMAIN_EVENTS_REGISTER = 3, /* skipgen skipgen
priority:low */
+ QEMU_PROC_DOMAIN_EVENTS_DEREGISTER = 4, /* skipgen skipgen
priority:low */
+ QEMU_PROC_DOMAIN_EVENTS_UNKNOWN_EVENT = 5 /* skipgen skipgen
priority:low */
};
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index ff2d4b4..1f7b25d 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -238,6 +238,10 @@ static void
remoteDomainBuildEventDiskChange(virNetClientProgramPtr prog,
virNetClientPtr client,
void *evdata, void *opaque);
+static void
+remoteQemuDomainBuildEventDefaultEvent(virNetClientProgramPtr prog,
+ virNetClientPtr client,
+ void *evdata, void *opaque);
static virNetClientProgramEvent remoteDomainEvents[] = {
{ REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE,
@@ -280,6 +284,10 @@ static virNetClientProgramEvent
remoteDomainEvents[] = {
remoteDomainBuildEventDiskChange,
sizeof(remote_domain_event_disk_change_msg),
(xdrproc_t)xdr_remote_domain_event_disk_change_msg },
+ { REMOTE_PROC_QEMU_DOMAIN_EVENT_UNKNOWN_EVENT,
+ remoteQemuDomainBuildEventDefaultEvent,
+ sizeof(remote_domain_event_default_event_msg),
+ (xdrproc_t)xdr_remote_domain_event_default_event_msg },
};
enum virDrvOpenRemoteFlags {
@@ -3345,6 +3353,28 @@
remoteDomainBuildEventBlockJob(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
}
static void
+remoteQemuDomainBuildEventDefaultEvent(virNetClientProgramPtr prog
ATTRIBUTE_UNUSED,
+ virNetClientPtr client
ATTRIBUTE_UNUSED,
+ void *evdata, void *opaque)
+{
+ virConnectPtr conn = opaque;
+ struct private_data *priv = conn->privateData;
+ remote_domain_event_default_event_msg *msg = evdata;
+ virDomainPtr dom;
+ virDomainEventPtr event = NULL;
+
+ dom = get_nonnull_domain(conn, msg->dom);
+ if (!dom)
+ return;
+
+ event = virDomainEventUnknownNewFromDom(dom, msg->eventName,
msg->eventArgs);
+
+ virDomainFree(dom);
+
+ remoteDomainEventQueue(priv, event);
+}
+
+static void
remoteDomainBuildEventGraphics(virNetClientProgramPtr prog
ATTRIBUTE_UNUSED,
virNetClientPtr client ATTRIBUTE_UNUSED,
void *evdata, void *opaque)
@@ -3800,7 +3830,6 @@ done:
return rv;
}
-
static int remoteDomainEventDeregisterAny(virConnectPtr conn,
int callbackID)
{
@@ -3843,6 +3872,126 @@ done:
return rv;
}
+static int
+remoteDomainQemuEventRegister(virConnectPtr conn,
+ virDomainPtr dom,
+ const char *eventName,
+ virConnectDomainEventGenericCallback
callback,
+ void *opaque,
+ virFreeCallback freecb)
+{
+ int rv = -1;
+ struct private_data *priv = conn->privateData;
+ qemu_domain_events_register_args args;
+ qemu_domain_events_register_ret ret;
+ int callbackID;
+
+ remoteDriverLock(priv);
+
+ if (priv->domainEventState->timer < 0) {
+ remoteError(VIR_ERR_NO_SUPPORT, "%s", _("no event support"));
+ goto done;
+ }
+
+ if ((callbackID = virDomainEventCallbackListAddName(conn,
+
priv->domainEventState->callbacks,
+ dom, eventName,
+
VIR_QEMU_DOMAIN_EVENT_ID_UNKNOWN,
+ callback, opaque,
freecb)) < 0) {
+ remoteError(VIR_ERR_RPC, "%s", _("adding cb to list"));
+ goto done;
+ }
+
+ /* If this is the first callback for this eventID, we need to enable
+ * events on the server */
+ if (virDomainEventCallbackListCountName(conn,
+
priv->domainEventState->callbacks,
+ eventName) == 1) {
+ args.eventName= (char *)eventName;
+
+ if (call (conn, priv, REMOTE_CALL_QEMU,
QEMU_PROC_DOMAIN_EVENTS_REGISTER,
+ (xdrproc_t) xdr_qemu_domain_events_register_args,
(char *) &args,
+ (xdrproc_t) xdr_qemu_domain_events_register_ret,
(char *) &ret) == -1) {
+ virDomainEventCallbackListRemoveID(conn,
+
priv->domainEventState->callbacks,
+ callbackID);
+ goto done;
+ }
+ }
+ virDomainEventCallbackListAddQemuCallbackID(conn,
+
priv->domainEventState->callbacks,
+ callbackID,
+ ret.callbackID);
+ rv = callbackID;
+
+done:
+ remoteDriverUnlock(priv);
+ return rv;
+}
+
+static int remoteDomainQemuEventDeregister(virConnectPtr conn,
+ int callbackID)
+{
+ struct private_data *priv = conn->privateData;
+ int rv = -1;
+ qemu_domain_events_deregister_args args;
+ qemu_domain_events_deregister_ret ret;
+ char *eventName = NULL;
+ ret.cb_deregistered = -1;
+
+ remoteDriverLock(priv);
+
+ if ((eventName = (char *)virDomainEventCallbackListEventName(conn,
+
priv->domainEventState->callbacks,
+ callbackID))
== NULL) {
+ remoteError(VIR_ERR_RPC, _("unable to find callback ID %d"),
callbackID);
+ goto done;
+ }
+ eventName = strdup(eventName);
+ if (eventName == NULL)
+ goto done;
+
+ if ((args.callbackID =
virDomainEventCallbackListEventQemuCallbackID(conn,
+
priv->domainEventState->callbacks,
+ callbackID))
== -1) {
+ remoteError(VIR_ERR_RPC, _("unable to find callback ID %d"),
callbackID);
+ goto done;
+ }
+
+ if (virDomainQemuEventStateDeregister(conn,
+ priv->domainEventState,
+ callbackID) < 0)
+ goto done;
+
+ /* If that was the last callback for this eventName, we need to disable
+ * events on the server */
+ if (virDomainEventCallbackListCountName(conn,
+
priv->domainEventState->callbacks,
+ eventName) == 0) {
+ args.eventName = eventName;
+
+ if (call (conn, priv, REMOTE_CALL_QEMU,
QEMU_PROC_DOMAIN_EVENTS_DEREGISTER,
+ (xdrproc_t) xdr_qemu_domain_events_deregister_args,
(char *) &args,
+ (xdrproc_t) xdr_qemu_domain_events_deregister_ret,
(char *) &ret) == -1) {
+ goto done;
+ }
+
+ if ( ret.cb_deregistered == -1 ) {
+ remoteError(VIR_ERR_RPC, _("remote sever deregeiter remote
callbackID:%d, and the client callbackID%d"),
+ args.callbackID,
+ callbackID);
+ goto done;
+ }
+ rv = ret.cb_deregistered;
+ }
+
+
+done:
+ remoteDriverUnlock(priv);
+ if (eventName != NULL)
+ VIR_FREE(eventName);
+ return rv;
+}
/*----------------------------------------------------------------------*/
@@ -4627,6 +4776,8 @@ static virDriver remote_driver = {
.nodeGetFreeMemory = remoteNodeGetFreeMemory, /* 0.3.3 */
.domainEventRegister = remoteDomainEventRegister, /* 0.5.0 */
.domainEventDeregister = remoteDomainEventDeregister, /* 0.5.0 */
+ .qemuDomainQemuEventRegister = remoteDomainQemuEventRegister, /*
0.9.9 */
+ .qemuDomainQemuEventDeregister = remoteDomainQemuEventDeregister,
/* 0.9.9 */
.domainMigratePrepare2 = remoteDomainMigratePrepare2, /* 0.5.0 */
.domainMigrateFinish2 = remoteDomainMigrateFinish2, /* 0.5.0 */
.nodeDeviceDettach = remoteNodeDeviceDettach, /* 0.6.1 */
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index 509a20b..4239db8 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -2049,6 +2049,12 @@ struct remote_domain_event_disk_change_msg {
int reason;
};
+struct remote_domain_event_default_event_msg {
+ remote_nonnull_domain dom;
+ remote_nonnull_string eventName;
+ remote_nonnull_string eventArgs;
+};
+
struct remote_domain_managed_save_args {
remote_nonnull_domain dom;
unsigned int flags;
@@ -2605,7 +2611,8 @@ enum remote_procedure {
REMOTE_PROC_DOMAIN_BLOCK_RESIZE = 251, /* autogen autogen */
REMOTE_PROC_DOMAIN_SET_BLOCK_IO_TUNE = 252, /* autogen autogen */
- REMOTE_PROC_DOMAIN_GET_BLOCK_IO_TUNE = 253 /* skipgen skipgen */
+ REMOTE_PROC_DOMAIN_GET_BLOCK_IO_TUNE = 253, /* skipgen skipgen */
+ REMOTE_PROC_QEMU_DOMAIN_EVENT_UNKNOWN_EVENT = 254 /* skipgen skipgen */
/*
* Notice how the entries are grouped in sets of 10 ?
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
index a9d4296..17b3896 100644
--- a/src/remote_protocol-structs
+++ b/src/remote_protocol-structs
@@ -1546,6 +1546,10 @@ struct remote_domain_event_disk_change_msg {
remote_nonnull_string devAlias;
int reason;
};
+struct remote_domain_event_default_event_msg {
+ remote_nonnull_domain dom;
+ remote_nonnull_string rawEvent;
+};
struct remote_domain_managed_save_args {
remote_nonnull_domain dom;
u_int flags;
@@ -2044,4 +2048,5 @@ enum remote_procedure {
REMOTE_PROC_DOMAIN_BLOCK_RESIZE = 251,
REMOTE_PROC_DOMAIN_SET_BLOCK_IO_TUNE = 252,
REMOTE_PROC_DOMAIN_GET_BLOCK_IO_TUNE = 253,
+ REMOTE_PROC_QEMU_DOMAIN_EVENT_UNKNOWN_EVENT = 254,
};
--
1.7.5.4
1
0
One month exactly after the previous release, 0.9.8 is available at
ftp://libvirt.org/libvirt/
This release is a balanced mix of new features, improvements and
various bug fixes, and with a higher than usual amount of portability
fixes:
Features:
- Add support for QEMU 1.0 (Jiri Denemark)
- Add PPC cpu driver. (Prerna Saxena)
- Add new API virDomain{Set, Get}BlockIoTune (Lei Li)
- block_resize: Define the new API (Osier Yang)
- Add a public API to invoke suspend/resume on the host (Srivatsa S. Bhat)
- various improvements for LXC containers (Daniel P. Berrange)
- Define keepalive protocol and add virConnectIsAlive API (Jiri Denemark)
- Add support for STP filtering (Stefan Berger)
- Add support for VLAN filtering (Stefan Berger)
Documentation:
- Add documentation for <disk><source type="dir"> (Christophe Fergeau)
- Fix typo in virDomainResume API doc (Christophe Fergeau)
- maint: fix improper use of 'an' (Eric Blake)
- virsh: translate net-info help (Eric Blake)
- maint: typo fixes (Eric Blake)
- virsh: Fix typos in man page (Jiri Denemark)
- rpc: Fix a typo in virNetClientSendNonBlock documentation (Jiri Denemark)
- docs: fix grammar of capabilities (Eric Blake)
- Documentation about chains' priorities, lists of elements etc. (Stefan Berger)
Portability:
- spec: don't use chkconfig --list (Eric Blake)
- build: fix build with older libxml2 (Eric Blake)
- Conditionalize daemonPath decl for Win32 which lacks UNIX sockets (Daniel P. Berrange)
- build: reduce warnings from older gcc (Eric Blake)
- Fix incorrect symbols for virtime.h module breaking Mingw32 (Daniel P. Berrange)
- build: fix build on Cygwin (Eric Blake)
- build: fix build at -O2 on rawhide (Eric Blake)
- Fix build for platforms lacking struct ifreq (Daniel P. Berrange)
- build: fix 'make dist' without dtrace (Eric Blake)
- Don't use undocumented __isleap macro (Daniel P. Berrange)
- virnetsocket: pass XAUTORITY for ssh connection (Christian Franke)
- Fix build on Mingw32 wrt export of virNetServerGetDBusConn (Daniel P. Berrange)
- build: fix compile error with no macvtap (Eric Blake)
- Fix build with polkit0 (Jim Fehlig)
- Fix strchr call triggering gcc 4.3 & 4.4 bug (Stefan Berger)
- PATCH: Fix build without MACVTAP (Michael Wood)
- util: fix compile error on debian (Eli Qiao)
- Disable numactl on ARM architectures too (Daniel P. Berrange)
- Add libvirt confdir to files section in mingw32 spec (Daniel P. Berrange)
- build: fix mingw build of gnulib openpty (Eric Blake)
Bug Fixes:
- Fix updating of haveTheBuck in RPC client to be race-free (Daniel P. Berrange)
- Prevent crash of libvirtd when attaching to existing qemu process (Jim Fehlig)
- qemu: Ignore shutdown event from destroyed domain (Jiri Denemark)
- remote_driver: don't fail if keepalive check fails (Guido Günther)
- command: handle empty buffer argument correctly (Eric Blake)
- client: Check if other thread claims it has the buck before claiming it. (Peter Krempa)
- Avoid crash in shunloadtest (Daniel P. Berrange)
- Fix a logic error for setting block I/O (Lei Li)
- virsh: Allow other escape characters for console (Michal Privoznik)
- bridge_driver: Don't define network if XML contains more IPv4 adreses. (Peter Krempa)
- virsh: Fix possible deadlock when virsh is about to exit (Jiri Denemark)
- util: Plug memory leak on virNetDevMacVLanCreateWithVPortProfile() error path (Alex Jia)
- util: Plug memory leak on virNetDevBridgeGet() sucessful path (Alex Jia)
- uml: Plug memory leak on umlStartVMDaemon() error path (Alex Jia)
- rpc: Plug memory leak on virNetClientSendInternal() error path (Alex Jia)
- conf: Plug memory leak on virDomainDefParseXML() error path (Alex Jia)
- qemu: Plug memory leak onqemuProcessWaitForMonitor() error path (Alex Jia)
- conf: reject duplicate paths in device weights (Eric Blake)
- Make logging async signal safe wrt time stamp generation (Daniel P. Berrange)
- Don't mark suspend as active until we know it is running (Daniel P. Berrange)
- util: avoid null deref on qcowXGetBackingStore (Alex Jia)
- virsh: correct return value error (Alex Jia)
- qemu: fix blkiotune --live --config (Eric Blake)
- lxc: Fix suspend/resume with freezer cgroup (Jiri Denemark)
- rpc: Really send non-blocking calls while waiting for another call (Jiri Denemark)
- util: fix thinko in runIO (Paolo Bonzini)
- storage: Skip socket and fifo on pool-start (Michal Privoznik)
- conf: Don't drop console definition on domain restart (Michal Privoznik)
- qemu: Avoid dereference of NULL pointer (Peter Krempa)
- nwfilter: Initialize virNWFilterAddIpAddrForIfname return variable (Michal Privoznik)
- Fix disabling of virtual port profile code on old hosts (Daniel P. Berrange)
- Fix uninitialized variable in NWfilter IP learning code (Daniel P. Berrange)
- storage: Fallback to use lvchange first if lvremove fails (Chang Liu)
- conf: don't modify cpu set string during parsing (Eric Blake)
- qemu: don't release network actual device twice (Roopa Prabhu)
- tests: avoid xend ABRT crash report (Eric Blake)
- Fix use of uninitialized variable in QEMU driver (Daniel P. Berrange)
- snapshot: refuse to generate names for non-regular backing files (Eric Blake)
- fix a bug in remoteSerializeTypedParameters (Hu Tao)
- Don't return a fatal error if receiving unexpected stream data (Daniel P. Berrange)
- Fix handling of stream EOF (Daniel P. Berrange)
- storage: forbid rebuilding existing disk storage pools (Guido Günther)
- qemu: fix domjobabort regression (Eric Blake)
- fix two bugs in bridge_driver.c (Hu Tao)
- nwfilter: avoid failure with noexec /tmp (Eric Blake)
- lxc: free error object to avoid memory leak (Alex Jia)
- lxc: free 'ttyFDs' array on return from lxcVmStart (Alex Jia)
Improvements:
- npiv: Expose fabric_name outside (Osier Yang)
- Improve error reporting when libvirtd is not installed (Daniel P. Berrange)
- spec: fix sanlock dependency (Eric Blake)
- spec: add dmidecode as prereq (Eric Blake)
- examples: Update event tests for shutdown event (Jiri Denemark)
- qemu: Rework handling of shutdown event (Jiri Denemark)
- python: Expose binding for virNodeGetMemoryStats() (Peter Krempa)
- python: Expose binding for virNodeGetCPUStats() (Peter Krempa)
- build: require more tools from maintainers (Eric Blake)
- apparmor: allow tunnelled migrations. (Serge Hallyn)
- Update of filters to handle multiple IP addresses (Stefan Berger)
- build: update to latest gnulib (Eric Blake)
- build: properly skip tests (Eric Blake)
- spec: mark directories in /var/run as ghosts (Eric Blake)
- qemu: filter blkio 0-device-weight at two other places (Hu Tao)
- qemu: amend existing table of device weights (Eric Blake)
- virsh: fix setting weight and device-weights at the same time (Hu Tao)
- Add tests for blkdeviotune (Lei Li)
- Support virDomain{Set, Get}BlockIoTune in the python API (Lei Li)
- Enable the blkdeviotune command in virsh (Lei Li)
- Implement virDomain{Set, Get}BlockIoTune for the qemu driver (Lei Li)
- Support block I/O throttle in XML (Lei Li)
- Add virDomain{Set, Get}BlockIoTune support to the remote driver (Lei Li)
- Fix leak build config file path (Daniel P. Berrange)
- Add internal APIs for dealing with time (Daniel P. Berrange)
- Remove obsolete virGetPMCapabilities sym from private symbols file (Daniel P. Berrange)
- Add suspend info to Xen, LXC and UML hypervisor capabilities (Daniel P. Berrange)
- Remove pointless strdup in node suspend code (Daniel P. Berrange)
- Do lazy init of host PM features (Daniel P. Berrange)
- Remove powerMgmt_valid field from capabilities struct (Daniel P. Berrange)
- Add export of node suspend capabilities APIs (Daniel P. Berrange)
- Move suspend capabilities APIs out of util.h into virnodesuspend.c (Daniel P. Berrange)
- Rename suspend capabilities APIs (Daniel P. Berrange)
- Sanitize virDiscoverHostPMFeature to return a boolean (Daniel P. Berrange)
- Move the virHostPMCapability enum helpers into capabilities.c (Daniel P. Berrange)
- Fix capabilities XML to use generic terms for suspend targets (Daniel P. Berrange)
- Remove internal only virHostPMCapability enum (Daniel P. Berrange)
- Fix values of PM target type constants (Daniel P. Berrange)
- blkiotune: add qemu support for blkiotune.device_weight (Hu Tao)
- blkiotune: add interface for blkiotune.device_weight (Hu Tao)
- qemu, lxc: drop redundant checks (Eric Blake)
- API: prevent query of --live and --config at once (Eric Blake)
- build: fix typo in last patch (Eric Blake)
- block_resize: Update test file for RPC (Osier Yang)
- block_resize: Expose the new API to virsh (Osier Yang)
- block_resize: Implement qemu driver method (Osier Yang)
- block_resize: Implement qemu monitor functions (Osier Yang)
- block_resize: Wire up the remote protocol (Osier Yang)
- examples: Correct the example command to use testnode.xml (Osier Yang)
- Add virsh command to initiate suspend on the host (Srivatsa S. Bhat)
- Implement the core API to suspend/resume the host (Srivatsa S. Bhat)
- Add the remote protocol implementation for virNodeSuspendForDuration (Srivatsa S. Bhat)
- Add 'Hybrid-Suspend' power management discovery for the host (Srivatsa S. Bhat)
- virsh: Don't traverse childless nodes in vshNodeIsSuperset (Michal Privoznik)
- conf: make virt-xml-validate work with vbox domains (Lorin Hochstein)
- conf: Improve incorrect root element error messages (Michal Privoznik)
- Refactor initial LXC mem tune / device ACL code (Daniel P. Berrange)
- Add support for blkio tuning of LXC containers (Daniel P. Berrange)
- Add support for CPU quota/period to LXC driver (Daniel P. Berrange)
- Support CPU placement in LXC driver (Daniel P. Berrange)
- Support NUMA memory placement for LXC containers (Daniel P. Berrange)
- storage: Refetch file status after open (Michal Privoznik)
- Fix version numbers for isAlive and setKeepAlive driver APIs (Jiri Denemark)
- build: Properly generate and check virkeepaliveprotocol-structs (Jiri Denemark)
- examples: Use virConnectOpenAuth in events-c (Jiri Denemark)
- qemu: Cancel p2p migration when connection breaks (Jiri Denemark)
- qemu: Add support for keepalive messages during p2p migration (Jiri Denemark)
- Add keepalive support into domain-events examples (Jiri Denemark)
- Implement virConnectIsAlive in all drivers (Jiri Denemark)
- Introduce virConnectIsAlive API (Jiri Denemark)
- Implement keepalive protocol in remote driver (Jiri Denemark)
- Add support for async close of client RPC socket (Jiri Denemark)
- Implement keepalive protocol in libvirt daemon (Jiri Denemark)
- virsh: Always run event loop (Jiri Denemark)
- Introduce virConnectSetKeepAlive (Jiri Denemark)
- Implement common keepalive handling (Jiri Denemark)
- rpc: Add some debug messages to virNetClient (Jiri Denemark)
- rpc: Fix handling of non-blocking calls that could not be sent (Jiri Denemark)
- rpc: Pass the buck only to the first available thread (Jiri Denemark)
- nwfilter: remove virConnectPtr from internal API calls (Stefan Berger)
- API: prefer 'disk' over 'block' or 'path' (Eric Blake)
- blockstats: support lookup by path in blockstats (Eric Blake)
- virsh: Increase device-detach intelligence (Michal PrÃvoznÃk)
- Enable detection of multiple IP addresses (Stefan Berger)
- fix error message when using wrong URI alias (Eli Qiao)
- Pass additional parameter into applyDHCPOnly function (Stefan Berger)
- nwfilter: use shell variable to invoke 'ip(6)tables' command (Stefan Berger)
- nwfilter: use shell variable to invoke 'ebtables' command (Stefan Berger)
- Improve error reporting of failures to apply filtering rules (Stefan Berger)
- Add documentation for STP filtering support (Stefan Berger)
- Add test cases for STP traffic filtering (Stefan Berger)
- Add a 'mac' chain (Stefan Berger)
- Add strings.h include to capabilities.h for ffs() function prototype (Daniel P. Berrange)
- build: Update AUTHORS (Osier Yang)
- Export KVM Host Power Management capabilities (Srivatsa S. Bhat)
- qemu: Copy console definition from serial (Michal Privoznik)
- storage: Skips backingStore of virtual snapshot lv (Osier Yang)
- Add documentation for VLAN filtering support (Stefan Berger)
- Add test cases for VLAN traffic filtering (Stefan Berger)
- Don't copy sexpr node value that is an empty string (Jim Fehlig)
- enable cgroup cpuset by default (Hu Tao)
- tests: test recent hash addition (Eric Blake)
- Add test cases for parsing of list values (Stefan Berger)
- Extend NWFilter parameter parser to cope with lists of values (Stefan Berger)
- Create rules for each member of a list (Stefan Berger)
- Rework value part of name-value pairs (Stefan Berger)
- Add test cases (Stefan Berger)
- Interleave jumping into chains with filtering rules in 'root' table (Stefan Berger)
- Extend rule priorities into negative numbers (Stefan Berger)
- Enable chains with names having a known prefix (Stefan Berger)
- Extend the filter XML to support priorities of chains (Stefan Berger)
- Use the actual names of chains in data structure (Stefan Berger)
- Use scripting for cleaning and renaming of chains (Stefan Berger)
- Make filter creation in root table more flexible (Stefan Berger)
- Introduce an internal priority for chains (Stefan Berger)
- Add function to get hash table's key/value pairs (Stefan Berger)
- Add support for systemd init service (Daniel P. Berrange)
- Add support for interfaces with type=direct to LXC (Daniel P. Berrange)
- Allow creation of plain macvlan devices (Daniel P. Berrange)
- Refactor LXC network setup to allow future enhancements (Daniel P. Berrange)
- Add missing 'const' annotations for internal domain conf helpers (Daniel P. Berrange)
- qemu: Generate -numa option (Bharata B Rao)
- XML definitions for guest NUMA and parsing routines (Bharata B Rao)
- virsh: add iface-bridge and iface-unbridge commands (Laine Stump)
- Allow non-blocking message sending on virNetClient (Daniel P. Berrange)
- Refactor code for enabling/disabling I/O callback in remote client (Daniel P. Berrange)
- Split virNetClientSend into 2 methods (Daniel P. Berrange)
- Refactor code for passing the buck in the remote client (Daniel P. Berrange)
- Explicitly track whether the buck is held in remote client (Daniel P. Berrange)
- Remove all linked list handling from remote client event loop (Daniel P. Berrange)
- util: Add netdev helper functions to private symbols (Eli Qiao)
- qemu/rbd: improve rbd device specification (Sage Weil)
- maint: fix build (Stefan Berger)
- Fix error reporting in port profile parsing/formatting APIs (Daniel P. Berrange)
- API: add trivial qemu support for VIR_TYPED_PARAM_STRING (Eric Blake)
- API: remote support for VIR_TYPED_PARAM_STRING (Eric Blake)
- API: add VIR_TYPED_PARAM_STRING (Eric Blake)
- maint: use mailmap, not AUTHORS, for secondary addresses (Eric Blake)
- maint: fix make syntax-check (Stefan Berger)
- nwfilter: simplify execution of ebiptables scripts (Eric Blake)
- Remove usage of brctl command line tool (Daniel P. Berrange)
- Add an API for retrieving the MAC address of an interface (Daniel P. Berrange)
- Expose MTU management APIs (Daniel P. Berrange)
- Turn two int parameters into bools in bridge APIs (Daniel P. Berrange)
- Make all brXXX APIs raise errors, instead of returning errnos (Daniel P. Berrange)
- build: allow for local gnulib diffs (Eric Blake)
- qemu: Fix improper error message for disk detaching (Osier Yang)
- virsh: Add VSH_OFLAG_EMPTY_OK for attach-disk command (Xu He Jie)
Cleanups:
- Remove time APIs from src/util/util.h (Daniel P. Berrange)
- bandwidth: Fix funky identation (Michal Privoznik)
- qemu: fix a const-correctness issue (Eric Blake)
- build: fix accidental POTFILES.in regression (Eric Blake)
- Fix up ordering of private symbols file (Daniel P. Berrange)
- Move ifaceMacvtapLinkDump and ifaceGetNthParent functions (Daniel P. Berrange)
- Move functions for dealing with physical/virtual devices (Daniel P. Berrange)
- Rename APIs for dealing with virtual/physical functions (Daniel P. Berrange)
- Move virNetDevValidateConfig to virnetdev.c (Daniel P. Berrange)
- Rename ifaceCheck to virNetDevValidateConfig (Daniel P. Berrange)
- Move virNetDevGetIPv4Address to virnetdev.c (Daniel P. Berrange)
- Rename ifaceGetIPAddress to virNetDevGetIPv4Address (Daniel P. Berrange)
- Move virNetDevGetIndex & virNetDevGetVLanID to virnetdev.c (Daniel P. Berrange)
- Rename ifaceGetIndex and ifaceGetVLAN (Daniel P. Berrange)
- Move MAC address replacement functions to virnetdev.c (Daniel P. Berrange)
- Rename interface MAC address replacement APIs (Daniel P. Berrange)
- Move the low level macvlan creation APIs (Daniel P. Berrange)
- Rename low level macvlan creation APIs (Daniel P. Berrange)
- Rename high level macvlan creation APIs (Daniel P. Berrange)
- Rename and split the macvtap.c file (Daniel P. Berrange)
- Rename Macvtap management APIs (Daniel P. Berrange)
- Remove ifaceSetMac and ifaceGetMac APIs (Daniel P. Berrange)
- Remove ifaceUp, ifaceDown, ifaceCtrl & ifaceIsUp APIs (Daniel P. Berrange)
- Move LXC veth.c code into shared utility APIs (Daniel P. Berrange)
- Rename the LXC veth management APIs and delete duplicated APIs (Daniel P. Berrange)
- Split src/util/network.{c,h} into 5 pieces (Daniel P. Berrange)
- Rename virVirtualPortProfileParams & APIs (Daniel P. Berrange)
- build: drop useless dirent.h includes (Eric Blake)
- xenapi: remove unused variable (Eric Blake)
- Remove code instantiating filters on direct interfaces (Stefan Berger)
- Adjust naming of network device bandwidth management APIs (Daniel P. Berrange)
- Santize naming of socket address APIs (Daniel P. Berrange)
- Split bridge.h into three separate files (Daniel P. Berrange)
- Rename all brXXXX APIs to follow new convention (Daniel P. Berrange)
- Remove 'brControl' object (Daniel P. Berrange)
Thanks again to everybody who contributed to this release, with
patches, ideas, documentation or reporting issues ! Let's not forget
the translation teams at transifex [1] with special kudos for ukainian
who have 100% complete localization if I believe transifex statistics :-)
Daniel
[1] https://www.transifex.net/projects/p/libvirt/resource/strings/
--
Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/
daniel(a)veillard.com | Rpmfind RPM search engine http://rpmfind.net/
http://veillard.com/ | virtualization library http://libvirt.org/
3
2
Hi,
I am using libvirt 0.9.7
-----Original Message-----
From: Kashyap Chamarthy [mailto:kchamart@redhat.com]
Sent: Monday, December 12, 2011 12:32 PM
To: Amit Tewari
Cc: libvir-list(a)redhat.com
Subject: Re: [libvirt] virsh console giving Error
On 12/12/2011 12:16 PM, Amit Tewari wrote:
> Hi all,
>
> Following is my test environment
>
> Host os= rhel6.1
>
> Guest os=rhel6.1
>
> Hypervisor - kvm
>
>
>
> I have a created a guest machine using virt-install command. And it
has created guest
> successfully.
>
> But now when I issue following command
>
> #virsh console guest
>
>
>
> Following error is displayed -
>
>
>
> "Error: internal error character device (null) is not using a PTY"
>
>
>
> Please let me no how can I avoid this error.
You have not specified what distribution, version of libvirt are you
using.
First, can you ensure if you have serial console set up in your guest by
checking if you
have the below directives in your guest kernel's command line options
(in /etc/grub.conf)
----
console=tty0 console=ttyS0,115200
----
If not, you can add it by running the below (ensure the guest is
shut-off):
# virt-edit guest /etc/grub.conf
'virt-edit' tool comes with libguestfs-tools-c package.
--
/kashyap
>
>
>
> Regards
>
> Amit Tewari
>
>
>
> --
> libvir-list mailing list
> libvir-list(a)redhat.com
> https://www.redhat.com/mailman/listinfo/libvir-list
DISCLAIMER:
-----------------------------------------------------------------------------------------------------------------------
The contents of this e-mail and any attachment(s) are confidential and
intended
for the named recipient(s) only.
It shall not attach any liability on the originator or NECHCL or its
affiliates. Any views or opinions presented in
this email are solely those of the author and may not necessarily reflect the
opinions of NECHCL or its affiliates.
Any form of reproduction, dissemination, copying, disclosure, modification,
distribution and / or publication of
this message without the prior written consent of the author of this e-mail is
strictly prohibited. If you have
received this email in error please delete it and notify the sender
immediately. .
-----------------------------------------------------------------------------------------------------------------------
4
3
Hey all,
I just noticed that make uninstall from the git HEAD fails:
rmdir /etc/sasl2/
rmdir: failed to remove `/etc/sasl2/': Directory not empty
it's correct that /etc/sasl2 should not be removed, as it has other
files in it, so I think this removal should be more targeted, although
I haven't investigated what should be removed when uninstalling.
Dave
4
5
12 Dec '11
When destroying a domain qemuDomainDestroy kills its qemu process and
starts a new job, which means it unlocks the domain object and locks it
again after some time. Although the object is usually unlocked for a
pretty short time, chances are another thread processing an EOF event on
qemu monitor is able to lock the object first and does all the cleanup
by itself. This leads to wrong shutoff reason and lifecycle event detail
and virDomainDestroy API incorrectly reporting failure to destroy an
inactive domain.
Reported by Charlie Smurthwaite.
---
src/qemu/qemu_domain.h | 1 +
src/qemu/qemu_driver.c | 10 ++++++++++
src/qemu/qemu_process.c | 22 +++++++++++++++-------
3 files changed, 26 insertions(+), 7 deletions(-)
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index e8bcab3..35f9440 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -110,6 +110,7 @@ struct _qemuDomainObjPrivate {
bool monError;
unsigned long long monStart;
bool gotShutdown;
+ bool beingDestroyed;
char *pidfile;
int nvcpupids;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 10a289e..ceb9f47 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -1678,6 +1678,7 @@ qemuDomainDestroyFlags(virDomainPtr dom,
virDomainObjPtr vm;
int ret = -1;
virDomainEventPtr event = NULL;
+ qemuDomainObjPrivatePtr priv;
virCheckFlags(0, -1);
@@ -1691,6 +1692,8 @@ qemuDomainDestroyFlags(virDomainPtr dom,
goto cleanup;
}
+ priv = vm->privateData;
+
qemuDomainSetFakeReboot(driver, vm, false);
/* Although qemuProcessStop does this already, there may
@@ -1700,9 +1703,16 @@ qemuDomainDestroyFlags(virDomainPtr dom,
*/
qemuProcessKill(vm, false);
+ /* We need to prevent monitor EOF callback from doing our work (and sending
+ * misleading events) while the vm is unlocked inside BeginJob API
+ */
+ priv->beingDestroyed = true;
+
if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_DESTROY) < 0)
goto cleanup;
+ priv->beingDestroyed = false;
+
if (!virDomainObjIsActive(vm)) {
qemuReportError(VIR_ERR_OPERATION_INVALID,
"%s", _("domain is not running"));
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index d4271d0..9123f4c 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -128,14 +128,18 @@ qemuProcessHandleMonitorEOF(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
qemuDriverLock(driver);
virDomainObjLock(vm);
+ priv = vm->privateData;
+
+ if (priv->beingDestroyed) {
+ VIR_DEBUG("Domain is being destroyed, EOF is expected");
+ goto unlock;
+ }
+
if (!virDomainObjIsActive(vm)) {
VIR_DEBUG("Domain %p is not active, ignoring EOF", vm);
- virDomainObjUnlock(vm);
- qemuDriverUnlock(driver);
- return;
+ goto unlock;
}
- priv = vm->privateData;
if (priv->monJSON && !priv->gotShutdown) {
VIR_DEBUG("Monitor connection to '%s' closed without SHUTDOWN event; "
"assuming the domain crashed", vm->def->name);
@@ -150,11 +154,15 @@ qemuProcessHandleMonitorEOF(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
qemuProcessStop(driver, vm, 0, stopReason);
virDomainAuditStop(vm, auditReason);
- if (!vm->persistent)
+ if (!vm->persistent) {
qemuDomainRemoveInactive(driver, vm);
- else
- virDomainObjUnlock(vm);
+ goto cleanup;
+ }
+unlock:
+ virDomainObjUnlock(vm);
+
+cleanup:
if (event)
qemuDomainEventQueue(driver, event);
qemuDriverUnlock(driver);
--
1.7.8
2
2
[libvirt] [libvirt-glib 1/2] Fix gvir_config_domain_disk_set_target_bus API
by Christophe Fergeau 12 Dec '11
by Christophe Fergeau 12 Dec '11
12 Dec '11
The bus type is actually an enum, let's reflect that in
libvirt-gconfig API
---
libvirt-gconfig/libvirt-gconfig-domain-disk.c | 8 ++++++--
libvirt-gconfig/libvirt-gconfig-domain-disk.h | 13 ++++++++++++-
libvirt-gconfig/libvirt-gconfig.sym | 1 +
libvirt-gconfig/tests/test-domain-create.c | 2 +-
4 files changed, 20 insertions(+), 4 deletions(-)
diff --git a/libvirt-gconfig/libvirt-gconfig-domain-disk.c b/libvirt-gconfig/libvirt-gconfig-domain-disk.c
index 502cf43..b52f4a5 100644
--- a/libvirt-gconfig/libvirt-gconfig-domain-disk.c
+++ b/libvirt-gconfig/libvirt-gconfig-domain-disk.c
@@ -159,14 +159,18 @@ void gvir_config_domain_disk_set_driver_type(GVirConfigDomainDisk *disk,
}
void gvir_config_domain_disk_set_target_bus(GVirConfigDomainDisk *disk,
- const char *bus)
+ GVirConfigDomainDiskBus bus)
{
GVirConfigObject *node;
g_return_if_fail(GVIR_IS_CONFIG_DOMAIN_DISK(disk));
node = gvir_config_object_add_child(GVIR_CONFIG_OBJECT(disk), "target");
g_return_if_fail(GVIR_IS_CONFIG_OBJECT(node));
- gvir_config_object_set_attribute(node, "bus", bus, NULL);
+ gvir_config_object_set_attribute_with_type(node,
+ "bus",
+ GVIR_TYPE_CONFIG_DOMAIN_DISK_BUS,
+ bus,
+ NULL);
g_object_unref(G_OBJECT(node));
}
diff --git a/libvirt-gconfig/libvirt-gconfig-domain-disk.h b/libvirt-gconfig/libvirt-gconfig-domain-disk.h
index b90b2bc..bc63dfe 100644
--- a/libvirt-gconfig/libvirt-gconfig-domain-disk.h
+++ b/libvirt-gconfig/libvirt-gconfig-domain-disk.h
@@ -64,6 +64,17 @@ typedef enum {
} GVirConfigDomainDiskType;
typedef enum {
+ GVIR_CONFIG_DOMAIN_DISK_BUS_IDE,
+ GVIR_CONFIG_DOMAIN_DISK_BUS_FDC,
+ GVIR_CONFIG_DOMAIN_DISK_BUS_SCSI,
+ GVIR_CONFIG_DOMAIN_DISK_BUS_VIRTIO,
+ GVIR_CONFIG_DOMAIN_DISK_BUS_XEN,
+ GVIR_CONFIG_DOMAIN_DISK_BUS_USB,
+ GVIR_CONFIG_DOMAIN_DISK_BUS_UML,
+ GVIR_CONFIG_DOMAIN_DISK_BUS_SATA
+} GVirConfigDomainDiskBus;
+
+typedef enum {
GVIR_CONFIG_DOMAIN_DISK_GUEST_DEVICE_DISK,
GVIR_CONFIG_DOMAIN_DISK_GUEST_DEVICE_FLOPPY,
GVIR_CONFIG_DOMAIN_DISK_GUEST_DEVICE_CDROM
@@ -94,7 +105,7 @@ void gvir_config_domain_disk_set_driver_name(GVirConfigDomainDisk *disk,
void gvir_config_domain_disk_set_driver_type(GVirConfigDomainDisk *disk,
const char *driver_type);
void gvir_config_domain_disk_set_target_bus(GVirConfigDomainDisk *disk,
- const char *bus);
+ GVirConfigDomainDiskBus bus);
void gvir_config_domain_disk_set_target_dev(GVirConfigDomainDisk *disk,
const char *dev);
G_END_DECLS
diff --git a/libvirt-gconfig/libvirt-gconfig.sym b/libvirt-gconfig/libvirt-gconfig.sym
index 6adc2c2..d0c35d2 100644
--- a/libvirt-gconfig/libvirt-gconfig.sym
+++ b/libvirt-gconfig/libvirt-gconfig.sym
@@ -54,6 +54,7 @@ LIBVIRT_GCONFIG_0.0.1 {
gvir_config_domain_device_get_type;
gvir_config_domain_disk_get_type;
+ gvir_config_domain_disk_bus_get_type;
gvir_config_domain_disk_guest_device_type_get_type;
gvir_config_domain_disk_snapshot_type_get_type;
gvir_config_domain_disk_type_get_type;
diff --git a/libvirt-gconfig/tests/test-domain-create.c b/libvirt-gconfig/tests/test-domain-create.c
index 42aa09b..ea3a3ea 100644
--- a/libvirt-gconfig/tests/test-domain-create.c
+++ b/libvirt-gconfig/tests/test-domain-create.c
@@ -100,7 +100,7 @@ int main(void)
gvir_config_domain_disk_set_source(disk, "/tmp/foo/bar");
gvir_config_domain_disk_set_driver_name(disk, "qemu");
gvir_config_domain_disk_set_driver_type(disk, "qcow2");
- gvir_config_domain_disk_set_target_bus(disk, "ide");
+ gvir_config_domain_disk_set_target_bus(disk, GVIR_CONFIG_DOMAIN_DISK_BUS_IDE);
gvir_config_domain_disk_set_target_dev(disk, "hda");
devices = g_list_append(devices, GVIR_CONFIG_DOMAIN_DEVICE(disk));
--
1.7.7.3
2
3
Hi,
This patch series add setters for the GVirConfigDomainInterface properties which
are common to all classes deriving from GVirConfigDomainInterface. It also adds
GVirConfigDomainInterfaceUser so that it's possible to create <interface
type="user"> nodes.
Christophe
2
3
In terms of documentation to virDomainScreenshot, caller MUST free
returned value. But virsh was not.
---
Pushing under trivial rule.
tools/virsh.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index d859b3a..d58b827 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -3097,6 +3097,7 @@ cleanup:
if (st)
virStreamFree(st);
VIR_FORCE_CLOSE(fd);
+ VIR_FREE(mime);
return ret;
}
--
1.7.3.4
1
0
[libvirt] [PATCH] storage: Activate/deactivate logical volumes only on local node
by Osier Yang 12 Dec '11
by Osier Yang 12 Dec '11
12 Dec '11
From: Rommer <rommer(a)active.by>
Current "-ay | -an" has problems on pool starting/refreshing if
the volumes are clustered. Rommer has posted a patch to list 2
months ago.
https://www.redhat.com/archives/libvir-list/2011-October/msg01116.html
But IMO we shouldn't skip the inactived vols. So this is a squashed
patch by Rommer.
Signed-off-by: Rommer <rommer(a)active.by>
---
src/storage/storage_backend_logical.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/src/storage/storage_backend_logical.c b/src/storage/storage_backend_logical.c
index 1420ede..6a235f6 100644
--- a/src/storage/storage_backend_logical.c
+++ b/src/storage/storage_backend_logical.c
@@ -51,7 +51,7 @@ virStorageBackendLogicalSetActive(virStoragePoolObjPtr pool,
const char *cmdargv[4];
cmdargv[0] = VGCHANGE;
- cmdargv[1] = on ? "-ay" : "-an";
+ cmdargv[1] = on ? "-aly" : "-aln";
cmdargv[2] = pool->def->source.name;
cmdargv[3] = NULL;
--
1.7.1
2
3