diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 99642b647c..cb5a3e2838 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 d7faa9027a..00ce8136e6 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 2d2d254eed..de5f1155e8 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 f5fc1b36fd..938c17efcf 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -735,6 +735,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, @@ -1250,6 +1305,7 @@ static qemuMonitorCallbacks monitorCallbacks = { .diskSecretLookup = qemuProcessFindVolumeQcowPassphrase, .domainShutdown = qemuProcessHandleShutdown, .domainStop = qemuProcessHandleStop, + .domainResume = qemuProcessHandleResume, .domainReset = qemuProcessHandleReset, .domainRTCChange = qemuProcessHandleRTCChange, .domainWatchdog = qemuProcessHandleWatchdog,