The code that runs a new QEMU process to be used for probing
capabilities is separated into four reusable functions so that any code
that wants to probe a QEMU process may just follow a few simple steps:
cmd = virQEMUCapsInitQMPCommandNew(...);
mon = virQEMUCapsInitQMPCommandRun(cmd, ...);
/* talk to the running QEMU process using its QMP monitor */
if (reprobeIsRequired) {
virQEMUCapsInitQMPCommandAbort(cmd, ...);
mon = virQEMUCapsInitQMPCommandRun(cmd, ...);
/* talk to the running QEMU process again */
}
virQEMUCapsInitQMPCommandFree(cmd);
Signed-off-by: Jiri Denemark <jdenemar(a)redhat.com>
---
src/qemu/qemu_capabilities.c | 259 +++++++++++++++++++++++++++++--------------
1 file changed, 174 insertions(+), 85 deletions(-)
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index cfd090c..5ae57be 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -4022,32 +4022,101 @@ virQEMUCapsInitQMPMonitor(virQEMUCapsPtr qemuCaps,
return ret;
}
-static int
-virQEMUCapsInitQMP(virQEMUCapsPtr qemuCaps,
- const char *libDir,
- uid_t runUid,
- gid_t runGid,
- char **qmperr)
-{
- int ret = -1;
- virCommandPtr cmd = NULL;
- qemuMonitorPtr mon = NULL;
- int status = 0;
+
+typedef struct _virQEMUCapsInitQMPCommand virQEMUCapsInitQMPCommand;
+typedef virQEMUCapsInitQMPCommand *virQEMUCapsInitQMPCommandPtr;
+struct _virQEMUCapsInitQMPCommand {
+ char *binary;
+ uid_t runUid;
+ gid_t runGid;
+ char **qmperr;
+ char *monarg;
+ char *monpath;
+ char *pidfile;
+ virCommandPtr cmd;
+ qemuMonitorPtr mon;
virDomainChrSourceDef config;
- char *monarg = NULL;
- char *monpath = NULL;
- char *pidfile = NULL;
- pid_t pid = 0;
- virDomainObjPtr vm = NULL;
- virDomainXMLOptionPtr xmlopt = NULL;
+ pid_t pid;
+ virDomainObjPtr vm;
+};
+
+
+static void
+virQEMUCapsInitQMPCommandAbort(virQEMUCapsInitQMPCommandPtr cmd)
+{
+ if (cmd->mon)
+ virObjectUnlock(cmd->mon);
+ qemuMonitorClose(cmd->mon);
+ cmd->mon = NULL;
+
+ virCommandAbort(cmd->cmd);
+ virCommandFree(cmd->cmd);
+ cmd->cmd = NULL;
+
+ if (cmd->monpath)
+ ignore_value(unlink(cmd->monpath));
+
+ virDomainObjEndAPI(&cmd->vm);
+
+ if (cmd->pid != 0) {
+ char ebuf[1024];
+
+ VIR_DEBUG("Killing QMP caps process %lld", (long long) cmd->pid);
+ if (virProcessKill(cmd->pid, SIGKILL) < 0 && errno != ESRCH)
+ VIR_ERROR(_("Failed to kill process %lld: %s"),
+ (long long) cmd->pid,
+ virStrerror(errno, ebuf, sizeof(ebuf)));
+
+ VIR_FREE(*cmd->qmperr);
+ }
+ if (cmd->pidfile)
+ unlink(cmd->pidfile);
+ cmd->pid = 0;
+}
+
+
+static void
+virQEMUCapsInitQMPCommandFree(virQEMUCapsInitQMPCommandPtr cmd)
+{
+ if (!cmd)
+ return;
+
+ virQEMUCapsInitQMPCommandAbort(cmd);
+ VIR_FREE(cmd->binary);
+ VIR_FREE(cmd->monpath);
+ VIR_FREE(cmd->monarg);
+ VIR_FREE(cmd->pidfile);
+ VIR_FREE(cmd);
+}
+
+
+static virQEMUCapsInitQMPCommandPtr
+virQEMUCapsInitQMPCommandNew(char *binary,
+ const char *libDir,
+ uid_t runUid,
+ gid_t runGid,
+ char **qmperr)
+{
+ virQEMUCapsInitQMPCommandPtr cmd = NULL;
+
+ if (VIR_ALLOC(cmd) < 0)
+ goto error;
+
+ if (VIR_STRDUP(cmd->binary, binary) < 0)
+ goto error;
+
+ cmd->runUid = runUid;
+ cmd->runGid = runGid;
+ cmd->qmperr = qmperr;
/* the ".sock" sufix is important to avoid a possible clash with a qemu
* domain called "capabilities"
*/
- if (virAsprintf(&monpath, "%s/%s", libDir,
"capabilities.monitor.sock") < 0)
- goto cleanup;
- if (virAsprintf(&monarg, "unix:%s,server,nowait", monpath) < 0)
- goto cleanup;
+ if (virAsprintf(&cmd->monpath, "%s/%s", libDir,
+ "capabilities.monitor.sock") < 0)
+ goto error;
+ if (virAsprintf(&cmd->monarg, "unix:%s,server,nowait",
cmd->monpath) < 0)
+ goto error;
/* ".pidfile" suffix is used rather than ".pid" to avoid a
possible clash
* with a qemu domain called "capabilities"
@@ -4055,17 +4124,31 @@ virQEMUCapsInitQMP(virQEMUCapsPtr qemuCaps,
* -daemonize we need QEMU to be allowed to create them, rather
* than libvirtd. So we're using libDir which QEMU can write to
*/
- if (virAsprintf(&pidfile, "%s/%s", libDir,
"capabilities.pidfile") < 0)
- goto cleanup;
+ if (virAsprintf(&cmd->pidfile, "%s/%s", libDir,
"capabilities.pidfile") < 0)
+ goto error;
- memset(&config, 0, sizeof(config));
- config.type = VIR_DOMAIN_CHR_TYPE_UNIX;
- config.data.nix.path = monpath;
- config.data.nix.listen = false;
+ virPidFileForceCleanupPath(cmd->pidfile);
- virPidFileForceCleanupPath(pidfile);
+ cmd->config.type = VIR_DOMAIN_CHR_TYPE_UNIX;
+ cmd->config.data.nix.path = cmd->monpath;
+ cmd->config.data.nix.listen = false;
- VIR_DEBUG("Try to get caps via QMP qemuCaps=%p", qemuCaps);
+ return cmd;
+
+ error:
+ virQEMUCapsInitQMPCommandFree(cmd);
+ return NULL;
+}
+
+
+static qemuMonitorPtr
+virQEMUCapsInitQMPCommandRun(virQEMUCapsInitQMPCommandPtr cmd,
+ bool *qemuFailed)
+{
+ virDomainXMLOptionPtr xmlopt = NULL;
+ int status = 0;
+
+ VIR_DEBUG("Try to probe capabilities of '%s' via QMP",
cmd->binary);
/*
* We explicitly need to use -daemonize here, rather than
@@ -4074,86 +4157,92 @@ virQEMUCapsInitQMP(virQEMUCapsPtr qemuCaps,
* daemonize guarantees control won't return to libvirt
* until the socket is present.
*/
- cmd = virCommandNewArgList(qemuCaps->binary,
- "-S",
- "-no-user-config",
- "-nodefaults",
- "-nographic",
- "-M", "none",
- "-qmp", monarg,
- "-pidfile", pidfile,
- "-daemonize",
- NULL);
- virCommandAddEnvPassCommon(cmd);
- virCommandClearCaps(cmd);
- virCommandSetGID(cmd, runGid);
- virCommandSetUID(cmd, runUid);
+ cmd->cmd = virCommandNewArgList(cmd->binary,
+ "-S",
+ "-no-user-config",
+ "-nodefaults",
+ "-nographic",
+ "-M", "none",
+ "-qmp", cmd->monarg,
+ "-pidfile", cmd->pidfile,
+ "-daemonize",
+ NULL);
+ virCommandAddEnvPassCommon(cmd->cmd);
+ virCommandClearCaps(cmd->cmd);
+ virCommandSetGID(cmd->cmd, cmd->runGid);
+ virCommandSetUID(cmd->cmd, cmd->runUid);
- virCommandSetErrorBuffer(cmd, qmperr);
+ virCommandSetErrorBuffer(cmd->cmd, cmd->qmperr);
/* Log, but otherwise ignore, non-zero status. */
- if (virCommandRun(cmd, &status) < 0)
+ if (virCommandRun(cmd->cmd, &status) < 0)
goto cleanup;
if (status != 0) {
- ret = 0;
VIR_DEBUG("QEMU %s exited with status %d: %s",
- qemuCaps->binary, status, *qmperr);
- goto cleanup;
+ cmd->binary, status, *cmd->qmperr);
+ goto ignore;
}
- if (virPidFileReadPath(pidfile, &pid) < 0) {
- VIR_DEBUG("Failed to read pidfile %s", pidfile);
- ret = 0;
- goto cleanup;
+ if (virPidFileReadPath(cmd->pidfile, &cmd->pid) < 0) {
+ VIR_DEBUG("Failed to read pidfile %s", cmd->pidfile);
+ goto ignore;
}
if (!(xmlopt = virDomainXMLOptionNew(NULL, NULL, NULL)) ||
- !(vm = virDomainObjNew(xmlopt)))
+ !(cmd->vm = virDomainObjNew(xmlopt)))
goto cleanup;
- vm->pid = pid;
+ cmd->vm->pid = cmd->pid;
- if (!(mon = qemuMonitorOpen(vm, &config, true, &callbacks, NULL))) {
- ret = 0;
+ if (!(cmd->mon = qemuMonitorOpen(cmd->vm, &cmd->config, true,
+ &callbacks, NULL)))
+ goto ignore;
+
+ virObjectLock(cmd->mon);
+
+ cleanup:
+ if (!cmd->mon)
+ virQEMUCapsInitQMPCommandAbort(cmd);
+ virObjectUnref(xmlopt);
+
+ return cmd->mon;
+
+ ignore:
+ *qemuFailed = true;
+ goto cleanup;
+}
+
+
+static int
+virQEMUCapsInitQMP(virQEMUCapsPtr qemuCaps,
+ const char *libDir,
+ uid_t runUid,
+ gid_t runGid,
+ char **qmperr)
+{
+ virQEMUCapsInitQMPCommandPtr cmd = NULL;
+ qemuMonitorPtr mon = NULL;
+ bool qemuFailed = false;
+ int ret = -1;
+
+ if (!(cmd = virQEMUCapsInitQMPCommandNew(qemuCaps->binary, libDir,
+ runUid, runGid, qmperr)))
+ goto cleanup;
+
+ if (!(mon = virQEMUCapsInitQMPCommandRun(cmd, &qemuFailed))) {
+ if (qemuFailed)
+ ret = 0;
goto cleanup;
}
- virObjectLock(mon);
-
if (virQEMUCapsInitQMPMonitor(qemuCaps, mon) < 0)
goto cleanup;
ret = 0;
cleanup:
- if (mon)
- virObjectUnlock(mon);
- qemuMonitorClose(mon);
- virCommandAbort(cmd);
- virCommandFree(cmd);
- VIR_FREE(monarg);
- if (monpath)
- ignore_value(unlink(monpath));
- VIR_FREE(monpath);
- virDomainObjEndAPI(&vm);
- virObjectUnref(xmlopt);
-
- if (pid != 0) {
- char ebuf[1024];
-
- VIR_DEBUG("Killing QMP caps process %lld", (long long) pid);
- if (virProcessKill(pid, SIGKILL) < 0 && errno != ESRCH)
- VIR_ERROR(_("Failed to kill process %lld: %s"),
- (long long) pid,
- virStrerror(errno, ebuf, sizeof(ebuf)));
-
- VIR_FREE(*qmperr);
- }
- if (pidfile) {
- unlink(pidfile);
- VIR_FREE(pidfile);
- }
+ virQEMUCapsInitQMPCommandFree(cmd);
return ret;
}
--
2.10.2