]> xenbits.xensource.com Git - people/liuw/libxenctrl-split/libvirt.git/commitdiff
qemu: Issue rtc-reset-reinjection command after guest-set-time
authorMichal Privoznik <mprivozn@redhat.com>
Wed, 13 Aug 2014 12:28:24 +0000 (14:28 +0200)
committerMichal Privoznik <mprivozn@redhat.com>
Wed, 20 Aug 2014 12:20:05 +0000 (14:20 +0200)
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@redhat.com>
src/qemu/qemu_capabilities.c
src/qemu/qemu_capabilities.h
src/qemu/qemu_driver.c
src/qemu/qemu_monitor.c
src/qemu/qemu_monitor.h
src/qemu/qemu_monitor_json.c
src/qemu/qemu_monitor_json.h
tests/qemumonitorjsontest.c

index 360cc67c0ed9a2b19fcb4f2087ff753af8ce8e39..b758b5a0d4ef2c6b2415036bc896bfdf191c4b72 100644 (file)
@@ -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[] = {
index 2911759b0e588d3ac9e3adb870659790322ef690..cbd3646c30a59af6b670dd73e1f220bb6cec279c 100644 (file)
@@ -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;
index 28a56a97fa132792e8f5f6e08ae3cf0864d10031..c4d40c2be4a7b6ffc7f1d7aa44d9923f8d08e4c4 100644 (file)
@@ -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;
 
index 3d9f87b63f0ebe34ee072a4e9c289d293a725bc1..d5ba08de976bb9cb80945600a31eed0abeb06044 100644 (file)
@@ -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);
+}
index c3695f248742b49ba486fd48cc976704c9155881..4fd6f01701bc830d8c7e2d2c29c7a6ceb98a55a6 100644 (file)
@@ -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
index a62c02f14cc7bed1f8c21ff79df3207492a555de..538110c062754f7ecfebebe90124618493b404a8 100644 (file)
@@ -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;
+}
index 5f6c846e7c2d3b7c87a9c7893a225de04f434526..d8c9308c5d29aaef4030324f941c69c2341be329 100644 (file)
@@ -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 */
index baee80a7ac0d4f01f31faf79a4d7324e830258b5..e3fb4f75b1ab49ea796c1cee6ebd30152090dfe0 100644 (file)
@@ -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);