Fix re-detection of transient VMs after libvirtd restart

This commit is contained in:
Daniel P. Berrange 2009-06-12 11:38:50 +00:00
parent 3bdda17adc
commit 56a46886ad
11 changed files with 449 additions and 330 deletions

View File

@ -1,3 +1,19 @@
Thu Jun 12 12:26:42 BST 2009 Daniel P. Berrange <berrange@redhat.com>
Fix re-detection of transient VMs after libvirtd restart
* src/domain_conf.c, src/domain_conf.h, src/libvirt_private.syms:
Extend virDomainLoadAllConfigs to allow for loading of live
state info from XML files. Add APIs to format/parse state info
from virDomainObjPtr to XML.
* src/lxc_driver.c, src/uml_driver.c: Adapt for API change in
virDomainLoadAllConfigs.
* src/qemu_driver.c, src/qemu_conf.c, src/qemu_conf.h: Remove
all code for loading live state files, and use standard APIs
from domain_conf.h.
* src/security.h, src/security_selinux.c: Add API for reserving
an existing in-use MCS context from a running VM detected at
daemon startup.
Thu Jun 11 17:33:43 CEST 2009 Daniel Veillard <veillard@redhat.com> Thu Jun 11 17:33:43 CEST 2009 Daniel Veillard <veillard@redhat.com>
* qemud/remote.c: fixing a typo pointed out by Runa Bhattacharjee * qemud/remote.c: fixing a typo pointed out by Runa Bhattacharjee
@ -6,8 +22,8 @@ Thu Jun 11 16:22:22 CEST 2009 Daniel Veillard <veillard@redhat.com>
* src/node_device_hal.c src/node_device_conf.[ch]: add support * src/node_device_hal.c src/node_device_conf.[ch]: add support
for serial number in HAL storage backend, patch by Dave Allan for serial number in HAL storage backend, patch by Dave Allan
* docs/schemas/nodedev.rng * docs/schemas/nodedev.rng,
tests/nodedevschemadata/storage_serial_3600c0ff000d7a2a5d463ff4902000000.xml: tests/nodedevschemadata/storage_serial_3600c0ff000d7a2a5d463ff4902000000.xml:
update the schemas and add a test case, also by Dave Allan update the schemas and add a test case, also by Dave Allan
Thu Jun 11 15:18:44 GMT 2009 Mark McLoughlin <markmc@redhat.com> Thu Jun 11 15:18:44 GMT 2009 Mark McLoughlin <markmc@redhat.com>

View File

