[libvirt] [PATCH v2 01/31] qemu: Make QMP probing process reusable
Pavel Hrdina
phrdina at redhat.com
Thu Nov 24 13:54:48 UTC 2016
On Mon, Nov 21, 2016 at 12:20:57AM +0100, Jiri Denemark wrote:
> 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 at 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)
That *bool* is not necessary, function virQEMUCapsInitQMPCommandRun can return
simple *int* because qemuMonitorPtr is stored in *cmd*. So this function can
return -1 in case of fatal error. In case return is 0, following code can
easily depend on whether cmd->mon is set or not.
Otherwise this patch looks good, but I think that it would be better to send a
new version with the suggested change.
Pavel
> +{
> + 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
>
> --
> libvir-list mailing list
> libvir-list at redhat.com
> https://www.redhat.com/mailman/listinfo/libvir-list
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: Digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20161124/b34b9686/attachment-0001.sig>
More information about the libvir-list
mailing list