From 56a46886ad4335b81daac32c86c77ccbcefa3e23 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 12 Jun 2009 11:38:50 +0000 Subject: [PATCH] Fix re-detection of transient VMs after libvirtd restart --- ChangeLog | 22 ++- src/domain_conf.c | 315 +++++++++++++++++++++++++++++++++++---- src/domain_conf.h | 17 ++- src/libvirt_private.syms | 1 + src/lxc_driver.c | 2 +- src/qemu_conf.c | 190 ----------------------- src/qemu_conf.h | 18 --- src/qemu_driver.c | 168 ++++++++++----------- src/security.h | 3 + src/security_selinux.c | 39 +++++ src/uml_driver.c | 4 +- 11 files changed, 449 insertions(+), 330 deletions(-) diff --git a/ChangeLog b/ChangeLog index a1167ae476..53d8faa4ee 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +Thu Jun 12 12:26:42 BST 2009 Daniel P. Berrange + + 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 * qemud/remote.c: fixing a typo pointed out by Runa Bhattacharjee @@ -6,9 +22,9 @@ Thu Jun 11 16:22:22 CEST 2009 Daniel Veillard * src/node_device_hal.c src/node_device_conf.[ch]: add support for serial number in HAL storage backend, patch by Dave Allan - * docs/schemas/nodedev.rng -tests/nodedevschemadata/storage_serial_3600c0ff000d7a2a5d463ff4902000000.xml: - update the schemas and add a test case, also by Dave Allan + * docs/schemas/nodedev.rng, + tests/nodedevschemadata/storage_serial_3600c0ff000d7a2a5d463ff4902000000.xml: + update the schemas and add a test case, also by Dave Allan Thu Jun 11 15:18:44 GMT 2009 Mark McLoughlin diff --git a/src/domain_conf.c b/src/domain_conf.c index c0c4df9fba..e83f7765dc 100644 --- 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(virDomainObjListPtr vms) 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,30 +556,16 @@ virDomainObjPtr virDomainAssignDef(virConnectPtr conn, 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) { virReportOOMError(conn); - VIR_FREE(domain); return NULL; } + if (!(domain = virDomainObjNew(conn))) + return NULL; + + domain->def = def; + doms->objs[doms->count] = domain; doms->count++; @@ -2623,6 +2635,68 @@ no_memory: 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. */ static void catchXMLError (void *ctx, const char *msg ATTRIBUTE_UNUSED, ...) @@ -2755,6 +2829,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 */ /************************************************************************ @@ -3707,6 +3853,40 @@ char *virDomainDefFormat(virConnectPtr conn, return NULL; } +char *virDomainObjFormat(virConnectPtr conn, + virDomainObjPtr obj, + int flags) +{ + char *config_xml = NULL, *xml = NULL; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + virBufferVSprintf(&buf, "\n", + virDomainStateTypeToString(obj->state), + obj->pid); + virBufferEscapeString(&buf, " \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, "\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 @@ -3782,6 +3962,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, @@ -3835,17 +4036,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 configs in %s", configDir); + if (!(dir = opendir(configDir))) { if (errno == ENOENT) return 0; @@ -3866,14 +4117,24 @@ int virDomainLoadAllConfigs(virConnectPtr conn, /* 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 index bba78609b8..aef1ec457a 100644 --- 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(virConnectPtr conn, 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(virConnectPtr conn, 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 index 0c55684150..6af8432372 100644 --- 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 index f2279a7f7e..6cdcbf3a8a 100644 --- a/src/lxc_driver.c +++ b/src/lxc_driver.c @@ -1190,7 +1190,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 index e84d245de3..22f315ca6a 100644 --- a/src/qemu_conf.c +++ b/src/qemu_conf.c @@ -2888,193 +2888,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, "\n", - virDomainStateTypeToString(vm->state), - vm->pid); - virBufferEscapeString(&buf, " \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, "\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 index b01fe485e2..ad6b0a3974 100644 --- 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 @@ -149,13 +140,4 @@ virDomainDefPtr qemuParseCommandLineString(virConnectPtr conn, virCapsPtr caps, 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 index a7bea7de31..5f94bed7ee 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -120,6 +120,8 @@ static int qemudMonitorCommandExtra(const virDomainObjPtr vm, static int qemudDomainSetMemoryBalloon(virConnectPtr conn, virDomainObjPtr vm, unsigned long newmem); +static int qemudDetectVcpuPIDs(virConnectPtr conn, + virDomainObjPtr vm); static struct qemud_driver *qemu_driver = NULL; @@ -282,79 +284,65 @@ static int qemudOpenMonitor(virConnectPtr conn, const char *monitor, 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 * - * Reconnect running vms to the daemon process + * Try to re-open the resources for live VMs that we care + * about. */ -static int -qemudReconnectVMs(struct qemud_driver *driver) +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; + virDomainObjPtr obj = driver->domains.objs[i]; - 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; + 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); } - - 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); + virDomainObjUnlock(obj); } - return 0; } static int @@ -508,14 +496,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) + 0, NULL, NULL) < 0) goto error; - qemudReconnectVMs(qemu_driver); qemuDriverUnlock(qemu_driver); qemudAutostartConfigs(qemu_driver); @@ -564,7 +563,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); @@ -1329,6 +1328,7 @@ static int qemudStartVMDaemon(virConnectPtr conn, int pos = -1; char ebuf[1024]; char *pidfile = NULL; + int logfile; struct gemudHookData hookData; hookData.conn = conn; @@ -1370,7 +1370,7 @@ static int qemudStartVMDaemon(virConnectPtr conn, 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; @@ -1419,29 +1419,29 @@ static int qemudStartVMDaemon(virConnectPtr conn, 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)); @@ -1449,7 +1449,7 @@ static int qemudStartVMDaemon(virConnectPtr conn, 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); @@ -1499,7 +1499,7 @@ static int qemudStartVMDaemon(virConnectPtr conn, (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 */ @@ -1517,10 +1517,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; } @@ -1547,14 +1545,8 @@ static void qemudShutdownVMDaemon(virConnectPtr conn ATTRIBUTE_UNUSED, 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 */ @@ -2183,7 +2175,7 @@ static int qemudDomainSuspend(virDomainPtr dom) { 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; @@ -2233,7 +2225,7 @@ static int qemudDomainResume(virDomainPtr dom) { 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; @@ -4116,7 +4108,7 @@ static int qemudDomainAttachDevice(virDomainPtr dom, goto cleanup; } - if (!ret && qemudSaveDomainStatus(dom->conn, driver, vm) < 0) + if (!ret && virDomainSaveStatus(dom->conn, driver->stateDir, vm) < 0) ret = -1; cleanup: @@ -4238,7 +4230,7 @@ static int qemudDomainDetachDevice(virDomainPtr dom, 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 index 05bf88c5df..585caa04c6 100644 --- a/src/security.h +++ b/src/security.h @@ -38,6 +38,8 @@ typedef int (*virSecurityDomainSetImageLabel) (virConnectPtr conn, 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 index ac317d791d..4fb7c867f6 100644 --- a/src/security_selinux.c +++ b/src/security_selinux.c @@ -215,6 +215,44 @@ done: 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 SELinuxSecurityDriverProbe(void) { @@ -422,6 +460,7 @@ virSecurityDriver virSELinuxSecurityDriver = { .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 index 98540e31e2..2df342c83a 100644 --- a/src/uml_driver.c +++ b/src/uml_driver.c @@ -394,7 +394,7 @@ umlStartup(void) { ¨_driver->domains, uml_driver->configDir, uml_driver->autostartDir, - NULL, NULL) < 0) + 0, NULL, NULL) < 0) goto error; umlAutostartConfigs(uml_driver); @@ -433,7 +433,7 @@ umlReload(void) { ¨_driver->domains, uml_driver->configDir, uml_driver->autostartDir, - NULL, NULL); + 0, NULL, NULL); umlAutostartConfigs(uml_driver); umlDriverUnlock(uml_driver);