@ -39,6 +39,7 @@
#include "util.h" #include "util.h"
#include "buf.h" #include "buf.h"
#include "c-ctype.h" #include "c-ctype.h"
#include "logging.h"
#define VIR_FROM_THIS VIR_FROM_DOMAIN #define VIR_FROM_THIS VIR_FROM_DOMAIN
@ -511,6 +512,31 @@ void virDomainObjListFree(virDomainObjListPtr vms)
vms->count = 0; 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, virDomainObjPtr virDomainAssignDef(virConnectPtr conn,
virDomainObjListPtr doms, virDomainObjListPtr doms,
const virDomainDefPtr def) const virDomainDefPtr def)
@ -530,30 +556,16 @@ virDomainObjPtr virDomainAssignDef(virConnectPtr conn,
return domain; 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;
domain->def = def;
domain->monitorWatch = -1;
domain->monitor = -1;
if (VIR_REALLOC_N(doms->objs, doms->count + 1) < 0) { if (VIR_REALLOC_N(doms->objs, doms->count + 1) < 0) {
virReportOOMError(conn); virReportOOMError(conn);
VIR_FREE(domain);
return NULL; return NULL;
} }
if (!(domain = virDomainObjNew(conn)))
return NULL;
domain->def = def;
doms->objs[doms->count] = domain; doms->objs[doms->count] = domain;
doms->count++; doms->count++;
@ -2623,6 +2635,68 @@ no_memory:
return NULL; return NULL;
} }
static virDomainObjPtr virDomainObjParseXML(virConnectPtr conn,
virCapsPtr caps,
xmlXPathContextPtr ctxt)
{
char *tmp = NULL;
long val;
xmlNodePtr config;
xmlNodePtr oldnode;
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;
}
oldnode = ctxt->node;
ctxt->node = config;
obj->def = virDomainDefParseXML(conn, caps, ctxt, 0);
ctxt->node = oldnode;
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. */ /* Called from SAX on parsing errors in the XML. */
static void static void
catchXMLError (void *ctx, const char *msg ATTRIBUTE_UNUSED, ...) catchXMLError (void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
@ -2755,6 +2829,78 @@ cleanup:
xmlXPathFreeContext(ctxt); xmlXPathFreeContext(ctxt);
return def; 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 */ #endif /* ! PROXY */
/************************************************************************ /************************************************************************
@ -3707,6 +3853,40 @@ char *virDomainDefFormat(virConnectPtr conn,
return NULL; 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 error;
virBufferAdd(&buf, config_xml, strlen(config_xml));
VIR_FREE(config_xml);
virBufferAddLit(&buf, "</domstatus>\n");
if (virBufferError(&buf))
goto no_memory;
return virBufferContentAndReset(&buf);
no_memory:
virReportOOMError(conn);
error:
xml = virBufferContentAndReset(&buf);
VIR_FREE(xml);
return NULL;
}
#ifndef PROXY #ifndef PROXY
@ -3782,6 +3962,27 @@ cleanup:
return ret; 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, virDomainObjPtr virDomainLoadConfig(virConnectPtr conn,
virCapsPtr caps, virCapsPtr caps,
@ -3835,17 +4036,67 @@ error:
return NULL; 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, int virDomainLoadAllConfigs(virConnectPtr conn,
virCapsPtr caps, virCapsPtr caps,
virDomainObjListPtr doms, virDomainObjListPtr doms,
const char *configDir, const char *configDir,
const char *autostartDir, const char *autostartDir,
int liveStatus,
virDomainLoadConfigNotify notify, virDomainLoadConfigNotify notify,
void *opaque) void *opaque)
{ {
DIR *dir; DIR *dir;
struct dirent *entry; struct dirent *entry;
VIR_INFO("Scanning for configs in %s", configDir);
if (!(dir = opendir(configDir))) { if (!(dir = opendir(configDir))) {
if (errno == ENOENT) if (errno == ENOENT)
return 0; return 0;
@ -3866,6 +4117,16 @@ int virDomainLoadAllConfigs(virConnectPtr conn,
/* NB: ignoring errors, so one malformed config doesn't /* NB: ignoring errors, so one malformed config doesn't
kill the whole process */ kill the whole process */
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, dom = virDomainLoadConfig(conn,
caps, caps,
doms, doms,

View File

@ -515,7 +515,6 @@ struct _virDomainObj {
int monitor; int monitor;
char *monitorpath; char *monitorpath;
int monitorWatch; int monitorWatch;
int logfile;
int pid; int pid;
int state; int state;
@ -589,10 +588,22 @@ virDomainDefPtr virDomainDefParseNode(virConnectPtr conn,
xmlDocPtr doc, xmlDocPtr doc,
xmlNodePtr root, xmlNodePtr root,
int flags); int flags);
virDomainObjPtr virDomainObjParseFile(virConnectPtr conn,
virCapsPtr caps,
const char *filename);
virDomainObjPtr virDomainObjParseNode(virConnectPtr conn,
virCapsPtr caps,
xmlDocPtr xml,
xmlNodePtr root);
#endif #endif
char *virDomainDefFormat(virConnectPtr conn, char *virDomainDefFormat(virConnectPtr conn,
virDomainDefPtr def, virDomainDefPtr def,
int flags); int flags);
char *virDomainObjFormat(virConnectPtr conn,
virDomainObjPtr obj,
int flags);
int virDomainCpuSetParse(virConnectPtr conn, int virDomainCpuSetParse(virConnectPtr conn,
const char **str, const char **str,
@ -615,6 +626,9 @@ int virDomainSaveXML(virConnectPtr conn,
int virDomainSaveConfig(virConnectPtr conn, int virDomainSaveConfig(virConnectPtr conn,
const char *configDir, const char *configDir,
virDomainDefPtr def); virDomainDefPtr def);
int virDomainSaveStatus(virConnectPtr conn,
const char *statusDir,
virDomainObjPtr obj);
typedef void (*virDomainLoadConfigNotify)(virDomainObjPtr dom, typedef void (*virDomainLoadConfigNotify)(virDomainObjPtr dom,
int newDomain, int newDomain,
@ -634,6 +648,7 @@ int virDomainLoadAllConfigs(virConnectPtr conn,
virDomainObjListPtr doms, virDomainObjListPtr doms,
const char *configDir, const char *configDir,
const char *autostartDir, const char *autostartDir,
int liveStatus,
virDomainLoadConfigNotify notify, virDomainLoadConfigNotify notify,
void *opaque); void *opaque);

View File

@ -94,6 +94,7 @@ virDomainObjListFree;
virDomainRemoveInactive; virDomainRemoveInactive;
virDomainSaveXML; virDomainSaveXML;
virDomainSaveConfig; virDomainSaveConfig;
virDomainSaveStatus;
virDomainSoundDefFree; virDomainSoundDefFree;
virDomainSoundModelTypeFromString; virDomainSoundModelTypeFromString;
virDomainSoundModelTypeToString; virDomainSoundModelTypeToString;

View File

@ -1190,7 +1190,7 @@ static int lxcStartup(void)
&lxc_driver->domains, &lxc_driver->domains,
lxc_driver->configDir, lxc_driver->configDir,
lxc_driver->autostartDir, lxc_driver->autostartDir,
NULL, NULL) < 0) 0, NULL, NULL) < 0)
goto cleanup; goto cleanup;
for (i = 0 ; i < lxc_driver->domains.count ; i++) { for (i = 0 ; i < lxc_driver->domains.count ; i++) {

View File

@ -2888,193 +2888,3 @@ cleanup:
return def; 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;
}

View File

@ -92,15 +92,6 @@ struct qemud_driver {
virSecurityDriverPtr securityDriver; 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. */ /* Port numbers used for KVM migration. */
#define QEMUD_MIGRATION_FIRST_PORT 49152 #define QEMUD_MIGRATION_FIRST_PORT 49152
@ -149,13 +140,4 @@ virDomainDefPtr qemuParseCommandLineString(virConnectPtr conn,
virCapsPtr caps, virCapsPtr caps,
const char *args); 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 */ #endif /* __QEMUD_CONF_H */

View File

@ -120,6 +120,8 @@ static int qemudMonitorCommandExtra(const virDomainObjPtr vm,
static int qemudDomainSetMemoryBalloon(virConnectPtr conn, static int qemudDomainSetMemoryBalloon(virConnectPtr conn,
virDomainObjPtr vm, virDomainObjPtr vm,
unsigned long newmem); unsigned long newmem);
static int qemudDetectVcpuPIDs(virConnectPtr conn,
virDomainObjPtr vm);
static struct qemud_driver *qemu_driver = NULL; static struct qemud_driver *qemu_driver = NULL;
@ -282,79 +284,65 @@ static int qemudOpenMonitor(virConnectPtr conn,
const char *monitor, const char *monitor,
int reconnect); int reconnect);
/*
* Open an existing VM's monitor, re-detect VCPU threads
* and re-reserve the security labels in use
*/
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 * qemudReconnectVMs
* *
* Reconnect running vms to the daemon process * Try to re-open the resources for live VMs that we care
* about.
*/ */
static int static void
qemudReconnectVMs(struct qemud_driver *driver) qemuReconnectDomains(struct qemud_driver *driver)
{ {
int i; int i;
for (i = 0 ; i < driver->domains.count ; i++) { for (i = 0 ; i < driver->domains.count ; i++) {
virDomainObjPtr vm = driver->domains.objs[i]; virDomainObjPtr obj = driver->domains.objs[i];
qemudDomainStatusPtr status = NULL;
char *config = NULL;
int rc;
virDomainObjLock(vm); virDomainObjLock(obj);
if ((rc = virFileReadPid(driver->stateDir, vm->def->name, &vm->pid)) == 0) if (qemuReconnectDomain(driver, obj) < 0) {
DEBUG("Found pid %d for '%s'", vm->pid, vm->def->name); /* If we can't get the monitor back, then kill the VM
else * so user has ability to start it again later without
goto next; * danger of ending up running twice */
qemudShutdownVMDaemon(NULL, driver, obj);
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;
} }
virDomainObjUnlock(obj);
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;
} }
static int static int
@ -508,14 +496,25 @@ qemudStartup(void) {
goto error; 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, if (virDomainLoadAllConfigs(NULL,
qemu_driver->caps, qemu_driver->caps,
&qemu_driver->domains, &qemu_driver->domains,
qemu_driver->configDir, qemu_driver->configDir,
qemu_driver->autostartDir, qemu_driver->autostartDir,
NULL, NULL) < 0) 0, NULL, NULL) < 0)
goto error; goto error;
qemudReconnectVMs(qemu_driver);
qemuDriverUnlock(qemu_driver); qemuDriverUnlock(qemu_driver);
qemudAutostartConfigs(qemu_driver); qemudAutostartConfigs(qemu_driver);
@ -564,7 +563,7 @@ qemudReload(void) {
&qemu_driver->domains, &qemu_driver->domains,
qemu_driver->configDir, qemu_driver->configDir,
qemu_driver->autostartDir, qemu_driver->autostartDir,
qemudNotifyLoadDomain, qemu_driver); 0, qemudNotifyLoadDomain, qemu_driver);
qemuDriverUnlock(qemu_driver); qemuDriverUnlock(qemu_driver);
qemudAutostartConfigs(qemu_driver); qemudAutostartConfigs(qemu_driver);
@ -1329,6 +1328,7 @@ static int qemudStartVMDaemon(virConnectPtr conn,
int pos = -1; int pos = -1;
char ebuf[1024]; char ebuf[1024];
char *pidfile = NULL; char *pidfile = NULL;
int logfile;
struct gemudHookData hookData; struct gemudHookData hookData;
hookData.conn = conn; hookData.conn = conn;
@ -1370,7 +1370,7 @@ static int qemudStartVMDaemon(virConnectPtr conn,
goto cleanup; 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; goto cleanup;
emulator = vm->def->emulator; emulator = vm->def->emulator;
@ -1419,29 +1419,29 @@ static int qemudStartVMDaemon(virConnectPtr conn,
tmp = progenv; tmp = progenv;
while (*tmp) { 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"), VIR_WARN(_("Unable to write envv to logfile: %s\n"),
virStrerror(errno, ebuf, sizeof ebuf)); 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"), VIR_WARN(_("Unable to write envv to logfile: %s\n"),
virStrerror(errno, ebuf, sizeof ebuf)); virStrerror(errno, ebuf, sizeof ebuf));
tmp++; tmp++;
} }
tmp = argv; tmp = argv;
while (*tmp) { 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"), VIR_WARN(_("Unable to write argv to logfile: %s\n"),
virStrerror(errno, ebuf, sizeof ebuf)); 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"), VIR_WARN(_("Unable to write argv to logfile: %s\n"),
virStrerror(errno, ebuf, sizeof ebuf)); virStrerror(errno, ebuf, sizeof ebuf));
tmp++; tmp++;
} }
if (safewrite(vm->logfile, "\n", 1) < 0) if (safewrite(logfile, "\n", 1) < 0)
VIR_WARN(_("Unable to write argv to logfile: %s\n"), VIR_WARN(_("Unable to write argv to logfile: %s\n"),
virStrerror(errno, ebuf, sizeof ebuf)); 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"), VIR_WARN(_("Unable to seek to end of logfile: %s\n"),
virStrerror(errno, ebuf, sizeof ebuf)); virStrerror(errno, ebuf, sizeof ebuf));
@ -1449,7 +1449,7 @@ static int qemudStartVMDaemon(virConnectPtr conn,
FD_SET(tapfds[i], &keepfd); FD_SET(tapfds[i], &keepfd);
ret = virExecDaemonize(conn, argv, progenv, &keepfd, &child, ret = virExecDaemonize(conn, argv, progenv, &keepfd, &child,
stdin_fd, &vm->logfile, &vm->logfile, stdin_fd, &logfile, &logfile,
VIR_EXEC_NONBLOCK, VIR_EXEC_NONBLOCK,
qemudSecurityHook, &hookData, qemudSecurityHook, &hookData,
pidfile); pidfile);
@ -1499,7 +1499,7 @@ static int qemudStartVMDaemon(virConnectPtr conn,
(qemudInitCpus(conn, vm, migrateFrom) < 0) || (qemudInitCpus(conn, vm, migrateFrom) < 0) ||
(qemudInitPasswords(conn, driver, vm) < 0) || (qemudInitPasswords(conn, driver, vm) < 0) ||
(qemudDomainSetMemoryBalloon(conn, vm, vm->def->memory) < 0) || (qemudDomainSetMemoryBalloon(conn, vm, vm->def->memory) < 0) ||
(qemudSaveDomainStatus(conn, qemu_driver, vm) < 0)) { (virDomainSaveStatus(conn, driver->stateDir, vm) < 0)) {
qemudShutdownVMDaemon(conn, driver, vm); qemudShutdownVMDaemon(conn, driver, vm);
ret = -1; ret = -1;
/* No need for 'goto cleanup' now since qemudShutdownVMDaemon does enough */ /* No need for 'goto cleanup' now since qemudShutdownVMDaemon does enough */
@ -1517,10 +1517,8 @@ cleanup:
vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC && vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
vm->def->graphics[0]->data.vnc.autoport) vm->def->graphics[0]->data.vnc.autoport)
vm->def->graphics[0]->data.vnc.port = -1; vm->def->graphics[0]->data.vnc.port = -1;
if (vm->logfile != -1) { if (logfile != -1)
close(vm->logfile); close(logfile);
vm->logfile = -1;
}
vm->def->id = -1; vm->def->id = -1;
return -1; return -1;
} }
@ -1547,14 +1545,8 @@ static void qemudShutdownVMDaemon(virConnectPtr conn ATTRIBUTE_UNUSED,
vm->monitorWatch = -1; 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) if (vm->monitor != -1)
close(vm->monitor); close(vm->monitor);
vm->logfile = -1;
vm->monitor = -1; vm->monitor = -1;
/* shut it off for sure */ /* shut it off for sure */
@ -2183,7 +2175,7 @@ static int qemudDomainSuspend(virDomainPtr dom) {
VIR_DOMAIN_EVENT_SUSPENDED_PAUSED); VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
VIR_FREE(info); VIR_FREE(info);
} }
if (qemudSaveDomainStatus(dom->conn, driver, vm) < 0) if (virDomainSaveStatus(dom->conn, driver->stateDir, vm) < 0)
goto cleanup; goto cleanup;
ret = 0; ret = 0;
@ -2233,7 +2225,7 @@ static int qemudDomainResume(virDomainPtr dom) {
VIR_DOMAIN_EVENT_RESUMED_UNPAUSED); VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
VIR_FREE(info); VIR_FREE(info);
} }
if (qemudSaveDomainStatus(dom->conn, driver, vm) < 0) if (virDomainSaveStatus(dom->conn, driver->stateDir, vm) < 0)
goto cleanup; goto cleanup;
ret = 0; ret = 0;
@ -4116,7 +4108,7 @@ static int qemudDomainAttachDevice(virDomainPtr dom,
goto cleanup; goto cleanup;
} }
if (!ret && qemudSaveDomainStatus(dom->conn, driver, vm) < 0) if (!ret && virDomainSaveStatus(dom->conn, driver->stateDir, vm) < 0)
ret = -1; ret = -1;
cleanup: cleanup:
@ -4238,7 +4230,7 @@ static int qemudDomainDetachDevice(virDomainPtr dom,
qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT, qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
"%s", _("only SCSI or virtio disk device can be detached dynamically")); "%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; ret = -1;
cleanup: cleanup:

