From b606bbb416e264466a3f5af62a13163e432d0f49 Mon Sep 17 00:00:00 2001 From: Michal Privoznik Date: Wed, 13 Aug 2014 14:28:24 +0200 Subject: [PATCH] qemu: Issue rtc-reset-reinjection command after guest-set-time https://bugzilla.redhat.com/show_bug.cgi?id=1103245 An advice appeared there on the qemu-devel list [1]. When a domain is suspended and then resumed guest kernel is not aware of this. So we've introduced virDomainSetTime API that resets the time within guest using qemu-ga. On the other hand, qemu itself is trying to make RTC beat faster to catch the difference. But if we don't tell qemu that guest's time was reset via the other method, both mechanisms are applied resulting in again wrong guest time. In order to avoid summing both corrections we need to tell qemu that it should not use the RTC injection if the guest time is set via guest agent. 1: http://www.mail-archive.com/qemu-devel@nongnu.org/msg236435.html Signed-off-by: Michal Privoznik --- src/qemu/qemu_capabilities.c | 2 ++ src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_driver.c | 17 +++++++++++++++++ src/qemu/qemu_monitor.c | 33 +++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor.h | 2 ++ src/qemu/qemu_monitor_json.c | 21 +++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 2 ++ tests/qemumonitorjsontest.c | 1 + 8 files changed, 79 insertions(+) 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); -- GitLab