提交 85af0b80 编写于 作者: M Michal Privoznik

qemu: Adaptive timeout for connecting to monitor

There were couple of reports on the list (e.g. [1]) that guests
with huge amounts of RAM are unable to start because libvirt
kills qemu in the initialization phase. The problem is that if
guest is configured to use hugepages kernel has to zero them all
out before handing over to qemu process. For instance, 402GiB
worth of 1GiB pages took around 105 seconds (~3.8GiB/s). Since we
do not want to make the timeout for connecting to monitor
configurable, we have to teach libvirt to count with this
fact. This commit implements "1s per each 1GiB of RAM" approach
as suggested here [2].

1: https://www.redhat.com/archives/libvir-list/2017-March/msg00373.html
2: https://www.redhat.com/archives/libvir-list/2017-March/msg00405.htmlSigned-off-by: NMichal Privoznik <mprivozn@redhat.com>
上级 67dcb797
...@@ -4767,7 +4767,7 @@ virQEMUCapsInitQMPCommandRun(virQEMUCapsInitQMPCommandPtr cmd, ...@@ -4767,7 +4767,7 @@ virQEMUCapsInitQMPCommandRun(virQEMUCapsInitQMPCommandPtr cmd,
cmd->vm->pid = cmd->pid; cmd->vm->pid = cmd->pid;
if (!(cmd->mon = qemuMonitorOpen(cmd->vm, &cmd->config, true, if (!(cmd->mon = qemuMonitorOpen(cmd->vm, &cmd->config, true,
&callbacks, NULL))) 0, &callbacks, NULL)))
goto ignore; goto ignore;
virObjectLock(cmd->mon); virObjectLock(cmd->mon);
......
...@@ -327,11 +327,13 @@ qemuMonitorDispose(void *obj) ...@@ -327,11 +327,13 @@ qemuMonitorDispose(void *obj)
static int static int
qemuMonitorOpenUnix(const char *monitor, pid_t cpid) qemuMonitorOpenUnix(const char *monitor,
pid_t cpid,
unsigned long long timeout)
{ {
struct sockaddr_un addr; struct sockaddr_un addr;
int monfd; int monfd;
virTimeBackOffVar timeout; virTimeBackOffVar timebackoff;
int ret = -1; int ret = -1;
if ((monfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { if ((monfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
...@@ -348,9 +350,9 @@ qemuMonitorOpenUnix(const char *monitor, pid_t cpid) ...@@ -348,9 +350,9 @@ qemuMonitorOpenUnix(const char *monitor, pid_t cpid)
goto error; goto error;
} }
if (virTimeBackOffStart(&timeout, 1, 30*1000 /* ms */) < 0) if (virTimeBackOffStart(&timebackoff, 1, timeout * 1000) < 0)
goto error; goto error;
while (virTimeBackOffWait(&timeout)) { while (virTimeBackOffWait(&timebackoff)) {
ret = connect(monfd, (struct sockaddr *) &addr, sizeof(addr)); ret = connect(monfd, (struct sockaddr *) &addr, sizeof(addr));
if (ret == 0) if (ret == 0)
...@@ -871,10 +873,30 @@ qemuMonitorOpenInternal(virDomainObjPtr vm, ...@@ -871,10 +873,30 @@ qemuMonitorOpenInternal(virDomainObjPtr vm,
} }
#define QEMU_DEFAULT_MONITOR_WAIT 30
/**
* qemuMonitorOpen:
* @vm: domain object
* @config: monitor configuration
* @json: enable JSON on the monitor
* @timeout: number of seconds to add to default timeout
* @cb: monitor event handles
* @opaque: opaque data for @cb
*
* Opens the monitor for running qemu. It may happen that it
* takes some time for qemu to create the monitor socket (e.g.
* because kernel is zeroing configured hugepages), therefore we
* wait up to default + timeout seconds for the monitor to show
* up after which a failure is claimed.
*
* Returns monitor object, NULL on error.
*/
qemuMonitorPtr qemuMonitorPtr
qemuMonitorOpen(virDomainObjPtr vm, qemuMonitorOpen(virDomainObjPtr vm,
virDomainChrSourceDefPtr config, virDomainChrSourceDefPtr config,
bool json, bool json,
unsigned long long timeout,
qemuMonitorCallbacksPtr cb, qemuMonitorCallbacksPtr cb,
void *opaque) void *opaque)
{ {
...@@ -882,10 +904,14 @@ qemuMonitorOpen(virDomainObjPtr vm, ...@@ -882,10 +904,14 @@ qemuMonitorOpen(virDomainObjPtr vm,
bool hasSendFD = false; bool hasSendFD = false;
qemuMonitorPtr ret; qemuMonitorPtr ret;
timeout += QEMU_DEFAULT_MONITOR_WAIT;
switch (config->type) { switch (config->type) {
case VIR_DOMAIN_CHR_TYPE_UNIX: case VIR_DOMAIN_CHR_TYPE_UNIX:
hasSendFD = true; hasSendFD = true;
if ((fd = qemuMonitorOpenUnix(config->data.nix.path, vm ? vm->pid : 0)) < 0) if ((fd = qemuMonitorOpenUnix(config->data.nix.path,
vm ? vm->pid : 0,
timeout)) < 0)
return NULL; return NULL;
break; break;
......
...@@ -246,6 +246,7 @@ char *qemuMonitorUnescapeArg(const char *in); ...@@ -246,6 +246,7 @@ char *qemuMonitorUnescapeArg(const char *in);
qemuMonitorPtr qemuMonitorOpen(virDomainObjPtr vm, qemuMonitorPtr qemuMonitorOpen(virDomainObjPtr vm,
virDomainChrSourceDefPtr config, virDomainChrSourceDefPtr config,
bool json, bool json,
unsigned long long timeout,
qemuMonitorCallbacksPtr cb, qemuMonitorCallbacksPtr cb,
void *opaque) void *opaque)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(4); ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(4);
......
...@@ -1658,6 +1658,7 @@ qemuConnectMonitor(virQEMUDriverPtr driver, virDomainObjPtr vm, int asyncJob, ...@@ -1658,6 +1658,7 @@ qemuConnectMonitor(virQEMUDriverPtr driver, virDomainObjPtr vm, int asyncJob,
qemuDomainObjPrivatePtr priv = vm->privateData; qemuDomainObjPrivatePtr priv = vm->privateData;
int ret = -1; int ret = -1;
qemuMonitorPtr mon = NULL; qemuMonitorPtr mon = NULL;
unsigned long long timeout = 0;
if (qemuSecuritySetDaemonSocketLabel(driver->securityManager, vm->def) < 0) { if (qemuSecuritySetDaemonSocketLabel(driver->securityManager, vm->def) < 0) {
VIR_ERROR(_("Failed to set security context for monitor for %s"), VIR_ERROR(_("Failed to set security context for monitor for %s"),
...@@ -1665,6 +1666,12 @@ qemuConnectMonitor(virQEMUDriverPtr driver, virDomainObjPtr vm, int asyncJob, ...@@ -1665,6 +1666,12 @@ qemuConnectMonitor(virQEMUDriverPtr driver, virDomainObjPtr vm, int asyncJob,
return -1; return -1;
} }
/* When using hugepages, kernel zeroes them out before
* handing them over to qemu. This can be very time
* consuming. Therefore, add a second to timeout for each
* 1GiB of guest RAM. */
timeout = vm->def->mem.total_memory / (1024 * 1024);
/* Hold an extra reference because we can't allow 'vm' to be /* Hold an extra reference because we can't allow 'vm' to be
* deleted until the monitor gets its own reference. */ * deleted until the monitor gets its own reference. */
virObjectRef(vm); virObjectRef(vm);
...@@ -1675,6 +1682,7 @@ qemuConnectMonitor(virQEMUDriverPtr driver, virDomainObjPtr vm, int asyncJob, ...@@ -1675,6 +1682,7 @@ qemuConnectMonitor(virQEMUDriverPtr driver, virDomainObjPtr vm, int asyncJob,
mon = qemuMonitorOpen(vm, mon = qemuMonitorOpen(vm,
priv->monConfig, priv->monConfig,
priv->monJSON, priv->monJSON,
timeout,
&monitorCallbacks, &monitorCallbacks,
driver); driver);
......
...@@ -1175,6 +1175,7 @@ qemuMonitorTestNew(bool json, ...@@ -1175,6 +1175,7 @@ qemuMonitorTestNew(bool json,
if (!(test->mon = qemuMonitorOpen(test->vm, if (!(test->mon = qemuMonitorOpen(test->vm,
&src, &src,
json, json,
0,
&qemuMonitorTestCallbacks, &qemuMonitorTestCallbacks,
driver))) driver)))
goto error; goto error;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册