When the libvirtd daemon starts up, it reads all config files from
/etc/libvirt/qemu. For each config file loaded, it then probes for
a pidfile / live status XML config in /var/run/libvirt/qemu.
In retrospect there is an obvious problem with this approach: it misses
all transient VMs which don't ever have config files in /etc/libvirt/qemu.
The core goal of this patch, is thus to change the way we deal with startup
to apply the following logic.
- Scan & load all status files in /var/run/libvirt/qemu for running VMs
- Reconnect to the monitor for all VMs, and re-detect VCPU threads.
- Scan & load all inactive configs in /etc/libvirt/qemu
This ensures we always re-detect all inactive and running VMs, whether
transient or persistent.
It also fixes two other bugs, first we forgot to detect VCPU threads,
so vCPU affinity functions were broken, and it also re-reserves the MCS
category with selinux so it is not re-used later.
Finally, if the attempt to reconnect to the QEMU monitor for a running
VM fails, then we explicitly kill off that VM, rather than just ignoring
it. This avoids leaving orphaned QEMU processes.
The patch is larger than anticipated, because I moved all the status
file code out of QEMU driver into the generic domain_conf.c file. This
enables both scanning loops to be done via the single method
virDomainLoadAllConfigs, just by pasing different directories. I also
want to re-use this code in the LXC and UML drivers to improve bugs in
their logic
domain_conf.c | 314 ++++++++++++++++++++++++++++++++++++++++++++++-----
domain_conf.h | 17 ++
libvirt_private.syms | 1
lxc_driver.c | 2
qemu_conf.c | 190 ------------------------------
qemu_conf.h | 18 --
qemu_driver.c | 178 +++++++++++++---------------
security.h | 3
security_selinux.c | 39 ++++++
uml_driver.c | 4
10 files changed, 431 insertions(+), 335 deletions(-)
Daniel
diff --git a/src/domain_conf.c b/src/domain_conf.c
--- a/src/domain_conf.c
+++ b/src/domain_conf.c
@@ -39,6 +39,7 @@
#include "util.h"
#include "buf.h"
#include "c-ctype.h"
+#include "logging.h"
#define VIR_FROM_THIS VIR_FROM_DOMAIN
@@ -511,6 +512,31 @@ void virDomainObjListFree(virDomainObjLi
vms->count = 0;
}
+
+static virDomainObjPtr virDomainObjNew(virConnectPtr conn)
+{
+ virDomainObjPtr domain;
+
+ if (VIR_ALLOC(domain) < 0) {
+ virReportOOMError(conn);
+ return NULL;
+ }
+
+ if (virMutexInit(&domain->lock) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot initialize mutex"));
+ VIR_FREE(domain);
+ return NULL;
+ }
+
+ virDomainObjLock(domain);
+ domain->state = VIR_DOMAIN_SHUTOFF;
+ domain->monitorWatch = -1;
+ domain->monitor = -1;
+
+ return domain;
+}
+
virDomainObjPtr virDomainAssignDef(virConnectPtr conn,
virDomainObjListPtr doms,
const virDomainDefPtr def)
@@ -530,29 +556,15 @@ virDomainObjPtr virDomainAssignDef(virCo
return domain;
}
- if (VIR_ALLOC(domain) < 0) {
- virReportOOMError(conn);
- return NULL;
- }
-
- if (virMutexInit(&domain->lock) < 0) {
- virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
- "%s", _("cannot initialize mutex"));
- VIR_FREE(domain);
- return NULL;
- }
-
- virDomainObjLock(domain);
- domain->state = VIR_DOMAIN_SHUTOFF;
+ if (VIR_REALLOC_N(doms->objs, doms->count + 1) < 0) {
+ virReportOOMError(conn);
+ return NULL;
+ }
+
+ if (!(domain = virDomainObjNew(conn)))
+ return NULL;
+
domain->def = def;
- domain->monitorWatch = -1;
- domain->monitor = -1;
-
- if (VIR_REALLOC_N(doms->objs, doms->count + 1) < 0) {
- virReportOOMError(conn);
- VIR_FREE(domain);
- return NULL;
- }
doms->objs[doms->count] = domain;
doms->count++;
@@ -2621,6 +2633,68 @@ no_memory:
return NULL;
}
+
+static virDomainObjPtr virDomainObjParseXML(virConnectPtr conn,
+ virCapsPtr caps,
+ xmlXPathContextPtr ctxt)
+{
+ char *tmp = NULL;
+ long val;
+ xmlNodePtr config;
+ xmlNodePtr oldctxt;
+ virDomainObjPtr obj;
+
+ if (!(obj = virDomainObjNew(conn)))
+ return NULL;
+
+ if (!(config = virXPathNode(conn, "./domain", ctxt))) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("no domain config"));
+ goto error;
+ }
+
+ oldctxt = ctxt->node;
+ ctxt->node = config;
+ obj->def = virDomainDefParseXML(conn, caps, ctxt, 0);
+ ctxt->node = oldctxt;
+ if (!obj->def)
+ goto error;
+
+ if (!(tmp = virXPathString(conn, "string(./@state)", ctxt))) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("missing domain state"));
+ goto error;
+ }
+ if ((obj->state = virDomainStateTypeFromString(tmp)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("invalid domain state '%s'"), tmp);
+ VIR_FREE(tmp);
+ goto error;
+ }
+ VIR_FREE(tmp);
+
+ if ((virXPathLong(conn, "string(./@pid)", ctxt, &val)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("invalid pid"));
+ goto error;
+ }
+ obj->pid = (pid_t)val;
+
+ if(!(obj->monitorpath =
+ virXPathString(conn, "string(./monitor[1]/@path)", ctxt))) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("no monitor path"));
+ goto error;
+ }
+
+ return obj;
+
+error:
+ virDomainObjFree(obj);
+ return NULL;
+}
+
+
/* Called from SAX on parsing errors in the XML. */
static void
catchXMLError (void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
@@ -2753,6 +2827,78 @@ cleanup:
xmlXPathFreeContext(ctxt);
return def;
}
+
+
+virDomainObjPtr virDomainObjParseFile(virConnectPtr conn,
+ virCapsPtr caps,
+ const char *filename)
+{
+ xmlParserCtxtPtr pctxt;
+ xmlDocPtr xml = NULL;
+ xmlNodePtr root;
+ virDomainObjPtr obj = NULL;
+
+ /* Set up a parser context so we can catch the details of XML errors. */
+ pctxt = xmlNewParserCtxt ();
+ if (!pctxt || !pctxt->sax)
+ goto cleanup;
+ pctxt->sax->error = catchXMLError;
+ pctxt->_private = conn;
+
+ if (conn) virResetError (&conn->err);
+ xml = xmlCtxtReadFile (pctxt, filename, NULL,
+ XML_PARSE_NOENT | XML_PARSE_NONET |
+ XML_PARSE_NOWARNING);
+ if (!xml) {
+ if (virGetLastError() == NULL)
+ virDomainReportError(conn, VIR_ERR_XML_ERROR,
+ "%s", _("failed to parse xml
document"));
+ goto cleanup;
+ }
+
+ if ((root = xmlDocGetRootElement(xml)) == NULL) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("missing root element"));
+ goto cleanup;
+ }
+
+ obj = virDomainObjParseNode(conn, caps, xml, root);
+
+cleanup:
+ xmlFreeParserCtxt (pctxt);
+ xmlFreeDoc (xml);
+ return obj;
+}
+
+
+virDomainObjPtr virDomainObjParseNode(virConnectPtr conn,
+ virCapsPtr caps,
+ xmlDocPtr xml,
+ xmlNodePtr root)
+{
+ xmlXPathContextPtr ctxt = NULL;
+ virDomainObjPtr obj = NULL;
+
+ if (!xmlStrEqual(root->name, BAD_CAST "domstatus")) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("incorrect root element"));
+ goto cleanup;
+ }
+
+ ctxt = xmlXPathNewContext(xml);
+ if (ctxt == NULL) {
+ virReportOOMError(conn);
+ goto cleanup;
+ }
+
+ ctxt->node = root;
+ obj = virDomainObjParseXML(conn, caps, ctxt);
+
+cleanup:
+ xmlXPathFreeContext(ctxt);
+ return obj;
+}
+
#endif /* ! PROXY */
/************************************************************************
@@ -3704,6 +3850,33 @@ char *virDomainDefFormat(virConnectPtr c
return NULL;
}
+char *virDomainObjFormat(virConnectPtr conn,
+ virDomainObjPtr obj,
+ int flags)
+{
+ char *config_xml = NULL, *xml = NULL;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+ virBufferVSprintf(&buf, "<domstatus state='%s'
pid='%d'>\n",
+ virDomainStateTypeToString(obj->state),
+ obj->pid);
+ virBufferEscapeString(&buf, " <monitor path='%s'/>\n",
obj->monitorpath);
+
+ if (!(config_xml = virDomainDefFormat(conn,
+ obj->def,
+ flags)))
+ goto cleanup;
+
+ virBufferAdd(&buf, config_xml, strlen(config_xml));
+ virBufferAddLit(&buf, "</domstatus>\n");
+
+ xml = virBufferContentAndReset(&buf);
+cleanup:
+ VIR_FREE(config_xml);
+ return xml;
+
+}
+
#ifndef PROXY
@@ -3779,6 +3952,27 @@ cleanup:
return ret;
}
+int virDomainSaveStatus(virConnectPtr conn,
+ const char *statusDir,
+ virDomainObjPtr obj)
+{
+ int ret = -1;
+ char *xml;
+
+ if (!(xml = virDomainObjFormat(conn,
+ obj,
+ VIR_DOMAIN_XML_SECURE)))
+ goto cleanup;
+
+ if (virDomainSaveXML(conn, statusDir, obj->def, xml))
+ goto cleanup;
+
+ ret = 0;
+cleanup:
+ VIR_FREE(xml);
+ return ret;
+}
+
virDomainObjPtr virDomainLoadConfig(virConnectPtr conn,
virCapsPtr caps,
@@ -3832,17 +4026,67 @@ error:
return NULL;
}
+static virDomainObjPtr virDomainLoadStatus(virConnectPtr conn,
+ virCapsPtr caps,
+ virDomainObjListPtr doms,
+ const char *statusDir,
+ const char *name,
+ virDomainLoadConfigNotify notify,
+ void *opaque)
+{
+ char *statusFile = NULL;
+ virDomainObjPtr obj = NULL;
+ virDomainObjPtr tmp = NULL;
+
+ if ((statusFile = virDomainConfigFile(conn, statusDir, name)) == NULL)
+ goto error;
+
+ if (!(obj = virDomainObjParseFile(conn, caps, statusFile)))
+ goto error;
+
+ tmp = virDomainFindByName(doms, obj->def->name);
+ if (tmp) {
+ virDomainObjUnlock(obj);
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected domain %s already exists"),
obj->def->name);
+ goto error;
+ }
+
+ if (VIR_REALLOC_N(doms->objs, doms->count + 1) < 0) {
+ virReportOOMError(conn);
+ goto error;
+ }
+
+ doms->objs[doms->count] = obj;
+ doms->count++;
+
+ if (notify)
+ (*notify)(obj, 1, opaque);
+
+ VIR_FREE(statusFile);
+ return obj;
+
+error:
+ virDomainObjFree(obj);
+ VIR_FREE(statusFile);
+ return NULL;
+}
+
int virDomainLoadAllConfigs(virConnectPtr conn,
virCapsPtr caps,
virDomainObjListPtr doms,
const char *configDir,
const char *autostartDir,
+ int liveStatus,
virDomainLoadConfigNotify notify,
void *opaque)
{
DIR *dir;
struct dirent *entry;
+ VIR_INFO("Scanning for %s configs in %s",
+ liveStatus ? "live" : "persistent", configDir);
+
if (!(dir = opendir(configDir))) {
if (errno == ENOENT)
return 0;
@@ -3863,14 +4107,24 @@ int virDomainLoadAllConfigs(virConnectPt
/* NB: ignoring errors, so one malformed config doesn't
kill the whole process */
- dom = virDomainLoadConfig(conn,
- caps,
- doms,
- configDir,
- autostartDir,
- entry->d_name,
- notify,
- opaque);
+ VIR_INFO("Loading config file '%s.xml'", entry->d_name);
+ if (liveStatus)
+ dom = virDomainLoadStatus(conn,
+ caps,
+ doms,
+ configDir,
+ entry->d_name,
+ notify,
+ opaque);
+ else
+ dom = virDomainLoadConfig(conn,
+ caps,
+ doms,
+ configDir,
+ autostartDir,
+ entry->d_name,
+ notify,
+ opaque);
if (dom) {
virDomainObjUnlock(dom);
dom->persistent = 1;
diff --git a/src/domain_conf.h b/src/domain_conf.h
--- a/src/domain_conf.h
+++ b/src/domain_conf.h
@@ -515,7 +515,6 @@ struct _virDomainObj {
int monitor;
char *monitorpath;
int monitorWatch;
- int logfile;
int pid;
int state;
@@ -589,10 +588,22 @@ virDomainDefPtr virDomainDefParseNode(vi
xmlDocPtr doc,
xmlNodePtr root,
int flags);
+
+virDomainObjPtr virDomainObjParseFile(virConnectPtr conn,
+ virCapsPtr caps,
+ const char *filename);
+virDomainObjPtr virDomainObjParseNode(virConnectPtr conn,
+ virCapsPtr caps,
+ xmlDocPtr xml,
+ xmlNodePtr root);
+
#endif
char *virDomainDefFormat(virConnectPtr conn,
virDomainDefPtr def,
int flags);
+char *virDomainObjFormat(virConnectPtr conn,
+ virDomainObjPtr obj,
+ int flags);
int virDomainCpuSetParse(virConnectPtr conn,
const char **str,
@@ -615,6 +626,9 @@ int virDomainSaveXML(virConnectPtr conn,
int virDomainSaveConfig(virConnectPtr conn,
const char *configDir,
virDomainDefPtr def);
+int virDomainSaveStatus(virConnectPtr conn,
+ const char *statusDir,
+ virDomainObjPtr obj);
typedef void (*virDomainLoadConfigNotify)(virDomainObjPtr dom,
int newDomain,
@@ -634,6 +648,7 @@ int virDomainLoadAllConfigs(virConnectPt
virDomainObjListPtr doms,
const char *configDir,
const char *autostartDir,
+ int liveStatus,
virDomainLoadConfigNotify notify,
void *opaque);
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -94,6 +94,7 @@ virDomainObjListFree;
virDomainRemoveInactive;
virDomainSaveXML;
virDomainSaveConfig;
+virDomainSaveStatus;
virDomainSoundDefFree;
virDomainSoundModelTypeFromString;
virDomainSoundModelTypeToString;
diff --git a/src/lxc_driver.c b/src/lxc_driver.c
--- a/src/lxc_driver.c
+++ b/src/lxc_driver.c
@@ -1176,7 +1176,7 @@ static int lxcStartup(void)
&lxc_driver->domains,
lxc_driver->configDir,
lxc_driver->autostartDir,
- NULL, NULL) < 0)
+ 0, NULL, NULL) < 0)
goto cleanup;
for (i = 0 ; i < lxc_driver->domains.count ; i++) {
diff --git a/src/qemu_conf.c b/src/qemu_conf.c
--- a/src/qemu_conf.c
+++ b/src/qemu_conf.c
@@ -2765,193 +2765,3 @@ cleanup:
return def;
}
-
-/* Called from SAX on parsing errors in the XML. */
-static void
-catchXMLError (void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
-{
- xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
-
- if (ctxt) {
- virConnectPtr conn = ctxt->_private;
-
- if (ctxt->lastError.level == XML_ERR_FATAL &&
- ctxt->lastError.message != NULL) {
- qemudReportError (conn, NULL, NULL, VIR_ERR_XML_DETAIL,
- _("at line %d: %s"),
- ctxt->lastError.line,
- ctxt->lastError.message);
- }
- }
-}
-
-
-/**
- * qemudDomainStatusParseFile
- *
- * read the last known status of a domain
- *
- * Returns 0 on success
- */
-qemudDomainStatusPtr
-qemudDomainStatusParseFile(virConnectPtr conn,
- virCapsPtr caps,
- const char *filename, int flags)
-{
- xmlParserCtxtPtr pctxt = NULL;
- xmlXPathContextPtr ctxt = NULL;
- xmlDocPtr xml = NULL;
- xmlNodePtr root, config_root;
- virDomainDefPtr def = NULL;
- char *tmp = NULL;
- long val;
- qemudDomainStatusPtr status = NULL;
-
- if (VIR_ALLOC(status) < 0) {
- virReportOOMError(conn);
- goto error;
- }
-
- /* Set up a parser context so we can catch the details of XML errors. */
- pctxt = xmlNewParserCtxt ();
- if (!pctxt || !pctxt->sax)
- goto error;
- pctxt->sax->error = catchXMLError;
- pctxt->_private = conn;
-
- if (conn) virResetError (&conn->err);
- xml = xmlCtxtReadFile (pctxt, filename, NULL,
- XML_PARSE_NOENT | XML_PARSE_NONET |
- XML_PARSE_NOWARNING);
- if (!xml) {
- if (conn && conn->err.code == VIR_ERR_NONE)
- qemudReportError(conn, NULL, NULL, VIR_ERR_XML_ERROR,
- "%s", _("failed to parse xml
document"));
- goto error;
- }
-
- if ((root = xmlDocGetRootElement(xml)) == NULL) {
- qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
- "%s", _("missing root element"));
- goto error;
- }
-
- ctxt = xmlXPathNewContext(xml);
- if (ctxt == NULL) {
- virReportOOMError(conn);
- goto error;
- }
-
- if (!xmlStrEqual(root->name, BAD_CAST "domstatus")) {
- qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
- "%s", _("incorrect root element"));
- goto error;
- }
-
- ctxt->node = root;
- if(!(tmp = virXPathString(conn, "string(./@state)", ctxt))) {
- qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
- "%s", _("invalid domain state"));
- goto error;
- } else {
- status->state = virDomainStateTypeFromString(tmp);
- VIR_FREE(tmp);
- }
-
- if((virXPathLong(conn, "string(./@pid)", ctxt, &val)) < 0) {
- qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
- "%s", _("invalid pid"));
- goto error;
- } else
- status->pid = (pid_t)val;
-
- if(!(tmp = virXPathString(conn, "string(./monitor[1]/@path)", ctxt))) {
- qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
- "%s", _("no monitor path"));
- goto error;
- } else
- status->monitorpath = tmp;
-
- if(!(config_root = virXPathNode(conn, "./domain", ctxt))) {
- qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
- "%s", _("no domain config"));
- goto error;
- }
- if(!(def = virDomainDefParseNode(conn, caps, xml, config_root, flags)))
- goto error;
- else
- status->def = def;
-
-cleanup:
- xmlFreeParserCtxt (pctxt);
- xmlXPathFreeContext(ctxt);
- xmlFreeDoc (xml);
- return status;
-
-error:
- VIR_FREE(tmp);
- VIR_FREE(status);
- goto cleanup;
-}
-
-
-/**
- * qemudDomainStatusFormat
- *
- * Get the state of a running domain as XML
- *
- * Returns xml on success
- */
-static char*
-qemudDomainStatusFormat(virConnectPtr conn,
- virDomainObjPtr vm)
-{
- char *config_xml = NULL, *xml = NULL;
- virBuffer buf = VIR_BUFFER_INITIALIZER;
-
- virBufferVSprintf(&buf, "<domstatus state='%s'
pid='%d'>\n",
- virDomainStateTypeToString(vm->state),
- vm->pid);
- virBufferEscapeString(&buf, " <monitor path='%s'/>\n",
vm->monitorpath);
-
- if (!(config_xml = virDomainDefFormat(conn,
- vm->def,
- VIR_DOMAIN_XML_SECURE)))
- goto cleanup;
-
- virBufferAdd(&buf, config_xml, strlen(config_xml));
- virBufferAddLit(&buf, "</domstatus>\n");
-
- xml = virBufferContentAndReset(&buf);
-cleanup:
- VIR_FREE(config_xml);
- return xml;
-}
-
-
-/**
- * qemudSaveDomainStatus
- *
- * Save the current status of a running domain
- *
- * Returns 0 on success
- */
-int
-qemudSaveDomainStatus(virConnectPtr conn,
- struct qemud_driver *driver,
- virDomainObjPtr vm)
-{
- int ret = -1;
- char *xml = NULL;
-
- if (!(xml = qemudDomainStatusFormat(conn, vm)))
- goto cleanup;
-
- if ((ret = virDomainSaveXML(conn, driver->stateDir, vm->def, xml)))
- goto cleanup;
-
- ret = 0;
-cleanup:
- VIR_FREE(xml);
- return ret;
-}
diff --git a/src/qemu_conf.h b/src/qemu_conf.h
--- a/src/qemu_conf.h
+++ b/src/qemu_conf.h
@@ -92,15 +92,6 @@ struct qemud_driver {
virSecurityDriverPtr securityDriver;
};
-/* Status needed to reconenct to running VMs */
-typedef struct _qemudDomainStatus qemudDomainStatus;
-typedef qemudDomainStatus *qemudDomainStatusPtr;
-struct _qemudDomainStatus {
- char *monitorpath;
- pid_t pid;
- int state;
- virDomainDefPtr def;
-};
/* Port numbers used for KVM migration. */
#define QEMUD_MIGRATION_FIRST_PORT 49152
@@ -141,13 +132,4 @@ virDomainDefPtr qemuParseCommandLine(vir
virDomainDefPtr qemuParseCommandLineString(virConnectPtr conn,
const char *args);
-const char *qemudVirtTypeToString (int type);
-qemudDomainStatusPtr qemudDomainStatusParseFile(virConnectPtr conn,
- virCapsPtr caps,
- const char *filename,
- int flags);
-int qemudSaveDomainStatus(virConnectPtr conn,
- struct qemud_driver *driver,
- virDomainObjPtr vm);
-
#endif /* __QEMUD_CONF_H */
diff --git a/src/qemu_driver.c b/src/qemu_driver.c
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -125,6 +125,8 @@ static int qemudMonitorCommandExtra(cons
static int qemudDomainSetMemoryBalloon(virConnectPtr conn,
virDomainObjPtr vm,
unsigned long newmem);
+static int qemudDetectVcpuPIDs(virConnectPtr conn,
+ virDomainObjPtr vm);
static struct qemud_driver *qemu_driver = NULL;
@@ -287,79 +289,65 @@ static int qemudOpenMonitor(virConnectPt
const char *monitor,
int reconnect);
+
+/*
+ * Open an existing VM's monitor, and re-detect VCPUs
+ * threads
+ */
+static int
+qemuReconnectDomain(struct qemud_driver *driver,
+ virDomainObjPtr obj)
+{
+ int rc;
+
+ if ((rc = qemudOpenMonitor(NULL, driver, obj, obj->monitorpath, 1)) != 0) {
+ VIR_ERROR(_("Failed to reconnect monitor for %s: %d\n"),
+ obj->def->name, rc);
+ goto error;
+ }
+
+ if (qemudDetectVcpuPIDs(NULL, obj) < 0) {
+ goto error;
+ }
+
+ if (obj->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
+ driver->securityDriver &&
+ driver->securityDriver->domainReserveSecurityLabel &&
+ driver->securityDriver->domainReserveSecurityLabel(NULL, obj) < 0)
+ return -1;
+
+ if (obj->def->id >= driver->nextvmid)
+ driver->nextvmid = obj->def->id + 1;
+
+ return 0;
+
+error:
+ return -1;
+}
+
/**
* qemudReconnectVMs
*
- * Reconnect running vms to the daemon process
- */
-static int
-qemudReconnectVMs(struct qemud_driver *driver)
+ * Try to re-open the resources for live VMs that we care
+ * about.
+ */
+static void
+qemuReconnectDomains(struct qemud_driver *driver)
{
int i;
for (i = 0 ; i < driver->domains.count ; i++) {
- virDomainObjPtr vm = driver->domains.objs[i];
- qemudDomainStatusPtr status = NULL;
- char *config = NULL;
- int rc;
-
- virDomainObjLock(vm);
- if ((rc = virFileReadPid(driver->stateDir, vm->def->name,
&vm->pid)) == 0)
- DEBUG("Found pid %d for '%s'", vm->pid,
vm->def->name);
- else
- goto next;
-
- if ((config = virDomainConfigFile(NULL,
- driver->stateDir,
- vm->def->name)) == NULL) {
- VIR_ERROR(_("Failed to read domain status for %s\n"),
- vm->def->name);
- goto next_error;
- }
-
- status = qemudDomainStatusParseFile(NULL, driver->caps, config, 0);
- if (status) {
- vm->newDef = vm->def;
- vm->def = status->def;
- } else {
- VIR_ERROR(_("Failed to parse domain status for %s\n"),
- vm->def->name);
- goto next_error;
- }
-
- if ((rc = qemudOpenMonitor(NULL, driver, vm, status->monitorpath, 1)) != 0) {
- VIR_ERROR(_("Failed to reconnect monitor for %s: %d\n"),
- vm->def->name, rc);
- goto next_error;
- }
-
- if ((vm->logfile = qemudLogFD(NULL, driver->logDir, vm->def->name))
< 0)
- goto next_error;
-
- if (vm->def->id >= driver->nextvmid)
- driver->nextvmid = vm->def->id + 1;
-
- vm->state = status->state;
- goto next;
-
-next_error:
- /* we failed to reconnect the vm so remove it's traces */
- vm->def->id = -1;
- qemudRemoveDomainStatus(NULL, driver, vm);
- /* Restore orignal def, if we'd loaded a live one */
- if (vm->newDef) {
- virDomainDefFree(vm->def);
- vm->def = vm->newDef;
- vm->newDef = NULL;
- }
-next:
- virDomainObjUnlock(vm);
- if (status)
- VIR_FREE(status->monitorpath);
- VIR_FREE(status);
- VIR_FREE(config);
- }
- return 0;
+ virDomainObjPtr obj = driver->domains.objs[i];
+
+ virDomainObjLock(obj);
+ if (qemuReconnectDomain(driver, obj) < 0) {
+ /* If we can't get the monitor back, then kill the VM
+ * so user has ability to start it again later without
+ * danger of ending up running twice */
+ qemudShutdownVMDaemon(NULL, driver, obj);
+ }
+ virDomainObjUnlock(obj);
+ }
}
static int
@@ -513,14 +501,25 @@ qemudStartup(void) {
goto error;
}
+ /* Get all the running persistent or transient configs first */
+ if (virDomainLoadAllConfigs(NULL,
+ qemu_driver->caps,
+ &qemu_driver->domains,
+ qemu_driver->stateDir,
+ NULL,
+ 1, NULL, NULL) < 0)
+ goto error;
+
+ qemuReconnectDomains(qemu_driver);
+
+ /* Then inactive persistent configs */
if (virDomainLoadAllConfigs(NULL,
qemu_driver->caps,
&qemu_driver->domains,
qemu_driver->configDir,
qemu_driver->autostartDir,
- NULL, NULL) < 0)
- goto error;
- qemudReconnectVMs(qemu_driver);
+ 0, NULL, NULL) < 0)
+ goto error;
qemuDriverUnlock(qemu_driver);
qemudAutostartConfigs(qemu_driver);
@@ -569,7 +568,7 @@ qemudReload(void) {
&qemu_driver->domains,
qemu_driver->configDir,
qemu_driver->autostartDir,
- qemudNotifyLoadDomain, qemu_driver);
+ 0, qemudNotifyLoadDomain, qemu_driver);
qemuDriverUnlock(qemu_driver);
qemudAutostartConfigs(qemu_driver);
@@ -1331,6 +1330,7 @@ static int qemudStartVMDaemon(virConnect
int pos = -1;
char ebuf[1024];
char *pidfile = NULL;
+ int logfile;
struct gemudHookData hookData;
hookData.conn = conn;
@@ -1372,7 +1372,7 @@ static int qemudStartVMDaemon(virConnect
goto cleanup;
}
- if((vm->logfile = qemudLogFD(conn, driver->logDir, vm->def->name)) <
0)
+ if ((logfile = qemudLogFD(conn, driver->logDir, vm->def->name)) < 0)
goto cleanup;
emulator = vm->def->emulator;
@@ -1421,29 +1421,29 @@ static int qemudStartVMDaemon(virConnect
tmp = progenv;
while (*tmp) {
- if (safewrite(vm->logfile, *tmp, strlen(*tmp)) < 0)
+ if (safewrite(logfile, *tmp, strlen(*tmp)) < 0)
VIR_WARN(_("Unable to write envv to logfile: %s\n"),
virStrerror(errno, ebuf, sizeof ebuf));
- if (safewrite(vm->logfile, " ", 1) < 0)
+ if (safewrite(logfile, " ", 1) < 0)
VIR_WARN(_("Unable to write envv to logfile: %s\n"),
virStrerror(errno, ebuf, sizeof ebuf));
tmp++;
}
tmp = argv;
while (*tmp) {
- if (safewrite(vm->logfile, *tmp, strlen(*tmp)) < 0)
+ if (safewrite(logfile, *tmp, strlen(*tmp)) < 0)
VIR_WARN(_("Unable to write argv to logfile: %s\n"),
virStrerror(errno, ebuf, sizeof ebuf));
- if (safewrite(vm->logfile, " ", 1) < 0)
+ if (safewrite(logfile, " ", 1) < 0)
VIR_WARN(_("Unable to write argv to logfile: %s\n"),
virStrerror(errno, ebuf, sizeof ebuf));
tmp++;
}
- if (safewrite(vm->logfile, "\n", 1) < 0)
+ if (safewrite(logfile, "\n", 1) < 0)
VIR_WARN(_("Unable to write argv to logfile: %s\n"),
virStrerror(errno, ebuf, sizeof ebuf));
- if ((pos = lseek(vm->logfile, 0, SEEK_END)) < 0)
+ if ((pos = lseek(logfile, 0, SEEK_END)) < 0)
VIR_WARN(_("Unable to seek to end of logfile: %s\n"),
virStrerror(errno, ebuf, sizeof ebuf));
@@ -1451,7 +1451,7 @@ static int qemudStartVMDaemon(virConnect
FD_SET(tapfds[i], &keepfd);
ret = virExecDaemonize(conn, argv, progenv, &keepfd, &child,
- stdin_fd, &vm->logfile, &vm->logfile,
+ stdin_fd, &logfile, &logfile,
VIR_EXEC_NONBLOCK,
qemudSecurityHook, &hookData,
pidfile);
@@ -1501,7 +1501,7 @@ static int qemudStartVMDaemon(virConnect
(qemudInitCpus(conn, vm, migrateFrom) < 0) ||
(qemudInitPasswords(conn, driver, vm) < 0) ||
(qemudDomainSetMemoryBalloon(conn, vm, vm->def->memory) < 0) ||
- (qemudSaveDomainStatus(conn, qemu_driver, vm) < 0)) {
+ (virDomainSaveStatus(conn, driver->stateDir, vm) < 0)) {
qemudShutdownVMDaemon(conn, driver, vm);
ret = -1;
/* No need for 'goto cleanup' now since qemudShutdownVMDaemon does enough
*/
@@ -1519,10 +1519,8 @@ cleanup:
vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
vm->def->graphics[0]->data.vnc.autoport)
vm->def->graphics[0]->data.vnc.port = -1;
- if (vm->logfile != -1) {
- close(vm->logfile);
- vm->logfile = -1;
- }
+ if (logfile != -1)
+ close(logfile);
vm->def->id = -1;
return -1;
}
@@ -1549,14 +1547,8 @@ static void qemudShutdownVMDaemon(virCon
vm->monitorWatch = -1;
}
- if (close(vm->logfile) < 0) {
- char ebuf[1024];
- VIR_WARN(_("Unable to close logfile: %s\n"),
- virStrerror(errno, ebuf, sizeof ebuf));
- }
if (vm->monitor != -1)
close(vm->monitor);
- vm->logfile = -1;
vm->monitor = -1;
/* shut it off for sure */
@@ -2260,7 +2252,7 @@ static int qemudDomainSuspend(virDomainP
VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
VIR_FREE(info);
}
- if (qemudSaveDomainStatus(dom->conn, driver, vm) < 0)
+ if (virDomainSaveStatus(dom->conn, driver->stateDir, vm) < 0)
goto cleanup;
ret = 0;
@@ -2310,7 +2302,7 @@ static int qemudDomainResume(virDomainPt
VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
VIR_FREE(info);
}
- if (qemudSaveDomainStatus(dom->conn, driver, vm) < 0)
+ if (virDomainSaveStatus(dom->conn, driver->stateDir, vm) < 0)
goto cleanup;
ret = 0;
@@ -4192,7 +4184,7 @@ static int qemudDomainAttachDevice(virDo
goto cleanup;
}
- if (!ret && qemudSaveDomainStatus(dom->conn, driver, vm) < 0)
+ if (!ret && virDomainSaveStatus(dom->conn, driver->stateDir, vm) <
0)
ret = -1;
cleanup:
@@ -4314,7 +4306,7 @@ static int qemudDomainDetachDevice(virDo
qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
"%s", _("only SCSI or virtio disk device can be
detached dynamically"));
- if (!ret && qemudSaveDomainStatus(dom->conn, driver, vm) < 0)
+ if (!ret && virDomainSaveStatus(dom->conn, driver->stateDir, vm) <
0)
ret = -1;
cleanup:
diff --git a/src/security.h b/src/security.h
--- a/src/security.h
+++ b/src/security.h
@@ -38,6 +38,8 @@ typedef int (*virSecurityDomainSetImageL
virDomainDiskDefPtr disk);
typedef int (*virSecurityDomainGenLabel) (virConnectPtr conn,
virDomainObjPtr sec);
+typedef int (*virSecurityDomainReserveLabel) (virConnectPtr conn,
+ virDomainObjPtr sec);
typedef int (*virSecurityDomainGetLabel) (virConnectPtr conn,
virDomainObjPtr vm,
virSecurityLabelPtr sec);
@@ -57,6 +59,7 @@ struct _virSecurityDriver {
virSecurityDomainRestoreImageLabel domainRestoreSecurityImageLabel;
virSecurityDomainSetImageLabel domainSetSecurityImageLabel;
virSecurityDomainGenLabel domainGenSecurityLabel;
+ virSecurityDomainReserveLabel domainReserveSecurityLabel;
virSecurityDomainGetLabel domainGetSecurityLabel;
virSecurityDomainSetLabel domainSetSecurityLabel;
virSecurityDomainRestoreLabel domainRestoreSecurityLabel;
diff --git a/src/security_selinux.c b/src/security_selinux.c
--- a/src/security_selinux.c
+++ b/src/security_selinux.c
@@ -216,6 +216,44 @@ done:
}
static int
+SELinuxReserveSecurityLabel(virConnectPtr conn,
+ virDomainObjPtr vm)
+{
+ security_context_t pctx;
+ context_t ctx = NULL;
+ const char *mcs;
+
+ if (getpidcon(vm->pid, &pctx) == -1) {
+ char ebuf[1024];
+ virSecurityReportError(conn, VIR_ERR_ERROR, _("%s: error calling "
+ "getpidcon(): %s"), __func__,
+ virStrerror(errno, ebuf, sizeof ebuf));
+ return -1;
+ }
+
+ ctx = context_new(pctx);
+ VIR_FREE(pctx);
+ if (!ctx)
+ goto err;
+
+ mcs = context_range_get(ctx);
+ if (!mcs)
+ goto err;
+
+ mcsAdd(mcs);
+
+ context_free(ctx);
+
+ return 0;
+
+err:
+ context_free(ctx);
+ return -1;
+}
+
+
+
+static int
SELinuxSecurityDriverProbe(void)
{
return is_selinux_enabled() ? SECURITY_DRIVER_ENABLE : SECURITY_DRIVER_DISABLE;
@@ -422,6 +460,7 @@ virSecurityDriver virSELinuxSecurityDriv
.domainSetSecurityImageLabel = SELinuxSetSecurityImageLabel,
.domainRestoreSecurityImageLabel = SELinuxRestoreSecurityImageLabel,
.domainGenSecurityLabel = SELinuxGenSecurityLabel,
+ .domainReserveSecurityLabel = SELinuxReserveSecurityLabel,
.domainGetSecurityLabel = SELinuxGetSecurityLabel,
.domainRestoreSecurityLabel = SELinuxRestoreSecurityLabel,
.domainSetSecurityLabel = SELinuxSetSecurityLabel,
diff --git a/src/uml_driver.c b/src/uml_driver.c
--- a/src/uml_driver.c
+++ b/src/uml_driver.c
@@ -399,7 +399,7 @@ umlStartup(void) {
¨_driver->domains,
uml_driver->configDir,
uml_driver->autostartDir,
- NULL, NULL) < 0)
+ 0, NULL, NULL) < 0)
goto error;
umlAutostartConfigs(uml_driver);
@@ -438,7 +438,7 @@ umlReload(void) {
¨_driver->domains,
uml_driver->configDir,
uml_driver->autostartDir,
- NULL, NULL);
+ 0, NULL, NULL);
umlAutostartConfigs(uml_driver);
umlDriverUnlock(uml_driver);
--
|: Red Hat, Engineering, London -o-
http://people.redhat.com/berrange/ :|
|:
http://libvirt.org -o-
http://virt-manager.org -o-
http://ovirt.org :|
|:
http://autobuild.org -o-
http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|