Perform all the appropriate plumbing.
When qemu/KVM VMs are paused manually through a monitor not-owned by libvirt,
libvirt will think of them as "paused" event after they are resumed and
effectively running. With this patch the discrepancy goes away.
This is meant to address bug 892791.
Signed-off-by: Andres Lagar-Cavilla <andres(a)lagarcavilla.org>
---
src/qemu/qemu_monitor.c | 10 ++++++++
src/qemu/qemu_monitor.h | 3 +++
src/qemu/qemu_monitor_json.c | 7 ++++++
src/qemu/qemu_process.c | 56 ++++++++++++++++++++++++++++++++++++++++++
4 files changed, 76 insertions(+)
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 99642b6..cb5a3e2 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -1022,6 +1022,16 @@ int qemuMonitorEmitStop(qemuMonitorPtr mon)
}
+int qemuMonitorEmitResume(qemuMonitorPtr mon)
+{
+ int ret = -1;
+ VIR_DEBUG("mon=%p", mon);
+
+ QEMU_MONITOR_CALLBACK(mon, ret, domainResume, mon->vm);
+ return ret;
+}
+
+
int qemuMonitorEmitRTCChange(qemuMonitorPtr mon, long long offset)
{
int ret = -1;
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index d7faa90..00ce813 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -97,6 +97,8 @@ struct _qemuMonitorCallbacks {
virDomainObjPtr vm);
int (*domainStop)(qemuMonitorPtr mon,
virDomainObjPtr vm);
+ int (*domainResume)(qemuMonitorPtr mon,
+ virDomainObjPtr vm);
int (*domainRTCChange)(qemuMonitorPtr mon,
virDomainObjPtr vm,
long long offset);
@@ -187,6 +189,7 @@ int qemuMonitorEmitShutdown(qemuMonitorPtr mon);
int qemuMonitorEmitReset(qemuMonitorPtr mon);
int qemuMonitorEmitPowerdown(qemuMonitorPtr mon);
int qemuMonitorEmitStop(qemuMonitorPtr mon);
+int qemuMonitorEmitResume(qemuMonitorPtr mon);
int qemuMonitorEmitRTCChange(qemuMonitorPtr mon, long long offset);
int qemuMonitorEmitWatchdog(qemuMonitorPtr mon, int action);
int qemuMonitorEmitIOError(qemuMonitorPtr mon,
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 2d2d254..de5f115 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -55,6 +55,7 @@ static void qemuMonitorJSONHandleShutdown(qemuMonitorPtr mon,
virJSONValuePtr da
static void qemuMonitorJSONHandleReset(qemuMonitorPtr mon, virJSONValuePtr data);
static void qemuMonitorJSONHandlePowerdown(qemuMonitorPtr mon, virJSONValuePtr data);
static void qemuMonitorJSONHandleStop(qemuMonitorPtr mon, virJSONValuePtr data);
+static void qemuMonitorJSONHandleResume(qemuMonitorPtr mon, virJSONValuePtr data);
static void qemuMonitorJSONHandleRTCChange(qemuMonitorPtr mon, virJSONValuePtr data);
static void qemuMonitorJSONHandleWatchdog(qemuMonitorPtr mon, virJSONValuePtr data);
static void qemuMonitorJSONHandleIOError(qemuMonitorPtr mon, virJSONValuePtr data);
@@ -87,6 +88,7 @@ static qemuEventHandler eventHandlers[] = {
{ "DEVICE_TRAY_MOVED", qemuMonitorJSONHandleTrayChange, },
{ "POWERDOWN", qemuMonitorJSONHandlePowerdown, },
{ "RESET", qemuMonitorJSONHandleReset, },
+ { "RESUME", qemuMonitorJSONHandleResume, },
{ "RTC_CHANGE", qemuMonitorJSONHandleRTCChange, },
{ "SHUTDOWN", qemuMonitorJSONHandleShutdown, },
{ "SPICE_CONNECTED", qemuMonitorJSONHandleSPICEConnect, },
@@ -589,6 +591,11 @@ static void qemuMonitorJSONHandleStop(qemuMonitorPtr mon,
virJSONValuePtr data A
qemuMonitorEmitStop(mon);
}
+static void qemuMonitorJSONHandleResume(qemuMonitorPtr mon, virJSONValuePtr data
ATTRIBUTE_UNUSED)
+{
+ qemuMonitorEmitResume(mon);
+}
+
static void qemuMonitorJSONHandleRTCChange(qemuMonitorPtr mon, virJSONValuePtr data)
{
long long offset = 0;
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index f5fc1b3..938c17e 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -736,6 +736,61 @@ unlock:
static int
+qemuProcessHandleResume(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
+ virDomainObjPtr vm)
+{
+ virQEMUDriverPtr driver = qemu_driver;
+ virDomainEventPtr event = NULL;
+
+ virDomainObjLock(vm);
+ if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+
+ if (priv->gotShutdown) {
+ VIR_DEBUG("Ignoring RESUME event after SHUTDOWN");
+ goto unlock;
+ }
+
+ VIR_DEBUG("Transitioned guest %s out of paused into resumed state",
+ vm->def->name);
+
+ virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
+ VIR_DOMAIN_RUNNING_UNPAUSED);
+ event = virDomainEventNewFromObj(vm,
+ VIR_DOMAIN_EVENT_RESUMED,
+ VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
+
+ VIR_DEBUG("Using lock state '%s' on resume event",
NULLSTR(priv->lockState));
+ if (virDomainLockProcessResume(driver->lockManager, driver->uri,
+ vm, priv->lockState) < 0) {
+ /* Don't free priv->lockState on error, because we need
+ * to make sure we have state still present if the user
+ * tries to resume again
+ */
+ goto unlock;
+ }
+ VIR_FREE(priv->lockState);
+
+ if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) {
+ VIR_WARN("Unable to save status on vm %s after state change",
+ vm->def->name);
+ }
+ }
+
+unlock:
+ virDomainObjUnlock(vm);
+
+ if (event) {
+ qemuDriverLock(driver);
+ qemuDomainEventQueue(driver, event);
+ qemuDriverUnlock(driver);
+ }
+
+ return 0;
+}
+
+
+static int
qemuProcessHandleRTCChange(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
virDomainObjPtr vm,
long long offset)
@@ -1250,6 +1305,7 @@ static qemuMonitorCallbacks monitorCallbacks = {
.diskSecretLookup = qemuProcessFindVolumeQcowPassphrase,
.domainShutdown = qemuProcessHandleShutdown,
.domainStop = qemuProcessHandleStop,
+ .domainResume = qemuProcessHandleResume,
.domainReset = qemuProcessHandleReset,
.domainRTCChange = qemuProcessHandleRTCChange,
.domainWatchdog = qemuProcessHandleWatchdog,
--
1.7.9.5