diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 360cc67c0e..b758b5a0d4 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -265,6 +265,7 @@ VIR_ENUM_IMPL(virQEMUCaps, QEMU_CAPS_LAST, "numa", "memory-backend-file", "usb-audio", + "rtc-reset-reinjection", ); @@ -1424,6 +1425,7 @@ struct virQEMUCapsStringFlags virQEMUCapsCommands[] = { { "add-fd", QEMU_CAPS_ADD_FD }, { "nbd-server-start", QEMU_CAPS_NBD_SERVER }, { "change-backing-file", QEMU_CAPS_CHANGE_BACKING_FILE }, + { "rtc-reset-reinjection", QEMU_CAPS_RTC_RESET_REINJECTION }, }; struct virQEMUCapsStringFlags virQEMUCapsEvents[] = { diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 2911759b0e..cbd3646c30 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -213,6 +213,7 @@ typedef enum { QEMU_CAPS_NUMA = 171, /* newer -numa handling with disjoint cpu ranges */ QEMU_CAPS_OBJECT_MEMORY_FILE = 172, /* -object memory-backend-file */ QEMU_CAPS_OBJECT_USB_AUDIO = 173, /* usb-audio device support */ + QEMU_CAPS_RTC_RESET_REINJECTION = 174, /* rtc-reset-reinjection monitor command */ QEMU_CAPS_LAST, /* this must always be the last item */ } virQEMUCapsFlags; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 28a56a97fa..c4d40c2be4 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -16844,6 +16844,13 @@ qemuDomainSetTime(virDomainPtr dom, priv = vm->privateData; + if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_RTC_RESET_REINJECTION)) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("cannot set time: qemu doesn't support " + "rtc-reset-reinjection command")); + goto cleanup; + } + if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0) goto cleanup; @@ -16860,6 +16867,16 @@ qemuDomainSetTime(virDomainPtr dom, rv = qemuAgentSetTime(priv->agent, seconds, nseconds, rtcSync); qemuDomainObjExitAgent(vm); + if (!virDomainObjIsActive(vm)) { + virReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is not running")); + goto endjob; + } + + qemuDomainObjEnterMonitor(driver, vm); + rv = qemuMonitorRTCResetReinjection(priv->mon); + qemuDomainObjExitMonitor(driver, vm); + if (rv < 0) goto endjob; diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 3d9f87b63f..d5ba08de97 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -4037,3 +4037,36 @@ qemuMonitorGetGuestCPU(qemuMonitorPtr mon, return qemuMonitorJSONGetGuestCPU(mon, arch, data); } + +/** + * qemuMonitorRTCResetReinjection: + * @mon: Pointer to the monitor + * + * Issue rtc-reset-reinjection command. + * This should be used in cases where guest time is restored via + * guest agent, so RTC injection is not needed (in fact it would + * confuse guest's RTC). + * + * Returns 0 on success + * -1 on error. + */ +int +qemuMonitorRTCResetReinjection(qemuMonitorPtr mon) +{ + + VIR_DEBUG("mon=%p", mon); + + if (!mon) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("monitor must not be NULL")); + return -1; + } + + if (!mon->json) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("JSON monitor is required")); + return -1; + } + + return qemuMonitorJSONRTCResetReinjection(mon); +} diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index c3695f2487..4fd6f01701 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -790,6 +790,8 @@ int qemuMonitorGetGuestCPU(qemuMonitorPtr mon, virArch arch, virCPUDataPtr *data); +int qemuMonitorRTCResetReinjection(qemuMonitorPtr mon); + /** * When running two dd process and using <> redirection, we need a * shell that will not truncate files. These two strings serve that diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index a62c02f14c..538110c062 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -5851,3 +5851,24 @@ qemuMonitorJSONGetGuestCPU(qemuMonitorPtr mon, return -1; } } + +int +qemuMonitorJSONRTCResetReinjection(qemuMonitorPtr mon) +{ + int ret = -1; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + + if (!(cmd = qemuMonitorJSONMakeCommand("rtc-reset-reinjection", + NULL))) + return ret; + + ret = qemuMonitorJSONCommand(mon, cmd, &reply); + + if (ret == 0) + ret = qemuMonitorJSONCheckError(cmd, reply); + + virJSONValueFree(cmd); + virJSONValueFree(reply); + return ret; +} diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 5f6c846e7c..d8c9308c5d 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -437,4 +437,6 @@ int qemuMonitorJSONGetDeviceAliases(qemuMonitorPtr mon, int qemuMonitorJSONGetGuestCPU(qemuMonitorPtr mon, virArch arch, virCPUDataPtr *data); + +int qemuMonitorJSONRTCResetReinjection(qemuMonitorPtr mon); #endif /* QEMU_MONITOR_JSON_H */ diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c index baee80a7ac..e3fb4f75b1 100644 --- a/tests/qemumonitorjsontest.c +++ b/tests/qemumonitorjsontest.c @@ -2279,6 +2279,7 @@ mymain(void) DO_TEST_SIMPLE("inject-nmi", qemuMonitorJSONInjectNMI); DO_TEST_SIMPLE("system_wakeup", qemuMonitorJSONSystemWakeup); DO_TEST_SIMPLE("nbd-server-stop", qemuMonitorJSONNBDServerStop); + DO_TEST_SIMPLE("rtc-reset-reinjection", qemuMonitorJSONRTCResetReinjection); DO_TEST_GEN(qemuMonitorJSONSetLink); DO_TEST_GEN(qemuMonitorJSONBlockResize); DO_TEST_GEN(qemuMonitorJSONSetVNCPassword);