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 <mprivozn@redhat.com>
This commit is contained in:
Michal Privoznik 2014-08-13 14:28:24 +02:00
parent 970ac2a0fe
commit b606bbb416
8 changed files with 79 additions and 0 deletions

View 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[] = {

View 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;

View 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;

View 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);
}

View 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

View 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;
}

View 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 */

View 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);