[PATCH 0/6] qemu: Remove monitor socket waiting code

We either pre-open a socket and pass the file descriptor to qemu or are guaranteed that the socket is open by other means. The qemu monitor code can be simplified a lot. Peter Krempa (6): qemu: process: Remove 'retry' argument from qemuConnectMonitor qemu: monitor: Remove 'timeout' argument from qemuMonitorOpen qemuMonitorTestNew: Call qemuMonitorOpen with 'retry' false qemuProcessQMPConnectMonitor: Connect to probing monitor with 'retry' set to false qemuMonitorOpenUnix: Remove 'retry' argument qemuMonitorOpenUnix: Don't overwrite 'ret' needlessly src/qemu/qemu_monitor.c | 59 +++++------------------------------- src/qemu/qemu_monitor.h | 4 +-- src/qemu/qemu_process.c | 24 +++------------ tests/qemumonitortestutils.c | 2 -- 4 files changed, 13 insertions(+), 76 deletions(-) -- 2.36.1

Both callers pass 'false' as the argument via a variable which is not modified. Remove the argument and pass 'false' directly. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_process.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 137dcf5cf4..42a5b3f643 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -1883,7 +1883,6 @@ static int qemuConnectMonitor(virQEMUDriver *driver, virDomainObj *vm, int asyncJob, - bool retry, qemuDomainLogContext *logCtxt, bool reconnect) { @@ -1907,7 +1906,7 @@ qemuConnectMonitor(virQEMUDriver *driver, mon = qemuMonitorOpen(vm, priv->monConfig, - retry, + false, timeout, virEventThreadGetContext(priv->eventThread), &monitorCallbacks); @@ -2345,12 +2344,10 @@ qemuProcessWaitForMonitor(virQEMUDriver *driver, int ret = -1; g_autoptr(GHashTable) info = NULL; qemuDomainObjPrivate *priv = vm->privateData; - bool retry = false; - VIR_DEBUG("Connect monitor to vm=%p name='%s' retry=%d", - vm, vm->def->name, retry); + VIR_DEBUG("Connect monitor to vm=%p name='%s'", vm, vm->def->name); - if (qemuConnectMonitor(driver, vm, asyncJob, retry, logCtxt, false) < 0) + if (qemuConnectMonitor(driver, vm, asyncJob, logCtxt, false) < 0) goto cleanup; /* Try to get the pty path mappings again via the monitor. This is much more @@ -8877,7 +8874,6 @@ qemuProcessReconnect(void *opaque) size_t i; unsigned int stopFlags = 0; bool jobStarted = false; - bool retry = false; bool tryMonReconn = false; virIdentitySetCurrent(data->identity); @@ -8916,13 +8912,12 @@ qemuProcessReconnect(void *opaque) if (qemuDomainObjStartWorker(obj) < 0) goto error; - VIR_DEBUG("Reconnect monitor to def=%p name='%s' retry=%d", - obj, obj->def->name, retry); + VIR_DEBUG("Reconnect monitor to def=%p name='%s'", obj, obj->def->name); tryMonReconn = true; /* XXX check PID liveliness & EXE path */ - if (qemuConnectMonitor(driver, obj, VIR_ASYNC_JOB_NONE, retry, NULL, true) < 0) + if (qemuConnectMonitor(driver, obj, VIR_ASYNC_JOB_NONE, NULL, true) < 0) goto error; priv->machineName = qemuDomainGetMachineName(obj); -- 2.36.1

The 'timeout' argument is used by 'qemuMonitorOpenUnix' only when the 'retry' argument is true. The callers of 'qemuMonitorOpen' only pass '0' for timeout when they call it with 'retry' true and use other values when 'retry' is false and thus ignored. This means we can remove the argument and simply have it set to the default value of QEMU_DEFAULT_MONITOR_WAIT. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_monitor.c | 21 +++++---------------- src/qemu/qemu_monitor.h | 3 +-- src/qemu/qemu_process.c | 10 +--------- tests/qemumonitortestutils.c | 1 - 4 files changed, 7 insertions(+), 28 deletions(-) diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 6ebdeb46f3..91e9f76944 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -223,12 +223,12 @@ qemuMonitorDispose(void *obj) g_free(mon->domainName); } +#define QEMU_DEFAULT_MONITOR_WAIT 30 static int qemuMonitorOpenUnix(const char *monitor, pid_t cpid, - bool retry, - unsigned long long timeout) + bool retry) { struct sockaddr_un addr; VIR_AUTOCLOSE monfd = -1; @@ -250,7 +250,7 @@ qemuMonitorOpenUnix(const char *monitor, } if (retry) { - if (virTimeBackOffStart(&timebackoff, 1, timeout * 1000) < 0) + if (virTimeBackOffStart(&timebackoff, 1, QEMU_DEFAULT_MONITOR_WAIT * 1000) < 0) return -1; while (virTimeBackOffWait(&timebackoff)) { ret = connect(monfd, (struct sockaddr *)&addr, sizeof(addr)); @@ -694,20 +694,13 @@ qemuMonitorOpenInternal(virDomainObj *vm, } -#define QEMU_DEFAULT_MONITOR_WAIT 30 - /** * qemuMonitorOpen: * @vm: domain object * @config: monitor configuration - * @timeout: number of seconds to add to default timeout * @cb: monitor event handles * - * 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. + * Opens the monitor for running qemu. * * Returns monitor object, NULL on error. */ @@ -715,15 +708,12 @@ qemuMonitor * qemuMonitorOpen(virDomainObj *vm, virDomainChrSourceDef *config, bool retry, - unsigned long long timeout, GMainContext *context, qemuMonitorCallbacks *cb) { VIR_AUTOCLOSE fd = -1; qemuMonitor *ret = NULL; - timeout += QEMU_DEFAULT_MONITOR_WAIT; - if (config->type != VIR_DOMAIN_CHR_TYPE_UNIX) { virReportError(VIR_ERR_INTERNAL_ERROR, _("unable to handle monitor type: %s"), @@ -732,8 +722,7 @@ qemuMonitorOpen(virDomainObj *vm, } virObjectUnlock(vm); - fd = qemuMonitorOpenUnix(config->data.nix.path, - vm->pid, retry, timeout); + fd = qemuMonitorOpenUnix(config->data.nix.path, vm->pid, retry); virObjectLock(vm); if (fd < 0) diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index b82f198285..2ef9118b84 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -409,10 +409,9 @@ struct _qemuMonitorCallbacks { qemuMonitor *qemuMonitorOpen(virDomainObj *vm, virDomainChrSourceDef *config, bool retry, - unsigned long long timeout, GMainContext *context, qemuMonitorCallbacks *cb) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(5); + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(4); void qemuMonitorWatchDispose(void); bool qemuMonitorWasDisposed(void); diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 42a5b3f643..1cd55fe989 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -1888,7 +1888,6 @@ qemuConnectMonitor(virQEMUDriver *driver, { qemuDomainObjPrivate *priv = vm->privateData; qemuMonitor *mon = NULL; - unsigned long long timeout = 0; if (qemuSecuritySetDaemonSocketLabel(driver->securityManager, vm->def) < 0) { VIR_ERROR(_("Failed to set security context for monitor for %s"), @@ -1896,18 +1895,11 @@ qemuConnectMonitor(virQEMUDriver *driver, 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 = virDomainDefGetMemoryTotal(vm->def) / (1024 * 1024); - ignore_value(virTimeMillisNow(&priv->monStart)); mon = qemuMonitorOpen(vm, priv->monConfig, false, - timeout, virEventThreadGetContext(priv->eventThread), &monitorCallbacks); @@ -9501,7 +9493,7 @@ qemuProcessQMPConnectMonitor(qemuProcessQMP *proc) proc->vm->pid = proc->pid; - if (!(proc->mon = qemuMonitorOpen(proc->vm, &monConfig, true, 0, + if (!(proc->mon = qemuMonitorOpen(proc->vm, &monConfig, true, virEventThreadGetContext(proc->eventThread), &callbacks))) return -1; diff --git a/tests/qemumonitortestutils.c b/tests/qemumonitortestutils.c index a5d716deee..50808f1fb5 100644 --- a/tests/qemumonitortestutils.c +++ b/tests/qemumonitortestutils.c @@ -1110,7 +1110,6 @@ qemuMonitorTestNew(virDomainXMLOption *xmlopt, if (!(test->mon = qemuMonitorOpen(test->vm, &src, true, - 0, virEventThreadGetContext(test->eventThread), &qemuMonitorTestCallbacks))) goto error; -- 2.36.1

The 'retry' argument makes the monitor connection opening re-try the connection in case the monitor socket doesn't exist or isn't properly listening. In case of the test code this can't happen because the socket is created and made listening in 'qemuMonitorCommonTestNew' which is called prior to calling 'qemuMonitorOpen'. We can thus avoit the code which attempts retries in monitor connection. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- tests/qemumonitortestutils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/qemumonitortestutils.c b/tests/qemumonitortestutils.c index 50808f1fb5..1ea8d72711 100644 --- a/tests/qemumonitortestutils.c +++ b/tests/qemumonitortestutils.c @@ -1109,7 +1109,7 @@ qemuMonitorTestNew(virDomainXMLOption *xmlopt, test->qapischema = schema; if (!(test->mon = qemuMonitorOpen(test->vm, &src, - true, + false, virEventThreadGetContext(test->eventThread), &qemuMonitorTestCallbacks))) goto error; -- 2.36.1

In 'qemuProcessQMPLaunch' qemu is very specifically launched using it's internal '-daemonize' flag (see comment in the function) to ensure that the monitor socket is ready and opened prior to attempting the monitor connection. This means we don't have to retry the connection to the monitor in qemuMonitorOpen as the socket will be already there. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_process.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 1cd55fe989..c51d704af8 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -9493,7 +9493,7 @@ qemuProcessQMPConnectMonitor(qemuProcessQMP *proc) proc->vm->pid = proc->pid; - if (!(proc->mon = qemuMonitorOpen(proc->vm, &monConfig, true, + if (!(proc->mon = qemuMonitorOpen(proc->vm, &monConfig, false, virEventThreadGetContext(proc->eventThread), &callbacks))) return -1; -- 2.36.1

All callers now pass false for 'retry' we are guaranteed to have a monitor socket present. This means that the retry code can be removed. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_monitor.c | 47 ++++++------------------------------ src/qemu/qemu_monitor.h | 1 - src/qemu/qemu_process.c | 3 +-- tests/qemumonitortestutils.c | 1 - 4 files changed, 8 insertions(+), 44 deletions(-) diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 91e9f76944..ad5e121359 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -223,16 +223,12 @@ qemuMonitorDispose(void *obj) g_free(mon->domainName); } -#define QEMU_DEFAULT_MONITOR_WAIT 30 static int -qemuMonitorOpenUnix(const char *monitor, - pid_t cpid, - bool retry) +qemuMonitorOpenUnix(const char *monitor) { struct sockaddr_un addr; VIR_AUTOCLOSE monfd = -1; - virTimeBackOffVar timebackoff; int ret = -1; if ((monfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { @@ -249,39 +245,11 @@ qemuMonitorOpenUnix(const char *monitor, return -1; } - if (retry) { - if (virTimeBackOffStart(&timebackoff, 1, QEMU_DEFAULT_MONITOR_WAIT * 1000) < 0) - return -1; - while (virTimeBackOffWait(&timebackoff)) { - ret = connect(monfd, (struct sockaddr *)&addr, sizeof(addr)); - - if (ret == 0) - break; - - if ((errno == ENOENT || errno == ECONNREFUSED) && - (!cpid || virProcessKill(cpid, 0) == 0)) { - /* ENOENT : Socket may not have shown up yet - * ECONNREFUSED : Leftover socket hasn't been removed yet */ - continue; - } - - virReportSystemError(errno, "%s", - _("failed to connect to monitor socket")); - return -1; - } - - if (ret != 0) { - virReportSystemError(errno, "%s", - _("monitor socket did not show up")); - return -1; - } - } else { - ret = connect(monfd, (struct sockaddr *) &addr, sizeof(addr)); - if (ret < 0) { - virReportSystemError(errno, "%s", - _("failed to connect to monitor socket")); - return -1; - } + ret = connect(monfd, (struct sockaddr *) &addr, sizeof(addr)); + if (ret < 0) { + virReportSystemError(errno, "%s", + _("failed to connect to monitor socket")); + return -1; } ret = monfd; @@ -707,7 +675,6 @@ qemuMonitorOpenInternal(virDomainObj *vm, qemuMonitor * qemuMonitorOpen(virDomainObj *vm, virDomainChrSourceDef *config, - bool retry, GMainContext *context, qemuMonitorCallbacks *cb) { @@ -722,7 +689,7 @@ qemuMonitorOpen(virDomainObj *vm, } virObjectUnlock(vm); - fd = qemuMonitorOpenUnix(config->data.nix.path, vm->pid, retry); + fd = qemuMonitorOpenUnix(config->data.nix.path); virObjectLock(vm); if (fd < 0) diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 2ef9118b84..742bfd4cdc 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -408,7 +408,6 @@ struct _qemuMonitorCallbacks { qemuMonitor *qemuMonitorOpen(virDomainObj *vm, virDomainChrSourceDef *config, - bool retry, GMainContext *context, qemuMonitorCallbacks *cb) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(4); diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index c51d704af8..d29da63242 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -1899,7 +1899,6 @@ qemuConnectMonitor(virQEMUDriver *driver, mon = qemuMonitorOpen(vm, priv->monConfig, - false, virEventThreadGetContext(priv->eventThread), &monitorCallbacks); @@ -9493,7 +9492,7 @@ qemuProcessQMPConnectMonitor(qemuProcessQMP *proc) proc->vm->pid = proc->pid; - if (!(proc->mon = qemuMonitorOpen(proc->vm, &monConfig, false, + if (!(proc->mon = qemuMonitorOpen(proc->vm, &monConfig, virEventThreadGetContext(proc->eventThread), &callbacks))) return -1; diff --git a/tests/qemumonitortestutils.c b/tests/qemumonitortestutils.c index 1ea8d72711..db0f450e40 100644 --- a/tests/qemumonitortestutils.c +++ b/tests/qemumonitortestutils.c @@ -1109,7 +1109,6 @@ qemuMonitorTestNew(virDomainXMLOption *xmlopt, test->qapischema = schema; if (!(test->mon = qemuMonitorOpen(test->vm, &src, - false, virEventThreadGetContext(test->eventThread), &qemuMonitorTestCallbacks))) goto error; -- 2.36.1

Directly check the return value of 'connect'. Unfortunately we can't remove it as we have to undo auto-closing of the socket on success. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_monitor.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index ad5e121359..0c0b07d4a5 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -245,8 +245,7 @@ qemuMonitorOpenUnix(const char *monitor) return -1; } - ret = connect(monfd, (struct sockaddr *) &addr, sizeof(addr)); - if (ret < 0) { + if (connect(monfd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { virReportSystemError(errno, "%s", _("failed to connect to monitor socket")); return -1; -- 2.36.1

On 8/2/22 7:51 AM, Peter Krempa wrote:
We either pre-open a socket and pass the file descriptor to qemu or are guaranteed that the socket is open by other means.
The qemu monitor code can be simplified a lot.
Peter Krempa (6): qemu: process: Remove 'retry' argument from qemuConnectMonitor qemu: monitor: Remove 'timeout' argument from qemuMonitorOpen qemuMonitorTestNew: Call qemuMonitorOpen with 'retry' false qemuProcessQMPConnectMonitor: Connect to probing monitor with 'retry' set to false qemuMonitorOpenUnix: Remove 'retry' argument qemuMonitorOpenUnix: Don't overwrite 'ret' needlessly
src/qemu/qemu_monitor.c | 59 +++++------------------------------- src/qemu/qemu_monitor.h | 4 +-- src/qemu/qemu_process.c | 24 +++------------ tests/qemumonitortestutils.c | 2 -- 4 files changed, 13 insertions(+), 76 deletions(-)
Series looks good to me. Reviewed-by: Jonathon Jongsma <jjongsma@redhat.com>
participants (2)
-
Jonathon Jongsma
-
Peter Krempa