mirror of https://gitee.com/openkylin/libvirt.git
qemu_process: Move process code from qemu_capabilities
QEMU process code in qemu_capabilities.c is moved to qemu_process.c in order to make the code usable outside the original capabilities use cases. The moved code activates and manages QEMU processes without establishing a guest domain. This patch is a straight cut/paste move between files. Signed-off-by: Chris Venteicher <cventeic@redhat.com> Reviewed-by: Jiri Denemark <jdenemar@redhat.com> Reviewed-by: Ján Tomko <jtomko@redhat.com>
This commit is contained in:
parent
e97d7733fe
commit
16058045d0
|
@ -45,6 +45,7 @@
|
|||
#define LIBVIRT_QEMU_CAPSPRIV_H_ALLOW
|
||||
#include "qemu_capspriv.h"
|
||||
#include "qemu_qapi.h"
|
||||
#include "qemu_process.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
@ -53,10 +54,6 @@
|
|||
#include <stdarg.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#if WITH_CAPNG
|
||||
# include <cap-ng.h>
|
||||
#endif
|
||||
|
||||
#define VIR_FROM_THIS VIR_FROM_QEMU
|
||||
|
||||
VIR_LOG_INIT("qemu.qemu_capabilities");
|
||||
|
@ -4049,18 +4046,6 @@ virQEMUCapsIsValid(void *data,
|
|||
}
|
||||
|
||||
|
||||
static void virQEMUCapsMonitorNotify(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
|
||||
virDomainObjPtr vm ATTRIBUTE_UNUSED,
|
||||
void *opaque ATTRIBUTE_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
static qemuMonitorCallbacks callbacks = {
|
||||
.eofNotify = virQEMUCapsMonitorNotify,
|
||||
.errorNotify = virQEMUCapsMonitorNotify,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* virQEMUCapsInitQMPArch:
|
||||
* @qemuCaps: QEMU capabilities
|
||||
|
@ -4369,219 +4354,6 @@ virQEMUCapsInitQMPMonitorTCG(virQEMUCapsPtr qemuCaps ATTRIBUTE_UNUSED,
|
|||
}
|
||||
|
||||
|
||||
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;
|
||||
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)
|
||||
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(&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"
|
||||
* Normally we'd use runDir for pid files, but because we're using
|
||||
* -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(&cmd->pidfile, "%s/%s", libDir, "capabilities.pidfile") < 0)
|
||||
goto error;
|
||||
|
||||
virPidFileForceCleanupPath(cmd->pidfile);
|
||||
|
||||
cmd->config.type = VIR_DOMAIN_CHR_TYPE_UNIX;
|
||||
cmd->config.data.nix.path = cmd->monpath;
|
||||
cmd->config.data.nix.listen = false;
|
||||
|
||||
return cmd;
|
||||
|
||||
error:
|
||||
virQEMUCapsInitQMPCommandFree(cmd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Returns -1 on fatal error,
|
||||
* 0 on success,
|
||||
* 1 when probing QEMU failed
|
||||
*/
|
||||
static int
|
||||
virQEMUCapsInitQMPCommandRun(virQEMUCapsInitQMPCommandPtr cmd,
|
||||
bool forceTCG)
|
||||
{
|
||||
virDomainXMLOptionPtr xmlopt = NULL;
|
||||
const char *machine;
|
||||
int status = 0;
|
||||
int ret = -1;
|
||||
|
||||
if (forceTCG)
|
||||
machine = "none,accel=tcg";
|
||||
else
|
||||
machine = "none,accel=kvm:tcg";
|
||||
|
||||
VIR_DEBUG("Try to probe capabilities of '%s' via QMP, machine %s",
|
||||
cmd->binary, machine);
|
||||
|
||||
/*
|
||||
* We explicitly need to use -daemonize here, rather than
|
||||
* virCommandDaemonize, because we need to synchronize
|
||||
* with QEMU creating its monitor socket API. Using
|
||||
* daemonize guarantees control won't return to libvirt
|
||||
* until the socket is present.
|
||||
*/
|
||||
cmd->cmd = virCommandNewArgList(cmd->binary,
|
||||
"-S",
|
||||
"-no-user-config",
|
||||
"-nodefaults",
|
||||
"-nographic",
|
||||
"-machine", machine,
|
||||
"-qmp", cmd->monarg,
|
||||
"-pidfile", cmd->pidfile,
|
||||
"-daemonize",
|
||||
NULL);
|
||||
virCommandAddEnvPassCommon(cmd->cmd);
|
||||
virCommandClearCaps(cmd->cmd);
|
||||
|
||||
#if WITH_CAPNG
|
||||
/* QEMU might run into permission issues, e.g. /dev/sev (0600), override
|
||||
* them just for the purpose of probing */
|
||||
if (geteuid() == 0)
|
||||
virCommandAllowCap(cmd->cmd, CAP_DAC_OVERRIDE);
|
||||
#endif
|
||||
|
||||
virCommandSetGID(cmd->cmd, cmd->runGid);
|
||||
virCommandSetUID(cmd->cmd, cmd->runUid);
|
||||
|
||||
virCommandSetErrorBuffer(cmd->cmd, cmd->qmperr);
|
||||
|
||||
/* Log, but otherwise ignore, non-zero status. */
|
||||
if (virCommandRun(cmd->cmd, &status) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (status != 0) {
|
||||
VIR_DEBUG("QEMU %s exited with status %d: %s",
|
||||
cmd->binary, status, *cmd->qmperr);
|
||||
goto ignore;
|
||||
}
|
||||
|
||||
if (virPidFileReadPath(cmd->pidfile, &cmd->pid) < 0) {
|
||||
VIR_DEBUG("Failed to read pidfile %s", cmd->pidfile);
|
||||
goto ignore;
|
||||
}
|
||||
|
||||
if (!(xmlopt = virDomainXMLOptionNew(NULL, NULL, NULL, NULL, NULL)) ||
|
||||
!(cmd->vm = virDomainObjNew(xmlopt)))
|
||||
goto cleanup;
|
||||
|
||||
cmd->vm->pid = cmd->pid;
|
||||
|
||||
if (!(cmd->mon = qemuMonitorOpen(cmd->vm, &cmd->config, true, true,
|
||||
0, &callbacks, NULL)))
|
||||
goto ignore;
|
||||
|
||||
virObjectLock(cmd->mon);
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
if (!cmd->mon)
|
||||
virQEMUCapsInitQMPCommandAbort(cmd);
|
||||
virObjectUnref(xmlopt);
|
||||
|
||||
return ret;
|
||||
|
||||
ignore:
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
virQEMUCapsInitQMP(virQEMUCapsPtr qemuCaps,
|
||||
const char *libDir,
|
||||
|
|
|
@ -34,6 +34,10 @@
|
|||
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#if WITH_CAPNG
|
||||
# include <cap-ng.h>
|
||||
#endif
|
||||
|
||||
#include "qemu_process.h"
|
||||
#define LIBVIRT_QEMU_PROCESSPRIV_H_ALLOW
|
||||
#include "qemu_processpriv.h"
|
||||
|
@ -8306,3 +8310,210 @@ qemuProcessReconnectAll(virQEMUDriverPtr driver)
|
|||
struct qemuProcessReconnectData data = {.driver = driver};
|
||||
virDomainObjListForEach(driver->domains, qemuProcessReconnectHelper, &data);
|
||||
}
|
||||
|
||||
|
||||
static void virQEMUCapsMonitorNotify(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
|
||||
virDomainObjPtr vm ATTRIBUTE_UNUSED,
|
||||
void *opaque ATTRIBUTE_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
static qemuMonitorCallbacks callbacks = {
|
||||
.eofNotify = virQEMUCapsMonitorNotify,
|
||||
.errorNotify = virQEMUCapsMonitorNotify,
|
||||
};
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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(&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"
|
||||
* Normally we'd use runDir for pid files, but because we're using
|
||||
* -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(&cmd->pidfile, "%s/%s", libDir, "capabilities.pidfile") < 0)
|
||||
goto error;
|
||||
|
||||
virPidFileForceCleanupPath(cmd->pidfile);
|
||||
|
||||
cmd->config.type = VIR_DOMAIN_CHR_TYPE_UNIX;
|
||||
cmd->config.data.nix.path = cmd->monpath;
|
||||
cmd->config.data.nix.listen = false;
|
||||
|
||||
return cmd;
|
||||
|
||||
error:
|
||||
virQEMUCapsInitQMPCommandFree(cmd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Returns -1 on fatal error,
|
||||
* 0 on success,
|
||||
* 1 when probing QEMU failed
|
||||
*/
|
||||
int
|
||||
virQEMUCapsInitQMPCommandRun(virQEMUCapsInitQMPCommandPtr cmd,
|
||||
bool forceTCG)
|
||||
{
|
||||
virDomainXMLOptionPtr xmlopt = NULL;
|
||||
const char *machine;
|
||||
int status = 0;
|
||||
int ret = -1;
|
||||
|
||||
if (forceTCG)
|
||||
machine = "none,accel=tcg";
|
||||
else
|
||||
machine = "none,accel=kvm:tcg";
|
||||
|
||||
VIR_DEBUG("Try to probe capabilities of '%s' via QMP, machine %s",
|
||||
cmd->binary, machine);
|
||||
|
||||
/*
|
||||
* We explicitly need to use -daemonize here, rather than
|
||||
* virCommandDaemonize, because we need to synchronize
|
||||
* with QEMU creating its monitor socket API. Using
|
||||
* daemonize guarantees control won't return to libvirt
|
||||
* until the socket is present.
|
||||
*/
|
||||
cmd->cmd = virCommandNewArgList(cmd->binary,
|
||||
"-S",
|
||||
"-no-user-config",
|
||||
"-nodefaults",
|
||||
"-nographic",
|
||||
"-machine", machine,
|
||||
"-qmp", cmd->monarg,
|
||||
"-pidfile", cmd->pidfile,
|
||||
"-daemonize",
|
||||
NULL);
|
||||
virCommandAddEnvPassCommon(cmd->cmd);
|
||||
virCommandClearCaps(cmd->cmd);
|
||||
|
||||
#if WITH_CAPNG
|
||||
/* QEMU might run into permission issues, e.g. /dev/sev (0600), override
|
||||
* them just for the purpose of probing */
|
||||
if (geteuid() == 0)
|
||||
virCommandAllowCap(cmd->cmd, CAP_DAC_OVERRIDE);
|
||||
#endif
|
||||
|
||||
virCommandSetGID(cmd->cmd, cmd->runGid);
|
||||
virCommandSetUID(cmd->cmd, cmd->runUid);
|
||||
|
||||
virCommandSetErrorBuffer(cmd->cmd, cmd->qmperr);
|
||||
|
||||
/* Log, but otherwise ignore, non-zero status. */
|
||||
if (virCommandRun(cmd->cmd, &status) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (status != 0) {
|
||||
VIR_DEBUG("QEMU %s exited with status %d: %s",
|
||||
cmd->binary, status, *cmd->qmperr);
|
||||
goto ignore;
|
||||
}
|
||||
|
||||
if (virPidFileReadPath(cmd->pidfile, &cmd->pid) < 0) {
|
||||
VIR_DEBUG("Failed to read pidfile %s", cmd->pidfile);
|
||||
goto ignore;
|
||||
}
|
||||
|
||||
if (!(xmlopt = virDomainXMLOptionNew(NULL, NULL, NULL, NULL, NULL)) ||
|
||||
!(cmd->vm = virDomainObjNew(xmlopt)))
|
||||
goto cleanup;
|
||||
|
||||
cmd->vm->pid = cmd->pid;
|
||||
|
||||
if (!(cmd->mon = qemuMonitorOpen(cmd->vm, &cmd->config, true, true,
|
||||
0, &callbacks, NULL)))
|
||||
goto ignore;
|
||||
|
||||
virObjectLock(cmd->mon);
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
if (!cmd->mon)
|
||||
virQEMUCapsInitQMPCommandAbort(cmd);
|
||||
virObjectUnref(xmlopt);
|
||||
|
||||
return ret;
|
||||
|
||||
ignore:
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -214,4 +214,34 @@ int qemuProcessStartManagedPRDaemon(virDomainObjPtr vm);
|
|||
|
||||
void qemuProcessKillManagedPRDaemon(virDomainObjPtr vm);
|
||||
|
||||
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;
|
||||
pid_t pid;
|
||||
virDomainObjPtr vm;
|
||||
};
|
||||
|
||||
virQEMUCapsInitQMPCommandPtr virQEMUCapsInitQMPCommandNew(char *binary,
|
||||
const char *libDir,
|
||||
uid_t runUid,
|
||||
gid_t runGid,
|
||||
char **qmperr);
|
||||
|
||||
void virQEMUCapsInitQMPCommandFree(virQEMUCapsInitQMPCommandPtr cmd);
|
||||
|
||||
int virQEMUCapsInitQMPCommandRun(virQEMUCapsInitQMPCommandPtr cmd,
|
||||
bool forceTCG);
|
||||
|
||||
void virQEMUCapsInitQMPCommandAbort(virQEMUCapsInitQMPCommandPtr cmd);
|
||||
|
||||
#endif /* LIBVIRT_QEMU_PROCESS_H */
|
||||
|
|
Loading…
Reference in New Issue