[libvirt] [PATCH V1] qemu-attach: Calculate index value if not already specified
by Supriya Kannery
virsh qemu-attach fails if user has not specified values
for index/unit/bus for a drive in qemu commandline. Set default
values instead of returning error.
Signed-off-by: Supriya Kannery <supriyak(a)linux.vnet.ibm.com>
---
src/qemu/qemu_command.c | 10 ----------
1 files changed, 0 insertions(+), 10 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 09f412e..8ba67a1 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -7130,16 +7130,6 @@ qemuParseCommandLineDisk(virCapsPtr caps,
def->bus == VIR_DOMAIN_DISK_BUS_VIRTIO)
idx = nvirtiodisk;
- if (idx == -1 &&
- unitid == -1 &&
- busid == -1) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("missing index/unit/bus parameter in drive '%s'"), val);
- virDomainDiskDefFree(def);
- def = NULL;
- goto cleanup;
- }
-
if (idx == -1) {
if (unitid == -1)
unitid = 0;
12 years, 7 months
[libvirt] [PATCH] maint: drop spurious semicolons
by Eric Blake
Detected with:
git grep ';;$' -- '**/*.[ch]'
* src/network/bridge_driver.c (networkRadvdConfContents): Fix
harmless typo.
* src/phyp/phyp_driver.c (phypUUIDTable_Pull): Likewise.
* src/qemu/qemu_monitor_json.c (qemuMonitorJSONDriveDel):
Likewise.
---
Pushing under the trivial rule.
src/network/bridge_driver.c | 2 +-
src/phyp/phyp_driver.c | 2 +-
src/qemu/qemu_monitor_json.c | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 0c4b0b0..5578373 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -981,7 +981,7 @@ networkRestartDhcpDaemon(virNetworkObjPtr network)
static int
networkRadvdConfContents(virNetworkObjPtr network, char **configstr)
{
- virBuffer configbuf = VIR_BUFFER_INITIALIZER;;
+ virBuffer configbuf = VIR_BUFFER_INITIALIZER;
int ret = -1, ii;
virNetworkIpDefPtr ipdef;
bool v6present = false;
diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c
index a1724ca..a3885a7 100644
--- a/src/phyp/phyp_driver.c
+++ b/src/phyp/phyp_driver.c
@@ -736,7 +736,7 @@ phypUUIDTable_Pull(virConnectPtr conn)
if (!channel) {
if (libssh2_session_last_errno(session) !=
LIBSSH2_ERROR_EAGAIN) {
- goto err;;
+ goto err;
} else {
waitsocket(sock, session);
}
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index c35948e..2daf8ea 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -3068,7 +3068,7 @@ int qemuMonitorJSONDriveDel(qemuMonitorPtr mon,
_("deleting disk is not supported. "
"This may leak data if disk is reassigned"));
ret = 1;
- virResetLastError();;
+ virResetLastError();
}
}
} else if (qemuMonitorJSONHasError(reply, "DeviceNotFound")) {
--
1.7.11.7
12 years, 7 months
[libvirt] [PATCH 3/3] Take the forwarding family into account
by Benjamin Cama
Only add iptables rules for this family, and also only check for
forwarding for this family.
---
src/network/bridge_driver.c | 27 +++++++++++++++++++++------
1 files changed, 21 insertions(+), 6 deletions(-)
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index e3e8dc2..6bd4217 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -1788,7 +1788,9 @@ networkAddIptablesRules(struct network_driver *driver,
return -1;
for (ii = 0;
- (ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, ii));
+ (ipdef = virNetworkDefGetIpByIndex(network->def,
+ network->def->forwardFamily,
+ ii));
ii++) {
/* Add address-specific iptables rules */
if (networkAddIpSpecificIptablesRules(driver, network, ipdef) < 0) {
@@ -1803,7 +1805,9 @@ err:
* added for previous IP addresses.
*/
while ((--ii >= 0) &&
- (ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, ii))) {
+ (ipdef = virNetworkDefGetIpByIndex(network->def,
+ network->def->forwardFamily,
+ ii))) {
networkRemoveIpSpecificIptablesRules(driver, network, ipdef);
}
networkRemoveGeneralIptablesRules(driver, network);
@@ -1819,7 +1823,9 @@ networkRemoveIptablesRules(struct network_driver *driver,
virNetworkIpDefPtr ipdef;
for (ii = 0;
- (ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, ii));
+ (ipdef = virNetworkDefGetIpByIndex(network->def,
+ network->def->forwardFamily,
+ ii));
ii++) {
networkRemoveIpSpecificIptablesRules(driver, network, ipdef);
}
@@ -2173,9 +2179,18 @@ networkStartNetworkVirtual(struct network_driver *driver,
goto err2;
/* If forwardType != NONE, check for IP forwarding */
- if (network->def->forwardType != VIR_NETWORK_FORWARD_NONE &&
- networkCheckIpForwarding(v4present, v6present) < 0) {
- goto err3;
+ if (network->def->forwardType != VIR_NETWORK_FORWARD_NONE) {
+ if (network->def->forwardFamily) {
+ /* if forwardFamily is set, we have at least a corresponding
+ * family's address
+ */
+ if (networkCheckIpForwarding(network->def->forwardFamily == AF_INET,
+ network->def->forwardFamily == AF_INET6) < 0)
+ goto err3;
+ } else {
+ if (networkCheckIpForwarding(v4present, v6present) < 0)
+ goto err3;
+ }
}
--
1.7.2.5
12 years, 7 months
[libvirt] [PATCH 0/8] RFC New API to retrieve host node CPU map
by Viktor Mihajlovski
Rationale:
In order to use the APIs listed below it is necessary for a client
to know the maximum number of node CPUs which is passed via the
maplen argument.
virDomainGetEmulatorPinInfo
virDomainGetVcpuPinInfo
virDomainGetVcpus
virDomainPinEmulator
virDomainPinVcpu
virDomainPinVcpuFlags
The current approach uses virNodeGetInfo to determine the maximum CPU number.
This can lead to incorrect results if not all node CPUs are online.
The maximum CPU number should always be the number of CPUs present on the
host, regardless of their online/offline state.
The following example illustrates the issue:
Host has 3 logical CPUs, 1 socket, 3 cores, 1 thread.
Guest has 1 virtual CPU and is started while all 3 host CPUs are
online.
$ virsh vcpuinfo guest
VCPU: 0
CPU: 0
State: running
CPU time: 35.4s
CPU Affinity: yyy
$ echo 0 > /sys/devices/system/cpu/cpu1/online
$ virsh vcpuinfo guest
VCPU: 0
CPU: 0
State: running
CPU time: 35.5s
CPU Affinity: y-
The correct display for CPU affinity would have been y-y, as the guest
continues to use CPUs 0 and 2.
This is not a display problem only, because it is also not possible to
explicitly pin the virtual CPU to host CPUs 0 and 2, due to the
truncated CPU mask.
PROPOSAL:
To help solve the issue above I suggest a new public API:
int virNodeGetCPUMapFlags(virConnectPtr conn,
unsigned char **cpumap,
unsigned int *online,
unsigned int flags);
The function will return the number of CPUs present on the host
or -1 on failure;
If cpumap is non-NULL virNodeGetCPUMapFlags will allocate an array
containing a bit map representation of the online CPUs. It's
the callers responsibility to deallocate cpumap using free().
If online is non-NULL, the variable pointed to will contain
the number of online host node CPUs.
The variable flags has been added to support future extensions
and must be set to 0.
Clients can use virNodeGetCPUMapFlags to properly determine the maximum
number of node CPUs and their online/offline state.
Remarks:
This series implements the QEMU and test drivers.
This series doesn't introduce changes to the existing vcpu pinning,
which I would submit as a succeeding patch set.
No python binding yet.
Viktor Mihajlovski (8):
virNodeGetCPUMapFlags: Define public API.
virNodeGetCPUMapFlags: Define driver API.
virNodeGetCPUMapFlags: Implement public API.
virNodeGetCPUMapFlags: Implement wire protocol.
libvirt.h.in: Add new cpumap macro VIR_CPU_USED
virNodeGetCPUMapFlags: Implement virsh support.
virNodeGetCPUMapFlags: Implement support function in nodeinfo
virNodeGetCPUMapFlags: Implement driver support
daemon/remote.c | 44 +++++++++++++++++++++++++++++++++
include/libvirt/libvirt.h.in | 28 ++++++++++++++++++---
python/generator.py | 1 +
src/driver.h | 7 +++++
src/libvirt.c | 56 ++++++++++++++++++++++++++++++++++++++++++
src/libvirt_private.syms | 1 +
src/libvirt_public.syms | 5 +++
src/nodeinfo.c | 49 ++++++++++++++++++++++++++++++++++++
src/nodeinfo.h | 6 ++++
src/qemu/qemu_driver.c | 1 +
src/remote/remote_driver.c | 49 ++++++++++++++++++++++++++++++++++++
src/remote/remote_protocol.x | 13 +++++++++-
src/remote_protocol-structs | 12 +++++++++
src/test/test_driver.c | 30 ++++++++++++++++++++++
tools/virsh-host.c | 41 ++++++++++++++++++++++++++++++
tools/virsh.pod | 5 +++
16 files changed, 343 insertions(+), 5 deletions(-)
12 years, 7 months
[libvirt] [PATCH] RFC: Clarify the relationship between <vcpu>, <vcpupin>, and <emulatorpin>
by Osier Yang
These 3 elements conflicts with each other in either the doc
or the underlying codes are. This is to propse a solution.
Before writing any codes, I want to see if the principle is
correct, any advise is welcomed.
Current problems:
Problem 1:
The doc shouldn't simply say "These settings are superseded
by CPU tuning. " for element <vcpu>. As except the tuning, <vcpu>
allows to specify the current, maxmum vcpu number. Apart from that,
<vcpu> also allows to specify the placement as "auto", which binds
the domain process to the advisory nodeset from numad.
Problem 2:
Doc for <vcpu> says its "cpuset" specify the physical CPUs
that the vcpus can be pinned. But it's not the truth, as
actually it only pin domain process to the specified physical
CPUs. So either it's a document bug, or code bug.
Problem 3:
Doc for <vcpupin> says it supersed "cpuset" of <vcpu>, it's
not quite correct, as each <vcpupin> specify the pinning policy
only for one vcpu. How about the ones which doesn't have
<vcpupin> specified? it says the vcpu will be pinned to all
available physical CPUs, but what's the meaning of attribute
"cpuset" of <vcpu> then?
Problem 4:
Doc for <emulatorpin> says it pin the emulator threads (domain
process in other context, perhaps another follow up patch to
cleanup the inconsistency is needed) to the physical CPUs
specified its attribute "cpuset". Which conflicts with
<vcpu>'s "cpuset". And actually in the underlying codes,
it set the affinity for domain process twice if both
"cpuset" for <vcpu> and <emulatorpin> are specified,
and <emulatorpin>'s pinning will override <vcpu>'s.
Problem 5:
When "placement" of <vcpu> is "auto" (I.e. uses numad to
get the advisory nodeset to which the domain process is
pinned to), it will also be overridden by <emulatorpin>,
This patch is trying to sort out the conflicts or bugs by:
1) Don't say <vcpu> is superseded by <cputune>
2) Keep the semanteme for "cpuset" of <vcpu> (I.e. Still says it
specify the physical CPUs the virtual CPUs). But modifying it
to mention it also set the pinning policy for domain process,
and the CPU placement of domain process specified by "cpuset"
of <vcpu> will be ingored if <emulatorpin> specified, and
similary, the CPU placement of vcpu thread will be ignored
if it has <vcpupin> specified, for vcpu which doesn't have
<vcpupin> specified, it inherits "cpuset" of <vcpu>.
3) Don't say <vcpu> is supersed by <vcpupin>. If neither <vcpupin>
nor "cpuset" of <vcpu> is specified, the vcpu will be pinned
to all available pCPUs.
4) If neither <emulatorpin> nor "cpuset" of <vcpu> is specified,
the domain process (emulator threads in the context) will be
pinned to all available pCPUs.
5) If "placement" of <vcpu> is "auto", <emulatorpin> is not allowed.
6) hotplugged vcpus will also inherit "cpuset" of <vcpu>
Codes changes above document changes will cause:
1) Inherit def->cpumask for each vcpu which doesn't have <vcpupin>
specified, during parsing.
2) ping the vcpu which doesn't have <vcpupin> specified to def->cpumask
either by cgroup for sched_setaffinity(2), which is actually done
by 1).
3) Error out if "placement" == "auto", and <emulatorpin> is specified.
Otherwise, <emulatorpin> is honored, and "cpuset" of <cpuset> is
ignored.
4) Setup cgroup for each hotplugged vcpu, and setup the pinning policy
by either cgroup or sched_setaffinity(2).
5) Remove cgroup and <vcpupin> for each hot unplugged vcpu.
---
docs/formatdomain.html.in | 42 +++++++++++++++++++++++++++---------------
1 files changed, 27 insertions(+), 15 deletions(-)
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index d664e7e..1ae8cf4 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -357,8 +357,18 @@
the maximum supported by the hypervisor. <span class="since">Since
0.4.4</span>, this element can contain an optional
<code>cpuset</code> attribute, which is a comma-separated
- list of physical CPU numbers that virtual CPUs can be pinned
- to. Each element in that list is either a single CPU number,
+ list of physical CPU numbers that domain process and virtual CPUs
+ can be pinned to by default. (NB: The pinning policy of domain
+ process and virtual CPUs can be specified separately by
+ <code>cputune</code>. If attribute <code>emulatorpin</code>
+ of <code>cputune</code> is specified, <code>cpuset</code>
+ specified by <code>vcpu</code> here will be ingored; Similarly,
+ For virtual CPUs which has <code>vcpupin</code> specified,
+ <code>cpuset</code> specified by <code>cpuset</code> here
+ will be ignored; For virtual CPUs which doesn't have
+ <code>vcpupin</code> specified, it will be pinned to the physical
+ CPUs specified by <code>cpuset</code> here).
+ Each element in that list is either a single CPU number,
a range of CPU numbers, or a caret followed by a CPU number to
be excluded from a previous range. <span class="since">Since
0.8.5</span>, the optional attribute <code>current</code> can
@@ -374,8 +384,7 @@
if it's specified. If both <code>cpuset</code> and <code>placement</code>
are not specified, or if <code>placement</code> is "static", but no
<code>cpuset</code> is specified, the domain process will be pinned to
- all the available physical CPUs. These settings are superseded
- by <a href="#elementsCPUTuning">CPU tuning</a>.
+ all the available physical CPUs.
</dd>
</dl>
@@ -411,23 +420,26 @@
<dt><code>vcpupin</code></dt>
<dd>
The optional <code>vcpupin</code> element specifies which of host's
- physical CPUs the domain VCPU will be pinned to. This setting supersedes
- previous VCPU placement specified in <a href="#elementsCPUAllocation">CPU
- Allocation</a> using <code>vcpu</code> element. If this is omitted,
- each VCPU is pinned to all the physical CPUs by default. It contains two
- required attributes, the attribute <code>vcpu</code> specifies vcpu id,
- and the attribute <code>cpuset</code> is same as
- attribute <code>cpuset</code>
- of element <code>vcpu</code>. (NB: Only qemu driver support)
+ physical CPUs the domain VCPU will be pinned to. If this is omitted,
+ and attribute <code>cpuset</code> of element <code>vcpu</code> is
+ not specified, the vCPU is pinned to all the physical CPUs by default.
+ It contains two required attributes, the attribute <code>vcpu</code>
+ specifies vcpu id, and the attribute <code>cpuset</code> is same as
+ attribute <code>cpuset</code> of element <code>vcpu</code>.
+ (NB: Only qemu driver support)
<span class="since">Since 0.9.0</span>
</dd>
<dt><code>emulatorpin</code></dt>
<dd>
The optional <code>emulatorpin</code> element specifies which of host
physical CPUs the "emulator", a subset of a domain not including vcpu,
- will be pinned to. If this is omitted, "emulator" is pinned to all
- the physical CPUs by default. It contains one required attribute
- <code>cpuset</code> specifying which physical CPUs to pin to.
+ will be pinned to. If this is omitted, and attribute
+ <code>cpuset</code> of element <code>vcpu</code> is not specified,
+ "emulator" is pinned to all the physical CPUs by default. It contains
+ one required attribute <code>cpuset</code> specifying which physical
+ CPUs to pin to. NB, <code>emulatorpin</code> is not allowed if
+ attribute <code>placement</code> of element <code>vcpu</code> is
+ "auto".
</dd>
<dt><code>shares</code></dt>
<dd>
--
1.7.7.6
12 years, 7 months
[libvirt] Some questions about virConnectAuthCallbackPtr
by Richard W.M. Jones
Some questions which seem to be left ambigious by the documentation
for virConnectAuthCallbackPtr:
http://libvirt.org/html/libvirt-libvirt.html#virConnectAuthCallbackPtr
(1) For a single open, can this be called multiple times? I'm
thinking, some authentication methods might give the user N attempts
at typing the password, which might result in N callbacks here.
(2) The documentation says: "Returns: 0 if all interactions were
filled, or -1 upon error". However it also says "If an interaction
cannot be filled, fill in NULL and 0". Does that mean it's OK (not an
error, return 0) if a result field is set to NULL?
Rich.
--
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
virt-top is 'top' for virtual machines. Tiny program with many
powerful monitoring features, net stats, disk stats, logging, etc.
http://et.redhat.com/~rjones/virt-top
12 years, 7 months
[libvirt] [PATCH 0/3] Add option to selectively enable IPv4/v6 forwarding
by Benjamin Cama
Hi,
Currently, when IP forwarding is enabled in a network element, libvirt enables
forwarding for IPv4/v6 on the OS if the bridge has some IP address of that
family. In some circumstances, one could only want forwarding for one family
and not the other, even if both address families are present; for example,
forwarding only IPv6 but still have some RFC1918 addresses on the “local”
network as a backup stack, or playing with IPv6 using (not forwarded) ULA
addresses, having some IPv4 NATed forwarding, without loosing IPv6 connectivity
because enabling it will disable auto-configuration (my case).
This patch adds a new optional "family" attribute to the "forward" element,
allowing selective forwarding: it can be set to "ipv4" or "ipv6". If not
present, the usual behavior of libvirt is kept, forwarding trafic for whichever
family there is an address on the bridge.
The first patch also remove libvirt's ability to set forwarding; I think it
should only check for it, letting the administrator enable it the usual way
(/etc/sysctl.conf or wathever) if he really wants it. In my case, this behavior
caused me to loose IPv6 connectivity when adding some ULA addresse to my VMs
bridge, because IPv6 forwarding was enabled in my back.
Regards,
Benjamin Cama (3):
Only check for IP forwarding, do not enable it
Add a "forward family" option
Take the forwarding family into account
src/conf/network_conf.c | 58 ++++++++++++++++++++++++++++++-
src/conf/network_conf.h | 1 +
src/network/bridge_driver.c | 81 +++++++++++++++++++++++++++++++++---------
3 files changed, 121 insertions(+), 19 deletions(-)
--
1.7.2.5
12 years, 7 months
[libvirt] [PATCHv3] Add support for SUSPEND_DISK event
by Martin Kletzander
This patch adds support for SUSPEND_DISK event; both lifecycle and
separated. The support is added for QEMU, machines are changed to
PMSUSPENDED, but as QEMU sends SHUTDOWN afterwards, the state changes
to shut-off. This and much more needs to be done in order for libvirt
to work with transient devices, wake-ups etc. This patch is not
aiming for that functionality.
---
daemon/remote.c | 25 +++++++++++
examples/domain-events/events-c/event-test.c | 22 +++++++++-
examples/domain-events/events-python/event-test.py | 3 +-
include/libvirt/libvirt.h.in | 29 +++++++++++++
python/libvirt-override-virConnect.py | 9 ++++
python/libvirt-override.c | 50 ++++++++++++++++++++++
src/conf/domain_event.c | 30 ++++++++++++-
src/conf/domain_event.h | 4 ++
src/libvirt_private.syms | 2 +
src/qemu/qemu_monitor.c | 10 +++++
src/qemu/qemu_monitor.h | 3 ++
src/qemu/qemu_monitor_json.c | 9 ++++
src/qemu/qemu_process.c | 47 ++++++++++++++++++++
src/remote/remote_driver.c | 31 ++++++++++++++
src/remote/remote_protocol.x | 7 ++-
src/remote_protocol-structs | 4 ++
16 files changed, 281 insertions(+), 4 deletions(-)
diff --git a/daemon/remote.c b/daemon/remote.c
index e7fe128..2d3f401 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -608,6 +608,30 @@ remoteRelayDomainEventBalloonChange(virConnectPtr conn ATTRIBUTE_UNUSED,
}
+static int remoteRelayDomainEventPMSuspendDisk(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virDomainPtr dom,
+ int reason ATTRIBUTE_UNUSED,
+ void *opaque) {
+ virNetServerClientPtr client = opaque;
+ remote_domain_event_pmsuspend_disk_msg data;
+
+ if (!client)
+ return -1;
+
+ VIR_DEBUG("Relaying domain %s %d system suspend-disk", dom->name, dom->id);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ make_nonnull_domain(&data.dom, dom);
+
+ remoteDispatchDomainEventSend(client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_PMSUSPEND_DISK,
+ (xdrproc_t)xdr_remote_domain_event_pmsuspend_disk_msg, &data);
+
+ return 0;
+}
+
+
static virConnectDomainEventGenericCallback domainEventCallbacks[] = {
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventReboot),
@@ -623,6 +647,7 @@ static virConnectDomainEventGenericCallback domainEventCallbacks[] = {
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventPMWakeup),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventPMSuspend),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBalloonChange),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventPMSuspendDisk),
};
verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST);
diff --git a/examples/domain-events/events-c/event-test.c b/examples/domain-events/events-c/event-test.c
index cde60fb..94104a0 100644
--- a/examples/domain-events/events-c/event-test.c
+++ b/examples/domain-events/events-c/event-test.c
@@ -201,6 +201,9 @@ static const char *eventDetailToString(int event, int detail) {
case VIR_DOMAIN_EVENT_PMSUSPENDED_MEMORY:
ret = "Memory";
break;
+ case VIR_DOMAIN_EVENT_PMSUSPENDED_DISK:
+ ret = "Disk";
+ break;
}
break;
}
@@ -402,6 +405,16 @@ static int myDomainEventPMSuspendCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
return 0;
}
+static int myDomainEventPMSuspendDiskCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virDomainPtr dom,
+ int reason ATTRIBUTE_UNUSED,
+ void *opaque ATTRIBUTE_UNUSED)
+{
+ printf("%s EVENT: Domain %s(%d) system suspend-disk\n",
+ __func__, virDomainGetName(dom), virDomainGetID(dom));
+ return 0;
+}
+
static void myFreeFunc(void *opaque)
{
char *str = opaque;
@@ -440,6 +453,7 @@ int main(int argc, char **argv)
int callback11ret = -1;
int callback12ret = -1;
int callback13ret = -1;
+ int callback14ret = -1;
struct sigaction action_stop;
memset(&action_stop, 0, sizeof(action_stop));
@@ -533,6 +547,11 @@ int main(int argc, char **argv)
VIR_DOMAIN_EVENT_ID_BALLOON_CHANGE,
VIR_DOMAIN_EVENT_CALLBACK(myDomainEventBalloonChangeCallback),
strdup("callback balloonchange"), myFreeFunc);
+ callback14ret = virConnectDomainEventRegisterAny(dconn,
+ NULL,
+ VIR_DOMAIN_EVENT_ID_PMSUSPEND_DISK,
+ VIR_DOMAIN_EVENT_CALLBACK(myDomainEventPMSuspendDiskCallback),
+ strdup("suspend-disk"), myFreeFunc);
if ((callback1ret != -1) &&
(callback2ret != -1) &&
(callback3ret != -1) &&
@@ -544,7 +563,8 @@ int main(int argc, char **argv)
(callback10ret != -1) &&
(callback11ret != -1) &&
(callback12ret != -1) &&
- (callback13ret != -1)) {
+ (callback13ret != -1) &&
+ (callback14ret != -1)) {
if (virConnectSetKeepAlive(dconn, 5, 3) < 0) {
virErrorPtr err = virGetLastError();
fprintf(stderr, "Failed to start keepalive protocol: %s\n",
diff --git a/examples/domain-events/events-python/event-test.py b/examples/domain-events/events-python/event-test.py
index 27e74c4..813b1c2 100644
--- a/examples/domain-events/events-python/event-test.py
+++ b/examples/domain-events/events-python/event-test.py
@@ -449,7 +449,7 @@ def detailToString(event, detail):
( "Unpaused", "Migrated", "Snapshot" ),
( "Shutdown", "Destroyed", "Crashed", "Migrated", "Saved", "Failed", "Snapshot"),
( "Finished", ),
- ( "Memory", )
+ ( "Memory", "Disk" )
)
return eventStrings[event][detail]
@@ -554,6 +554,7 @@ def main():
vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_PMWAKEUP, myDomainEventPMWakeupCallback, None)
vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_PMSUSPEND, myDomainEventPMSuspendCallback, None)
vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_BALLOON_CHANGE, myDomainEventBalloonChangeCallback, None)
+ vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_PMSUSPEND_DISK, myDomainEventPMSuspendDiskCallback, None)
vc.setKeepAlive(5, 3)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index a4e8ca9..5858c44 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -225,6 +225,14 @@ typedef enum {
#endif
} virDomainPMSuspendedReason;
+typedef enum {
+ VIR_DOMAIN_PMSUSPENDED_DISK_UNKNOWN = 0,
+
+#ifdef VIR_ENUM_SENTINELS
+ VIR_DOMAIN_PMSUSPENDED_DISK_LAST
+#endif
+} virDomainPMSuspendedDiskReason;
+
/**
* virDomainControlState:
*
@@ -3114,6 +3122,7 @@ typedef enum {
*/
typedef enum {
VIR_DOMAIN_EVENT_PMSUSPENDED_MEMORY = 0, /* Guest was PM suspended to memory */
+ VIR_DOMAIN_EVENT_PMSUSPENDED_DISK = 1, /* Guest was PM suspended to disk */
#ifdef VIR_ENUM_SENTINELS
VIR_DOMAIN_EVENT_PMSUSPENDED_LAST
@@ -4164,6 +4173,25 @@ typedef void (*virConnectDomainEventBalloonChangeCallback)(virConnectPtr conn,
void *opaque);
/**
+ * virConnectDomainEventPMSuspendDiskCallback:
+ * @conn: connection object
+ * @dom: domain on which the event occurred
+ * @reason: reason why the callback was called, unused currently,
+ * always passes 0
+ * @opaque: application specified data
+ *
+ * This callback occurs when the guest is suspended to disk.
+ *
+ * The callback signature to use when registering for an event of type
+ * VIR_DOMAIN_EVENT_ID_PMSUSPEND_DISK with virConnectDomainEventRegisterAny()
+ */
+typedef void (*virConnectDomainEventPMSuspendDiskCallback)(virConnectPtr conn,
+ virDomainPtr dom,
+ int reason,
+ void *opaque);
+
+
+/**
* VIR_DOMAIN_EVENT_CALLBACK:
*
* Used to cast the event specific callback into the generic one
@@ -4187,6 +4215,7 @@ typedef enum {
VIR_DOMAIN_EVENT_ID_PMWAKEUP = 11, /* virConnectDomainEventPMWakeupCallback */
VIR_DOMAIN_EVENT_ID_PMSUSPEND = 12, /* virConnectDomainEventPMSuspendCallback */
VIR_DOMAIN_EVENT_ID_BALLOON_CHANGE = 13, /* virConnectDomainEventBalloonChangeCallback */
+ VIR_DOMAIN_EVENT_ID_PMSUSPEND_DISK = 14, /* virConnectDomainEventPMSuspendDiskCallback */
#ifdef VIR_ENUM_SENTINELS
/*
diff --git a/python/libvirt-override-virConnect.py b/python/libvirt-override-virConnect.py
index 6bec66d..00bfcaf 100644
--- a/python/libvirt-override-virConnect.py
+++ b/python/libvirt-override-virConnect.py
@@ -170,6 +170,15 @@
cb(self, virDomain(self, _obj=dom), actual, opaque)
return 0
+ def _dispatchDomainEventPMSuspendDiskCallback(self, dom, reason, cbData):
+ """Dispatches event to python user domain suspend-disk event callbacks
+ """
+ cb = cbData["cb"]
+ opaque = cbData["opaque"]
+
+ cb(self, virDomain(self, _obj=dom), reason, opaque)
+ return 0;
+
def domainEventDeregisterAny(self, callbackID):
"""Removes a Domain Event Callback. De-registering for a
domain callback will disable delivery of this event type """
diff --git a/python/libvirt-override.c b/python/libvirt-override.c
index 81099b1..83dc925 100644
--- a/python/libvirt-override.c
+++ b/python/libvirt-override.c
@@ -5812,6 +5812,53 @@ libvirt_virConnectDomainEventBalloonChangeCallback(virConnectPtr conn ATTRIBUTE_
return ret;
}
+static int
+libvirt_virConnectDomainEventPMSuspendDiskCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virDomainPtr dom,
+ int reason,
+ 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*)"_dispatchDomainEventPMSuspendDiskCallback",
+ (char*)"OiO",
+ pyobj_dom,
+ reason,
+ pyobj_cbData);
+
+ Py_DECREF(pyobj_cbData);
+ Py_DECREF(pyobj_dom);
+
+ if(!pyobj_ret) {
+ DEBUG("%s - ret:%p\n", __FUNCTION__, pyobj_ret);
+ PyErr_Print();
+ } else {
+ Py_DECREF(pyobj_ret);
+ ret = 0;
+ }
+
+ LIBVIRT_RELEASE_THREAD_STATE;
+ return ret;
+}
+
static PyObject *
libvirt_virConnectDomainEventRegisterAny(ATTRIBUTE_UNUSED PyObject * self,
PyObject * args)
@@ -5884,6 +5931,9 @@ libvirt_virConnectDomainEventRegisterAny(ATTRIBUTE_UNUSED PyObject * self,
case VIR_DOMAIN_EVENT_ID_BALLOON_CHANGE:
cb = VIR_DOMAIN_EVENT_CALLBACK(libvirt_virConnectDomainEventBalloonChangeCallback);
break;
+ case VIR_DOMAIN_EVENT_ID_PMSUSPEND_DISK:
+ cb = VIR_DOMAIN_EVENT_CALLBACK(libvirt_virConnectDomainEventPMSuspendDiskCallback);
+ break;
}
if (!cb) {
diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c
index 7da4a1e..062752a 100644
--- a/src/conf/domain_event.c
+++ b/src/conf/domain_event.c
@@ -1,7 +1,7 @@
/*
* domain_event.c: domain event queue processing helpers
*
- * Copyright (C) 2010-2011 Red Hat, Inc.
+ * Copyright (C) 2010-2012 Red Hat, Inc.
* Copyright (C) 2008 VirtualIron
*
* This library is free software; you can redistribute it and/or
@@ -1125,6 +1125,30 @@ virDomainEventPMSuspendNewFromDom(virDomainPtr dom)
return virDomainEventPMSuspendNew(dom->id, dom->name, dom->uuid);
}
+static virDomainEventPtr
+virDomainEventPMSuspendDiskNew(int id, const char *name,
+ unsigned char *uuid)
+{
+ virDomainEventPtr ev =
+ virDomainEventNewInternal(VIR_DOMAIN_EVENT_ID_PMSUSPEND_DISK,
+ id, name, uuid);
+ return ev;
+}
+
+virDomainEventPtr
+virDomainEventPMSuspendDiskNewFromObj(virDomainObjPtr obj)
+{
+ return virDomainEventPMSuspendDiskNew(obj->def->id,
+ obj->def->name,
+ obj->def->uuid);
+}
+
+virDomainEventPtr
+virDomainEventPMSuspendDiskNewFromDom(virDomainPtr dom)
+{
+ return virDomainEventPMSuspendDiskNew(dom->id, dom->name, dom->uuid);
+}
+
virDomainEventPtr virDomainEventBalloonChangeNewFromDom(virDomainPtr dom,
unsigned long long actual)
{
@@ -1294,6 +1318,10 @@ virDomainEventDispatchDefaultFunc(virConnectPtr conn,
cbopaque);
break;
+ case VIR_DOMAIN_EVENT_ID_PMSUSPEND_DISK:
+ ((virConnectDomainEventPMSuspendDiskCallback)cb)(conn, dom, 0, cbopaque);
+ break;
+
default:
VIR_WARN("Unexpected event ID %d", event->eventID);
break;
diff --git a/src/conf/domain_event.h b/src/conf/domain_event.h
index 995b655..5f64a47 100644
--- a/src/conf/domain_event.h
+++ b/src/conf/domain_event.h
@@ -1,6 +1,7 @@
/*
* domain_event.h: domain event queue processing helpers
*
+ * Copyright (C) 2012 Red Hat, Inc.
* Copyright (C) 2008 VirtualIron
*
* This library is free software; you can redistribute it and/or
@@ -128,6 +129,9 @@ virDomainEventPtr virDomainEventPMSuspendNewFromDom(virDomainPtr dom);
virDomainEventPtr virDomainEventBalloonChangeNewFromDom(virDomainPtr dom, unsigned long long actual);
virDomainEventPtr virDomainEventBalloonChangeNewFromObj(virDomainObjPtr obj, unsigned long long actual);
+virDomainEventPtr virDomainEventPMSuspendDiskNewFromObj(virDomainObjPtr obj);
+virDomainEventPtr virDomainEventPMSuspendDiskNewFromDom(virDomainPtr dom);
+
void virDomainEventFree(virDomainEventPtr event);
void virDomainEventStateFree(virDomainEventStatePtr state);
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index fe31bbe..fdf4b8b 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -585,6 +585,8 @@ virDomainEventStateRegisterID;
virDomainEventStateFree;
virDomainEventStateNew;
virDomainEventStateQueue;
+virDomainEventPMSuspendDiskNewFromDom;
+virDomainEventPMSuspendDiskNewFromObj;
virDomainEventTrayChangeNewFromDom;
virDomainEventTrayChangeNewFromObj;
virDomainEventWatchdogNewFromDom;
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 85b0bc2..4313451 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -1111,6 +1111,16 @@ int qemuMonitorEmitPMSuspend(qemuMonitorPtr mon)
return ret;
}
+int qemuMonitorEmitPMSuspendDisk(qemuMonitorPtr mon)
+{
+ int ret = -1;
+ VIR_DEBUG("mon=%p", mon);
+
+ QEMU_MONITOR_CALLBACK(mon, ret, domainPMSuspendDisk, mon->vm);
+
+ return ret;
+}
+
int qemuMonitorEmitBlockJob(qemuMonitorPtr mon,
const char *diskAlias,
int type,
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 54b3a99..f33b94c 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -136,6 +136,8 @@ struct _qemuMonitorCallbacks {
int (*domainBalloonChange)(qemuMonitorPtr mon,
virDomainObjPtr vm,
unsigned long long actual);
+ int (*domainPMSuspendDisk)(qemuMonitorPtr mon,
+ virDomainObjPtr vm);
};
char *qemuMonitorEscapeArg(const char *in);
@@ -213,6 +215,7 @@ int qemuMonitorEmitBlockJob(qemuMonitorPtr mon,
int status);
int qemuMonitorEmitBalloonChange(qemuMonitorPtr mon,
unsigned long long actual);
+int qemuMonitorEmitPMSuspendDisk(qemuMonitorPtr mon);
int qemuMonitorStartCPUs(qemuMonitorPtr mon,
virConnectPtr conn);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index bd52ce4..c35948e 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -70,6 +70,7 @@ static void qemuMonitorJSONHandlePMSuspend(qemuMonitorPtr mon, virJSONValuePtr d
static void qemuMonitorJSONHandleBlockJobCompleted(qemuMonitorPtr mon, virJSONValuePtr data);
static void qemuMonitorJSONHandleBlockJobCanceled(qemuMonitorPtr mon, virJSONValuePtr data);
static void qemuMonitorJSONHandleBalloonChange(qemuMonitorPtr mon, virJSONValuePtr data);
+static void qemuMonitorJSONHandlePMSuspendDisk(qemuMonitorPtr mon, virJSONValuePtr data);
typedef struct {
const char *type;
@@ -91,6 +92,7 @@ static qemuEventHandler eventHandlers[] = {
{ "SPICE_INITIALIZED", qemuMonitorJSONHandleSPICEInitialize, },
{ "STOP", qemuMonitorJSONHandleStop, },
{ "SUSPEND", qemuMonitorJSONHandlePMSuspend, },
+ { "SUSPEND_DISK", qemuMonitorJSONHandlePMSuspendDisk, },
{ "VNC_CONNECTED", qemuMonitorJSONHandleVNCConnect, },
{ "VNC_DISCONNECTED", qemuMonitorJSONHandleVNCDisconnect, },
{ "VNC_INITIALIZED", qemuMonitorJSONHandleVNCInitialize, },
@@ -891,6 +893,13 @@ qemuMonitorJSONHandleBalloonChange(qemuMonitorPtr mon,
qemuMonitorEmitBalloonChange(mon, actual);
}
+static void
+qemuMonitorJSONHandlePMSuspendDisk(qemuMonitorPtr mon,
+ virJSONValuePtr data ATTRIBUTE_UNUSED)
+{
+ qemuMonitorEmitPMSuspendDisk(mon);
+}
+
int
qemuMonitorJSONHumanCommandWithFd(qemuMonitorPtr mon,
const char *cmd_str,
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index f8a2bfd..4c6c7d7 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -1178,6 +1178,52 @@ qemuProcessHandleBalloonChange(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
return 0;
}
+static int
+qemuProcessHandlePMSuspendDisk(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
+ virDomainObjPtr vm)
+{
+ struct qemud_driver *driver = qemu_driver;
+ virDomainEventPtr event = NULL;
+ virDomainEventPtr lifecycleEvent = NULL;
+
+ virDomainObjLock(vm);
+ event = virDomainEventPMSuspendDiskNewFromObj(vm);
+
+ if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ VIR_DEBUG("Transitioned guest %s to pmsuspended state due to "
+ "QMP suspend_disk event", vm->def->name);
+
+ virDomainObjSetState(vm, VIR_DOMAIN_PMSUSPENDED,
+ VIR_DOMAIN_PMSUSPENDED_UNKNOWN);
+ lifecycleEvent =
+ virDomainEventNewFromObj(vm,
+ VIR_DOMAIN_EVENT_PMSUSPENDED,
+ VIR_DOMAIN_EVENT_PMSUSPENDED_DISK);
+
+ if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) {
+ VIR_WARN("Unable to save status on vm %s after suspend event",
+ vm->def->name);
+ }
+
+ if (priv->agent)
+ qemuAgentNotifyEvent(priv->agent, QEMU_AGENT_EVENT_SUSPEND);
+ }
+
+ virDomainObjUnlock(vm);
+
+ if (event || lifecycleEvent) {
+ qemuDriverLock(driver);
+ if (event)
+ qemuDomainEventQueue(driver, event);
+ if (lifecycleEvent)
+ qemuDomainEventQueue(driver, lifecycleEvent);
+ qemuDriverUnlock(driver);
+ }
+
+ return 0;
+}
+
static qemuMonitorCallbacks monitorCallbacks = {
.destroy = qemuProcessHandleMonitorDestroy,
@@ -1196,6 +1242,7 @@ static qemuMonitorCallbacks monitorCallbacks = {
.domainPMWakeup = qemuProcessHandlePMWakeup,
.domainPMSuspend = qemuProcessHandlePMSuspend,
.domainBalloonChange = qemuProcessHandleBalloonChange,
+ .domainPMSuspendDisk = qemuProcessHandlePMSuspendDisk,
};
static int
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index fc4c696..3253de7 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -253,6 +253,10 @@ static void
remoteDomainBuildEventBalloonChange(virNetClientProgramPtr prog,
virNetClientPtr client,
void *evdata, void *opaque);
+static void
+remoteDomainBuildEventPMSuspendDisk(virNetClientProgramPtr prog,
+ virNetClientPtr client,
+ void *evdata, void *opaque);
static virNetClientProgramEvent remoteDomainEvents[] = {
{ REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE,
@@ -311,6 +315,10 @@ static virNetClientProgramEvent remoteDomainEvents[] = {
remoteDomainBuildEventBalloonChange,
sizeof(remote_domain_event_balloon_change_msg),
(xdrproc_t)xdr_remote_domain_event_balloon_change_msg },
+ { REMOTE_PROC_DOMAIN_EVENT_PMSUSPEND_DISK,
+ remoteDomainBuildEventPMSuspendDisk,
+ sizeof(remote_domain_event_pmsuspend_disk_msg),
+ (xdrproc_t)xdr_remote_domain_event_pmsuspend_disk_msg },
};
enum virDrvOpenRemoteFlags {
@@ -4575,6 +4583,29 @@ remoteDomainBuildEventBalloonChange(virNetClientProgramPtr prog ATTRIBUTE_UNUSED
}
+static void
+remoteDomainBuildEventPMSuspendDisk(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+ virNetClientPtr client ATTRIBUTE_UNUSED,
+ void *evdata, void *opaque)
+{
+ virConnectPtr conn = opaque;
+ struct private_data *priv = conn->privateData;
+ remote_domain_event_pmsuspend_disk_msg *msg = evdata;
+ virDomainPtr dom;
+ virDomainEventPtr event = NULL;
+
+ dom = get_nonnull_domain(conn, msg->dom);
+ if (!dom)
+ return;
+
+ event = virDomainEventPMSuspendDiskNewFromDom(dom);
+
+ virDomainFree(dom);
+
+ remoteDomainEventQueue(priv, event);
+}
+
+
static virDrvOpenStatus ATTRIBUTE_NONNULL (1)
remoteSecretOpen(virConnectPtr conn, virConnectAuthPtr auth,
unsigned int flags)
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index b0b530c..4359c82 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -2259,6 +2259,10 @@ struct remote_domain_event_balloon_change_msg {
unsigned hyper actual;
};
+struct remote_domain_event_pmsuspend_disk_msg {
+ remote_nonnull_domain dom;
+};
+
struct remote_domain_managed_save_args {
remote_nonnull_domain dom;
unsigned int flags;
@@ -3008,7 +3012,8 @@ enum remote_procedure {
REMOTE_PROC_NODE_GET_MEMORY_PARAMETERS = 289, /* skipgen skipgen */
REMOTE_PROC_DOMAIN_BLOCK_COMMIT = 290, /* autogen autogen */
- REMOTE_PROC_NETWORK_UPDATE = 291 /* autogen autogen priority:high */
+ REMOTE_PROC_NETWORK_UPDATE = 291, /* autogen autogen priority:high */
+ REMOTE_PROC_DOMAIN_EVENT_PMSUSPEND_DISK = 292 /* autogen autogen */
/*
* Notice how the entries are grouped in sets of 10 ?
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
index 4d2627a..0c0a317 100644
--- a/src/remote_protocol-structs
+++ b/src/remote_protocol-structs
@@ -1718,6 +1718,9 @@ struct remote_domain_event_balloon_change_msg {
remote_nonnull_domain dom;
uint64_t actual;
};
+struct remote_domain_event_pmsuspend_disk_msg {
+ remote_nonnull_domain dom;
+};
struct remote_domain_managed_save_args {
remote_nonnull_domain dom;
u_int flags;
@@ -2415,4 +2418,5 @@ enum remote_procedure {
REMOTE_PROC_NODE_GET_MEMORY_PARAMETERS = 289,
REMOTE_PROC_DOMAIN_BLOCK_COMMIT = 290,
REMOTE_PROC_NETWORK_UPDATE = 291,
+ REMOTE_PROC_DOMAIN_EVENT_PMSUSPEND_DISK = 292,
};
--
1.7.12.3
12 years, 7 months
[libvirt] [PATCH] Add support for SUSPEND_DISK event
by Martin Kletzander
This patch adds support for SUSPEND_DISK event; both lifecycle and
separated. The support is added for QEMU, machines are changed to
PMSUSPENDED, but as QEMU sends SHUTDOWN afterwards, the state changes
to shut-off. This and much more needs to be done in order for libvirt
to work with transient devices, wake-ups etc. This patch is not
aiming for that functionality.
---
daemon/remote.c | 25 +++++++++++
examples/domain-events/events-c/event-test.c | 22 +++++++++-
examples/domain-events/events-python/event-test.py | 3 +-
include/libvirt/libvirt.h.in | 29 +++++++++++++
python/libvirt-override-virConnect.py | 9 ++++
python/libvirt-override.c | 50 ++++++++++++++++++++++
src/conf/domain_event.c | 32 +++++++++++++-
src/conf/domain_event.h | 4 ++
src/libvirt_private.syms | 2 +
src/qemu/qemu_monitor.c | 10 +++++
src/qemu/qemu_monitor.h | 3 ++
src/qemu/qemu_monitor_json.c | 9 ++++
src/qemu/qemu_process.c | 47 ++++++++++++++++++++
src/remote/remote_driver.c | 31 ++++++++++++++
src/remote/remote_protocol.x | 7 ++-
src/remote_protocol-structs | 4 ++
16 files changed, 282 insertions(+), 5 deletions(-)
diff --git a/daemon/remote.c b/daemon/remote.c
index e7fe128..58017e5 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -608,6 +608,30 @@ remoteRelayDomainEventBalloonChange(virConnectPtr conn ATTRIBUTE_UNUSED,
}
+static int remoteRelayDomainEventSuspendDisk(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virDomainPtr dom,
+ int reason ATTRIBUTE_UNUSED,
+ void *opaque) {
+ virNetServerClientPtr client = opaque;
+ remote_domain_event_suspend_disk_msg data;
+
+ if (!client)
+ return -1;
+
+ VIR_DEBUG("Relaying domain %s %d system suspend-disk", dom->name, dom->id);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ make_nonnull_domain(&data.dom, dom);
+
+ remoteDispatchDomainEventSend(client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_SUSPEND_DISK,
+ (xdrproc_t)xdr_remote_domain_event_suspend_disk_msg, &data);
+
+ return 0;
+}
+
+
static virConnectDomainEventGenericCallback domainEventCallbacks[] = {
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventReboot),
@@ -623,6 +647,7 @@ static virConnectDomainEventGenericCallback domainEventCallbacks[] = {
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventPMWakeup),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventPMSuspend),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBalloonChange),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventSuspendDisk),
};
verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST);
diff --git a/examples/domain-events/events-c/event-test.c b/examples/domain-events/events-c/event-test.c
index cde60fb..856eb4f 100644
--- a/examples/domain-events/events-c/event-test.c
+++ b/examples/domain-events/events-c/event-test.c
@@ -201,6 +201,9 @@ static const char *eventDetailToString(int event, int detail) {
case VIR_DOMAIN_EVENT_PMSUSPENDED_MEMORY:
ret = "Memory";
break;
+ case VIR_DOMAIN_EVENT_PMSUSPENDED_DISK:
+ ret = "Disk";
+ break;
}
break;
}
@@ -402,6 +405,16 @@ static int myDomainEventPMSuspendCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
return 0;
}
+static int myDomainEventSuspendDiskCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virDomainPtr dom,
+ int reason ATTRIBUTE_UNUSED,
+ void *opaque ATTRIBUTE_UNUSED)
+{
+ printf("%s EVENT: Domain %s(%d) system suspend-disk\n",
+ __func__, virDomainGetName(dom), virDomainGetID(dom));
+ return 0;
+}
+
static void myFreeFunc(void *opaque)
{
char *str = opaque;
@@ -440,6 +453,7 @@ int main(int argc, char **argv)
int callback11ret = -1;
int callback12ret = -1;
int callback13ret = -1;
+ int callback14ret = -1;
struct sigaction action_stop;
memset(&action_stop, 0, sizeof(action_stop));
@@ -533,6 +547,11 @@ int main(int argc, char **argv)
VIR_DOMAIN_EVENT_ID_BALLOON_CHANGE,
VIR_DOMAIN_EVENT_CALLBACK(myDomainEventBalloonChangeCallback),
strdup("callback balloonchange"), myFreeFunc);
+ callback14ret = virConnectDomainEventRegisterAny(dconn,
+ NULL,
+ VIR_DOMAIN_EVENT_ID_SUSPEND_DISK,
+ VIR_DOMAIN_EVENT_CALLBACK(myDomainEventSuspendDiskCallback),
+ strdup("suspend-disk"), myFreeFunc);
if ((callback1ret != -1) &&
(callback2ret != -1) &&
(callback3ret != -1) &&
@@ -544,7 +563,8 @@ int main(int argc, char **argv)
(callback10ret != -1) &&
(callback11ret != -1) &&
(callback12ret != -1) &&
- (callback13ret != -1)) {
+ (callback13ret != -1) &&
+ (callback14ret != -1)) {
if (virConnectSetKeepAlive(dconn, 5, 3) < 0) {
virErrorPtr err = virGetLastError();
fprintf(stderr, "Failed to start keepalive protocol: %s\n",
diff --git a/examples/domain-events/events-python/event-test.py b/examples/domain-events/events-python/event-test.py
index 27e74c4..bf11fb9 100644
--- a/examples/domain-events/events-python/event-test.py
+++ b/examples/domain-events/events-python/event-test.py
@@ -449,7 +449,7 @@ def detailToString(event, detail):
( "Unpaused", "Migrated", "Snapshot" ),
( "Shutdown", "Destroyed", "Crashed", "Migrated", "Saved", "Failed", "Snapshot"),
( "Finished", ),
- ( "Memory", )
+ ( "Memory", "Disk" )
)
return eventStrings[event][detail]
@@ -554,6 +554,7 @@ def main():
vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_PMWAKEUP, myDomainEventPMWakeupCallback, None)
vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_PMSUSPEND, myDomainEventPMSuspendCallback, None)
vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_BALLOON_CHANGE, myDomainEventBalloonChangeCallback, None)
+ vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_SUSPEND_DISK, myDomainEventSuspendDiskCallback, None)
vc.setKeepAlive(5, 3)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index a4e8ca9..422819c 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -225,6 +225,14 @@ typedef enum {
#endif
} virDomainPMSuspendedReason;
+typedef enum {
+ VIR_DOMAIN_SUSPENDED_DISK_UNKNOWN = 0,
+
+#ifdef VIR_ENUM_SENTINELS
+ VIR_DOMAIN_SUSPENDED_DISK_LAST
+#endif
+} virDomainSuspendedDiskReason;
+
/**
* virDomainControlState:
*
@@ -3114,6 +3122,7 @@ typedef enum {
*/
typedef enum {
VIR_DOMAIN_EVENT_PMSUSPENDED_MEMORY = 0, /* Guest was PM suspended to memory */
+ VIR_DOMAIN_EVENT_PMSUSPENDED_DISK = 1, /* Guest was PM suspended to disk */
#ifdef VIR_ENUM_SENTINELS
VIR_DOMAIN_EVENT_PMSUSPENDED_LAST
@@ -4164,6 +4173,25 @@ typedef void (*virConnectDomainEventBalloonChangeCallback)(virConnectPtr conn,
void *opaque);
/**
+ * virConnectDomainEventSuspendDiskCallback:
+ * @conn: connection object
+ * @dom: domain on which the event occurred
+ * @reason: reason why the callback was called, unused currently,
+ * always passes 0
+ * @opaque: application specified data
+ *
+ * This callback occurs when the guest is suspended to disk.
+ *
+ * The callback signature to use when registering for an event of type
+ * VIR_DOMAIN_EVENT_ID_SUSPEND_DISK with virConnectDomainEventRegisterAny()
+ */
+typedef void (*virConnectDomainEventSuspendDiskCallback)(virConnectPtr conn,
+ virDomainPtr dom,
+ int reason,
+ void *opaque);
+
+
+/**
* VIR_DOMAIN_EVENT_CALLBACK:
*
* Used to cast the event specific callback into the generic one
@@ -4187,6 +4215,7 @@ typedef enum {
VIR_DOMAIN_EVENT_ID_PMWAKEUP = 11, /* virConnectDomainEventPMWakeupCallback */
VIR_DOMAIN_EVENT_ID_PMSUSPEND = 12, /* virConnectDomainEventPMSuspendCallback */
VIR_DOMAIN_EVENT_ID_BALLOON_CHANGE = 13, /* virConnectDomainEventBalloonChangeCallback */
+ VIR_DOMAIN_EVENT_ID_SUSPEND_DISK = 14, /* virConnectDomainEventSuspendDiskCallback */
#ifdef VIR_ENUM_SENTINELS
/*
diff --git a/python/libvirt-override-virConnect.py b/python/libvirt-override-virConnect.py
index 6bec66d..3136841 100644
--- a/python/libvirt-override-virConnect.py
+++ b/python/libvirt-override-virConnect.py
@@ -170,6 +170,15 @@
cb(self, virDomain(self, _obj=dom), actual, opaque)
return 0
+ def _dispatchDomainEventSuspendDiskCallback(self, dom, reason, cbData):
+ """Dispatches event to python user domain suspend-disk event callbacks
+ """
+ cb = cbData["cb"]
+ opaque = cbData["opaque"]
+
+ cb(self, virDomain(self, _obj=dom), reason, opaque)
+ return 0;
+
def domainEventDeregisterAny(self, callbackID):
"""Removes a Domain Event Callback. De-registering for a
domain callback will disable delivery of this event type """
diff --git a/python/libvirt-override.c b/python/libvirt-override.c
index 81099b1..bc73ad0 100644
--- a/python/libvirt-override.c
+++ b/python/libvirt-override.c
@@ -5812,6 +5812,53 @@ libvirt_virConnectDomainEventBalloonChangeCallback(virConnectPtr conn ATTRIBUTE_
return ret;
}
+static int
+libvirt_virConnectDomainEventSuspendDiskCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virDomainPtr dom,
+ int reason,
+ 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*)"_dispatchDomainEventSuspendDiskCallback",
+ (char*)"OiO",
+ pyobj_dom,
+ reason,
+ pyobj_cbData);
+
+ Py_DECREF(pyobj_cbData);
+ Py_DECREF(pyobj_dom);
+
+ if(!pyobj_ret) {
+ DEBUG("%s - ret:%p\n", __FUNCTION__, pyobj_ret);
+ PyErr_Print();
+ } else {
+ Py_DECREF(pyobj_ret);
+ ret = 0;
+ }
+
+ LIBVIRT_RELEASE_THREAD_STATE;
+ return ret;
+}
+
static PyObject *
libvirt_virConnectDomainEventRegisterAny(ATTRIBUTE_UNUSED PyObject * self,
PyObject * args)
@@ -5884,6 +5931,9 @@ libvirt_virConnectDomainEventRegisterAny(ATTRIBUTE_UNUSED PyObject * self,
case VIR_DOMAIN_EVENT_ID_BALLOON_CHANGE:
cb = VIR_DOMAIN_EVENT_CALLBACK(libvirt_virConnectDomainEventBalloonChangeCallback);
break;
+ case VIR_DOMAIN_EVENT_ID_SUSPEND_DISK:
+ cb = VIR_DOMAIN_EVENT_CALLBACK(libvirt_virConnectDomainEventSuspendDiskCallback);
+ break;
}
if (!cb) {
diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c
index 7da4a1e..c7010c8 100644
--- a/src/conf/domain_event.c
+++ b/src/conf/domain_event.c
@@ -1,7 +1,7 @@
/*
* domain_event.c: domain event queue processing helpers
*
- * Copyright (C) 2010-2011 Red Hat, Inc.
+ * Copyright (C) 2010-2012 Red Hat, Inc.
* Copyright (C) 2008 VirtualIron
*
* This library is free software; you can redistribute it and/or
@@ -1107,10 +1107,10 @@ virDomainEventPMSuspendNew(int id, const char *name,
virDomainEventPtr ev =
virDomainEventNewInternal(VIR_DOMAIN_EVENT_ID_PMSUSPEND,
id, name, uuid);
-
return ev;
}
+
virDomainEventPtr
virDomainEventPMSuspendNewFromObj(virDomainObjPtr obj)
{
@@ -1125,6 +1125,30 @@ virDomainEventPMSuspendNewFromDom(virDomainPtr dom)
return virDomainEventPMSuspendNew(dom->id, dom->name, dom->uuid);
}
+static virDomainEventPtr
+virDomainEventSuspendDiskNew(int id, const char *name,
+ unsigned char *uuid)
+{
+ virDomainEventPtr ev =
+ virDomainEventNewInternal(VIR_DOMAIN_EVENT_ID_SUSPEND_DISK,
+ id, name, uuid);
+ return ev;
+}
+
+virDomainEventPtr
+virDomainEventSuspendDiskNewFromObj(virDomainObjPtr obj)
+{
+ return virDomainEventSuspendDiskNew(obj->def->id,
+ obj->def->name,
+ obj->def->uuid);
+}
+
+virDomainEventPtr
+virDomainEventSuspendDiskNewFromDom(virDomainPtr dom)
+{
+ return virDomainEventSuspendDiskNew(dom->id, dom->name, dom->uuid);
+}
+
virDomainEventPtr virDomainEventBalloonChangeNewFromDom(virDomainPtr dom,
unsigned long long actual)
{
@@ -1294,6 +1318,10 @@ virDomainEventDispatchDefaultFunc(virConnectPtr conn,
cbopaque);
break;
+ case VIR_DOMAIN_EVENT_ID_SUSPEND_DISK:
+ ((virConnectDomainEventSuspendDiskCallback)cb)(conn, dom, 0, cbopaque);
+ break;
+
default:
VIR_WARN("Unexpected event ID %d", event->eventID);
break;
diff --git a/src/conf/domain_event.h b/src/conf/domain_event.h
index 995b655..173eba8 100644
--- a/src/conf/domain_event.h
+++ b/src/conf/domain_event.h
@@ -1,6 +1,7 @@
/*
* domain_event.h: domain event queue processing helpers
*
+ * Copyright (C) 2012 Red Hat, Inc.
* Copyright (C) 2008 VirtualIron
*
* This library is free software; you can redistribute it and/or
@@ -128,6 +129,9 @@ virDomainEventPtr virDomainEventPMSuspendNewFromDom(virDomainPtr dom);
virDomainEventPtr virDomainEventBalloonChangeNewFromDom(virDomainPtr dom, unsigned long long actual);
virDomainEventPtr virDomainEventBalloonChangeNewFromObj(virDomainObjPtr obj, unsigned long long actual);
+virDomainEventPtr virDomainEventSuspendDiskNewFromObj(virDomainObjPtr obj);
+virDomainEventPtr virDomainEventSuspendDiskNewFromDom(virDomainPtr dom);
+
void virDomainEventFree(virDomainEventPtr event);
void virDomainEventStateFree(virDomainEventStatePtr state);
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index fe31bbe..c1f08e0 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -585,6 +585,8 @@ virDomainEventStateRegisterID;
virDomainEventStateFree;
virDomainEventStateNew;
virDomainEventStateQueue;
+virDomainEventSuspendDiskNewFromDom;
+virDomainEventSuspendDiskNewFromObj;
virDomainEventTrayChangeNewFromDom;
virDomainEventTrayChangeNewFromObj;
virDomainEventWatchdogNewFromDom;
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 85b0bc2..b0fa682 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -1111,6 +1111,16 @@ int qemuMonitorEmitPMSuspend(qemuMonitorPtr mon)
return ret;
}
+int qemuMonitorEmitSuspendDisk(qemuMonitorPtr mon)
+{
+ int ret = -1;
+ VIR_DEBUG("mon=%p", mon);
+
+ QEMU_MONITOR_CALLBACK(mon, ret, domainSuspendDisk, mon->vm);
+
+ return ret;
+}
+
int qemuMonitorEmitBlockJob(qemuMonitorPtr mon,
const char *diskAlias,
int type,
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 54b3a99..f4dc94f 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -136,6 +136,8 @@ struct _qemuMonitorCallbacks {
int (*domainBalloonChange)(qemuMonitorPtr mon,
virDomainObjPtr vm,
unsigned long long actual);
+ int (*domainSuspendDisk)(qemuMonitorPtr mon,
+ virDomainObjPtr vm);
};
char *qemuMonitorEscapeArg(const char *in);
@@ -213,6 +215,7 @@ int qemuMonitorEmitBlockJob(qemuMonitorPtr mon,
int status);
int qemuMonitorEmitBalloonChange(qemuMonitorPtr mon,
unsigned long long actual);
+int qemuMonitorEmitSuspendDisk(qemuMonitorPtr mon);
int qemuMonitorStartCPUs(qemuMonitorPtr mon,
virConnectPtr conn);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index bd52ce4..d0fd23a 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -70,6 +70,7 @@ static void qemuMonitorJSONHandlePMSuspend(qemuMonitorPtr mon, virJSONValuePtr d
static void qemuMonitorJSONHandleBlockJobCompleted(qemuMonitorPtr mon, virJSONValuePtr data);
static void qemuMonitorJSONHandleBlockJobCanceled(qemuMonitorPtr mon, virJSONValuePtr data);
static void qemuMonitorJSONHandleBalloonChange(qemuMonitorPtr mon, virJSONValuePtr data);
+static void qemuMonitorJSONHandleSuspendDisk(qemuMonitorPtr mon, virJSONValuePtr data);
typedef struct {
const char *type;
@@ -91,6 +92,7 @@ static qemuEventHandler eventHandlers[] = {
{ "SPICE_INITIALIZED", qemuMonitorJSONHandleSPICEInitialize, },
{ "STOP", qemuMonitorJSONHandleStop, },
{ "SUSPEND", qemuMonitorJSONHandlePMSuspend, },
+ { "SUSPEND_DISK", qemuMonitorJSONHandleSuspendDisk, },
{ "VNC_CONNECTED", qemuMonitorJSONHandleVNCConnect, },
{ "VNC_DISCONNECTED", qemuMonitorJSONHandleVNCDisconnect, },
{ "VNC_INITIALIZED", qemuMonitorJSONHandleVNCInitialize, },
@@ -891,6 +893,13 @@ qemuMonitorJSONHandleBalloonChange(qemuMonitorPtr mon,
qemuMonitorEmitBalloonChange(mon, actual);
}
+static void
+qemuMonitorJSONHandleSuspendDisk(qemuMonitorPtr mon,
+ virJSONValuePtr data ATTRIBUTE_UNUSED)
+{
+ qemuMonitorEmitSuspendDisk(mon);
+}
+
int
qemuMonitorJSONHumanCommandWithFd(qemuMonitorPtr mon,
const char *cmd_str,
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index f8a2bfd..02beb5d 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -1178,6 +1178,52 @@ qemuProcessHandleBalloonChange(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
return 0;
}
+static int
+qemuProcessHandleSuspendDisk(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
+ virDomainObjPtr vm)
+{
+ struct qemud_driver *driver = qemu_driver;
+ virDomainEventPtr event = NULL;
+ virDomainEventPtr lifecycleEvent = NULL;
+
+ virDomainObjLock(vm);
+ event = virDomainEventSuspendDiskNewFromObj(vm);
+
+ if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ VIR_DEBUG("Transitioned guest %s to pmsuspended state due to "
+ "QMP suspend_disk event", vm->def->name);
+
+ virDomainObjSetState(vm, VIR_DOMAIN_PMSUSPENDED,
+ VIR_DOMAIN_PMSUSPENDED_UNKNOWN);
+ lifecycleEvent =
+ virDomainEventNewFromObj(vm,
+ VIR_DOMAIN_EVENT_PMSUSPENDED,
+ VIR_DOMAIN_EVENT_PMSUSPENDED_DISK);
+
+ if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) {
+ VIR_WARN("Unable to save status on vm %s after suspend event",
+ vm->def->name);
+ }
+
+ if (priv->agent)
+ qemuAgentNotifyEvent(priv->agent, QEMU_AGENT_EVENT_SUSPEND);
+ }
+
+ virDomainObjUnlock(vm);
+
+ if (event || lifecycleEvent) {
+ qemuDriverLock(driver);
+ if (event)
+ qemuDomainEventQueue(driver, event);
+ if (lifecycleEvent)
+ qemuDomainEventQueue(driver, lifecycleEvent);
+ qemuDriverUnlock(driver);
+ }
+
+ return 0;
+}
+
static qemuMonitorCallbacks monitorCallbacks = {
.destroy = qemuProcessHandleMonitorDestroy,
@@ -1196,6 +1242,7 @@ static qemuMonitorCallbacks monitorCallbacks = {
.domainPMWakeup = qemuProcessHandlePMWakeup,
.domainPMSuspend = qemuProcessHandlePMSuspend,
.domainBalloonChange = qemuProcessHandleBalloonChange,
+ .domainSuspendDisk = qemuProcessHandleSuspendDisk,
};
static int
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index fc4c696..741c159 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -253,6 +253,10 @@ static void
remoteDomainBuildEventBalloonChange(virNetClientProgramPtr prog,
virNetClientPtr client,
void *evdata, void *opaque);
+static void
+remoteDomainBuildEventSuspendDisk(virNetClientProgramPtr prog,
+ virNetClientPtr client,
+ void *evdata, void *opaque);
static virNetClientProgramEvent remoteDomainEvents[] = {
{ REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE,
@@ -311,6 +315,10 @@ static virNetClientProgramEvent remoteDomainEvents[] = {
remoteDomainBuildEventBalloonChange,
sizeof(remote_domain_event_balloon_change_msg),
(xdrproc_t)xdr_remote_domain_event_balloon_change_msg },
+ { REMOTE_PROC_DOMAIN_EVENT_SUSPEND_DISK,
+ remoteDomainBuildEventSuspendDisk,
+ sizeof(remote_domain_event_suspend_disk_msg),
+ (xdrproc_t)xdr_remote_domain_event_suspend_disk_msg },
};
enum virDrvOpenRemoteFlags {
@@ -4575,6 +4583,29 @@ remoteDomainBuildEventBalloonChange(virNetClientProgramPtr prog ATTRIBUTE_UNUSED
}
+static void
+remoteDomainBuildEventSuspendDisk(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+ virNetClientPtr client ATTRIBUTE_UNUSED,
+ void *evdata, void *opaque)
+{
+ virConnectPtr conn = opaque;
+ struct private_data *priv = conn->privateData;
+ remote_domain_event_suspend_disk_msg *msg = evdata;
+ virDomainPtr dom;
+ virDomainEventPtr event = NULL;
+
+ dom = get_nonnull_domain(conn, msg->dom);
+ if (!dom)
+ return;
+
+ event = virDomainEventSuspendDiskNewFromDom(dom);
+
+ virDomainFree(dom);
+
+ remoteDomainEventQueue(priv, event);
+}
+
+
static virDrvOpenStatus ATTRIBUTE_NONNULL (1)
remoteSecretOpen(virConnectPtr conn, virConnectAuthPtr auth,
unsigned int flags)
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index b0b530c..94ea947 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -2259,6 +2259,10 @@ struct remote_domain_event_balloon_change_msg {
unsigned hyper actual;
};
+struct remote_domain_event_suspend_disk_msg {
+ remote_nonnull_domain dom;
+};
+
struct remote_domain_managed_save_args {
remote_nonnull_domain dom;
unsigned int flags;
@@ -3008,7 +3012,8 @@ enum remote_procedure {
REMOTE_PROC_NODE_GET_MEMORY_PARAMETERS = 289, /* skipgen skipgen */
REMOTE_PROC_DOMAIN_BLOCK_COMMIT = 290, /* autogen autogen */
- REMOTE_PROC_NETWORK_UPDATE = 291 /* autogen autogen priority:high */
+ REMOTE_PROC_NETWORK_UPDATE = 291, /* autogen autogen priority:high */
+ REMOTE_PROC_DOMAIN_EVENT_SUSPEND_DISK = 292 /* autogen autogen */
/*
* Notice how the entries are grouped in sets of 10 ?
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
index 4d2627a..cbdd27c 100644
--- a/src/remote_protocol-structs
+++ b/src/remote_protocol-structs
@@ -1718,6 +1718,9 @@ struct remote_domain_event_balloon_change_msg {
remote_nonnull_domain dom;
uint64_t actual;
};
+struct remote_domain_event_suspend_disk_msg {
+ remote_nonnull_domain dom;
+};
struct remote_domain_managed_save_args {
remote_nonnull_domain dom;
u_int flags;
@@ -2415,4 +2418,5 @@ enum remote_procedure {
REMOTE_PROC_NODE_GET_MEMORY_PARAMETERS = 289,
REMOTE_PROC_DOMAIN_BLOCK_COMMIT = 290,
REMOTE_PROC_NETWORK_UPDATE = 291,
+ REMOTE_PROC_DOMAIN_EVENT_SUSPEND_DISK = 292,
};
--
1.7.12.3
12 years, 7 months