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 <mprivozn(a)redhat.com>
---
Notes:
diff to v1:
-fixed command name in subject
-added testcase
src/qemu/qemu_driver.c | 10 ++++++++++
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 +
6 files changed, 69 insertions(+)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index b6219ba..bdfd155 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -16879,6 +16879,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 3d9f87b..77627bc 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 will
+ * 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 c3695f2..4fd6f01 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 a62c02f..538110c 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 5f6c846..d8c9308 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 baee80a..e3fb4f7 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);
--
1.8.5.5