View File

@ -38,6 +38,8 @@ typedef int (*virSecurityDomainSetImageLabel) (virConnectPtr conn,
virDomainDiskDefPtr disk); virDomainDiskDefPtr disk);
typedef int (*virSecurityDomainGenLabel) (virConnectPtr conn, typedef int (*virSecurityDomainGenLabel) (virConnectPtr conn,
virDomainObjPtr sec); virDomainObjPtr sec);
typedef int (*virSecurityDomainReserveLabel) (virConnectPtr conn,
virDomainObjPtr sec);
typedef int (*virSecurityDomainGetLabel) (virConnectPtr conn, typedef int (*virSecurityDomainGetLabel) (virConnectPtr conn,
virDomainObjPtr vm, virDomainObjPtr vm,
virSecurityLabelPtr sec); virSecurityLabelPtr sec);
@ -57,6 +59,7 @@ struct _virSecurityDriver {
virSecurityDomainRestoreImageLabel domainRestoreSecurityImageLabel; virSecurityDomainRestoreImageLabel domainRestoreSecurityImageLabel;
virSecurityDomainSetImageLabel domainSetSecurityImageLabel; virSecurityDomainSetImageLabel domainSetSecurityImageLabel;
virSecurityDomainGenLabel domainGenSecurityLabel; virSecurityDomainGenLabel domainGenSecurityLabel;
virSecurityDomainReserveLabel domainReserveSecurityLabel;
virSecurityDomainGetLabel domainGetSecurityLabel; virSecurityDomainGetLabel domainGetSecurityLabel;
virSecurityDomainSetLabel domainSetSecurityLabel; virSecurityDomainSetLabel domainSetSecurityLabel;
virSecurityDomainRestoreLabel domainRestoreSecurityLabel; virSecurityDomainRestoreLabel domainRestoreSecurityLabel;

View File

@ -215,6 +215,44 @@ done:
return rc; return rc;
} }
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 static int
SELinuxSecurityDriverProbe(void) SELinuxSecurityDriverProbe(void)
{ {
@ -422,6 +460,7 @@ virSecurityDriver virSELinuxSecurityDriver = {
.domainSetSecurityImageLabel = SELinuxSetSecurityImageLabel, .domainSetSecurityImageLabel = SELinuxSetSecurityImageLabel,
.domainRestoreSecurityImageLabel = SELinuxRestoreSecurityImageLabel, .domainRestoreSecurityImageLabel = SELinuxRestoreSecurityImageLabel,
.domainGenSecurityLabel = SELinuxGenSecurityLabel, .domainGenSecurityLabel = SELinuxGenSecurityLabel,
.domainReserveSecurityLabel = SELinuxReserveSecurityLabel,
.domainGetSecurityLabel = SELinuxGetSecurityLabel, .domainGetSecurityLabel = SELinuxGetSecurityLabel,
.domainRestoreSecurityLabel = SELinuxRestoreSecurityLabel, .domainRestoreSecurityLabel = SELinuxRestoreSecurityLabel,
.domainSetSecurityLabel = SELinuxSetSecurityLabel, .domainSetSecurityLabel = SELinuxSetSecurityLabel,

View File

@ -394,7 +394,7 @@ umlStartup(void) {
&uml_driver->domains, &uml_driver->domains,
uml_driver->configDir, uml_driver->configDir,
uml_driver->autostartDir, uml_driver->autostartDir,
NULL, NULL) < 0) 0, NULL, NULL) < 0)
goto error; goto error;
umlAutostartConfigs(uml_driver); umlAutostartConfigs(uml_driver);
@ -433,7 +433,7 @@ umlReload(void) {
&uml_driver->domains, &uml_driver->domains,
uml_driver->configDir, uml_driver->configDir,
uml_driver->autostartDir, uml_driver->autostartDir,
NULL, NULL); 0, NULL, NULL);
umlAutostartConfigs(uml_driver); umlAutostartConfigs(uml_driver);
umlDriverUnlock(uml_driver); umlDriverUnlock(uml_driver);