mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-03-20 06:50:22 +03:00
qemu: Implement virDomain{Get,Set}Time
One caveat though, qemu-ga is expecting time and returning time in nanoseconds. With all the buffering and propagation delay, the time is already wrong once it gets to the qemu-ga, but there's nothing we can do about it. Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
This commit is contained in:
parent
222fdbfd2b
commit
6f9c75a6f7
@ -1685,3 +1685,96 @@ qemuAgentUpdateCPUInfo(unsigned int nvcpus,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
qemuAgentGetTime(qemuAgentPtr mon,
|
||||
long long *seconds,
|
||||
unsigned int *nseconds)
|
||||
{
|
||||
int ret = -1;
|
||||
unsigned long long json_time;
|
||||
virJSONValuePtr cmd;
|
||||
virJSONValuePtr reply = NULL;
|
||||
|
||||
cmd = qemuAgentMakeCommand("guest-get-time",
|
||||
NULL);
|
||||
if (!cmd)
|
||||
return ret;
|
||||
|
||||
if (qemuAgentCommand(mon, cmd, &reply, true,
|
||||
VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (virJSONValueObjectGetNumberUlong(reply, "return", &json_time) < 0) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("malformed return value"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* guest agent returns time in nanoseconds,
|
||||
* we need it in seconds here */
|
||||
*seconds = json_time / 1000000000LL;
|
||||
*nseconds = json_time % 1000000000LL;
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
virJSONValueFree(cmd);
|
||||
virJSONValueFree(reply);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* qemuAgentSetTime:
|
||||
* @setTime: time to set
|
||||
* @sync: let guest agent to read domain's RTC (@setTime is ignored)
|
||||
*/
|
||||
int
|
||||
qemuAgentSetTime(qemuAgentPtr mon,
|
||||
long long seconds,
|
||||
unsigned int nseconds,
|
||||
bool sync)
|
||||
{
|
||||
int ret = -1;
|
||||
virJSONValuePtr cmd;
|
||||
virJSONValuePtr reply = NULL;
|
||||
|
||||
if (sync) {
|
||||
cmd = qemuAgentMakeCommand("guest-set-time", NULL);
|
||||
} else {
|
||||
/* guest agent expect time with nanosecond granularity.
|
||||
* Impressing. */
|
||||
long long json_time;
|
||||
|
||||
/* Check if we overflow. For some reason qemu doesn't handle unsigned
|
||||
* long long on the monitor well as it silently truncates numbers to
|
||||
* signed long long. Therefore we must check overflow against LLONG_MAX
|
||||
* not ULLONG_MAX. */
|
||||
if (seconds > LLONG_MAX / 1000000000LL) {
|
||||
virReportError(VIR_ERR_INVALID_ARG,
|
||||
_("Time '%lld' is too big for guest agent"),
|
||||
seconds);
|
||||
return ret;
|
||||
}
|
||||
|
||||
json_time = seconds * 1000000000LL;
|
||||
json_time += nseconds;
|
||||
cmd = qemuAgentMakeCommand("guest-set-time",
|
||||
"I:time", json_time,
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (!cmd)
|
||||
return ret;
|
||||
|
||||
if (qemuAgentCommand(mon, cmd, &reply, true,
|
||||
VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0)
|
||||
goto cleanup;
|
||||
|
||||
ret = 0;
|
||||
cleanup:
|
||||
virJSONValueFree(cmd);
|
||||
virJSONValueFree(reply);
|
||||
return ret;
|
||||
}
|
||||
|
@ -98,4 +98,12 @@ int qemuAgentSetVCPUs(qemuAgentPtr mon, qemuAgentCPUInfoPtr cpus, size_t ncpus);
|
||||
int qemuAgentUpdateCPUInfo(unsigned int nvcpus,
|
||||
qemuAgentCPUInfoPtr cpuinfo,
|
||||
int ncpuinfo);
|
||||
|
||||
int qemuAgentGetTime(qemuAgentPtr mon,
|
||||
long long *seconds,
|
||||
unsigned int *nseconds);
|
||||
int qemuAgentSetTime(qemuAgentPtr mon,
|
||||
long long seconds,
|
||||
unsigned int nseconds,
|
||||
bool sync);
|
||||
#endif /* __QEMU_AGENT_H__ */
|
||||
|
@ -16536,6 +16536,113 @@ qemuConnectGetCPUModelNames(virConnectPtr conn,
|
||||
return cpuGetModels(arch, models);
|
||||
}
|
||||
|
||||
static int
|
||||
qemuDomainGetTime(virDomainPtr dom,
|
||||
long long *seconds,
|
||||
unsigned int *nseconds,
|
||||
unsigned int flags)
|
||||
{
|
||||
virQEMUDriverPtr driver = dom->conn->privateData;
|
||||
virDomainObjPtr vm = NULL;
|
||||
qemuDomainObjPrivatePtr priv;
|
||||
int ret = -1;
|
||||
int rv;
|
||||
|
||||
virCheckFlags(0, ret);
|
||||
|
||||
if (!(vm = qemuDomObjFromDomain(dom)))
|
||||
return ret;
|
||||
|
||||
if (virDomainGetTimeEnsureACL(dom->conn, vm->def) < 0)
|
||||
goto cleanup;
|
||||
|
||||
priv = vm->privateData;
|
||||
|
||||
if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (!virDomainObjIsActive(vm)) {
|
||||
virReportError(VIR_ERR_OPERATION_INVALID,
|
||||
"%s", _("domain is not running"));
|
||||
goto endjob;
|
||||
}
|
||||
|
||||
if (!qemuDomainAgentAvailable(priv, true))
|
||||
goto endjob;
|
||||
|
||||
qemuDomainObjEnterAgent(vm);
|
||||
rv = qemuAgentGetTime(priv->agent, seconds, nseconds);
|
||||
qemuDomainObjExitAgent(vm);
|
||||
|
||||
if (rv < 0)
|
||||
goto endjob;
|
||||
|
||||
ret = 0;
|
||||
|
||||
endjob:
|
||||
if (!qemuDomainObjEndJob(driver, vm))
|
||||
vm = NULL;
|
||||
|
||||
cleanup:
|
||||
if (vm)
|
||||
virObjectUnlock(vm);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
qemuDomainSetTime(virDomainPtr dom,
|
||||
long long seconds,
|
||||
unsigned int nseconds,
|
||||
unsigned int flags)
|
||||
{
|
||||
virQEMUDriverPtr driver = dom->conn->privateData;
|
||||
qemuDomainObjPrivatePtr priv;
|
||||
virDomainObjPtr vm;
|
||||
bool sync = flags & VIR_DOMAIN_TIME_SYNC;
|
||||
int ret = -1;
|
||||
int rv;
|
||||
|
||||
virCheckFlags(VIR_DOMAIN_TIME_SYNC, ret);
|
||||
|
||||
if (!(vm = qemuDomObjFromDomain(dom)))
|
||||
return ret;
|
||||
|
||||
if (virDomainSetTimeEnsureACL(dom->conn, vm->def) < 0)
|
||||
goto cleanup;
|
||||
|
||||
priv = vm->privateData;
|
||||
|
||||
if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (!virDomainObjIsActive(vm)) {
|
||||
virReportError(VIR_ERR_OPERATION_INVALID,
|
||||
"%s", _("domain is not running"));
|
||||
goto endjob;
|
||||
}
|
||||
|
||||
if (!qemuDomainAgentAvailable(priv, true))
|
||||
goto endjob;
|
||||
|
||||
qemuDomainObjEnterAgent(vm);
|
||||
rv = qemuAgentSetTime(priv->agent, seconds, nseconds, sync);
|
||||
qemuDomainObjExitAgent(vm);
|
||||
|
||||
if (rv < 0)
|
||||
goto endjob;
|
||||
|
||||
ret = 0;
|
||||
|
||||
endjob:
|
||||
if (!qemuDomainObjEndJob(driver, vm))
|
||||
vm = NULL;
|
||||
|
||||
cleanup:
|
||||
if (vm)
|
||||
virObjectUnlock(vm);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qemuDomainFSFreeze(virDomainPtr dom,
|
||||
@ -16819,6 +16926,8 @@ static virDriver qemuDriver = {
|
||||
.connectGetCPUModelNames = qemuConnectGetCPUModelNames, /* 1.1.3 */
|
||||
.domainFSFreeze = qemuDomainFSFreeze, /* 1.2.5 */
|
||||
.domainFSThaw = qemuDomainFSThaw, /* 1.2.5 */
|
||||
.domainGetTime = qemuDomainGetTime, /* 1.2.5 */
|
||||
.domainSetTime = qemuDomainSetTime, /* 1.2.5 */
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user