mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-09-09 09:14:57 +00:00
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:
parent
970ac2a0fe
commit
b606bbb416
@ -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[] = {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user