[libvirt] PATCH: Fix redetection of transient QEMU VMs on daemon restarts

Daniel P. Berrange berrange at redhat.com
Wed Jun 3 16:42:20 UTC 2009


On Tue, Jun 02, 2009 at 03:55:27PM +0200, Daniel Veillard wrote:
> On Wed, May 27, 2009 at 04:58:44PM +0100, Daniel P. Berrange wrote:
> [...]
> > +                                            xmlXPathContextPtr ctxt)
> > +{
> > +    char *tmp = NULL;
> > +    long val;
> > +    xmlNodePtr config;
> > +    xmlNodePtr oldctxt;
> 
>   I would s/oldctxt/oldnode/ as what is saved is really only the old
>   XPath current node not the context itself.

Good idea, changed this.

> 
> [...]
> > +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)))
> 
>            Hum we are leaking the buffer content here.
> 
> > +        goto cleanup;
> > +
> > +    virBufferAdd(&buf, config_xml, strlen(config_xml));
> > +    virBufferAddLit(&buf, "</domstatus>\n");
> > +
> > +    xml = virBufferContentAndReset(&buf);
> > +cleanup:
> > +    VIR_FREE(config_xml);
> > +    return xml;
> > +
> > +}


Yes, and also forgetting to check virBufferError() to report OOM. Fixed
the cleanup in this function now.


> > +        virDomainObjUnlock(obj);
> > +        virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
> > +                             _("unexpected domain %s already exists"), obj->def->name);
> 
> 
>   let's wrap to 80 columns
> 
> [...]
> > +/*
> > + * Open an existing VM's monitor, and re-detect VCPUs
> > + * threads
> 
>   maybe update the comment about the security labels too, especially as
> this is a bit arcane.

Updated these two.

> > @@ -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;
> >  }
> 
>    Hum, do we still use vm->logfile field then ? Maybe I didn't see the
> place where it was removed from the structure.

Yep, this field in the struct has been killed off - see domain_conf.h

Here's the updated patch in full

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++;
@@ -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 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 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
 
@@ -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,68 @@ 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;
@@ -3866,14 +4118,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
@@ -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
--- a/src/qemu_conf.c
+++ b/src/qemu_conf.c
@@ -2798,193 +2798,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
@@ -143,13 +134,4 @@ virDomainDefPtr qemuParseCommandLineStri
                                            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
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -120,6 +120,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;
 
@@ -282,79 +284,65 @@ static int qemudOpenMonitor(virConnectPt
                             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
- */
-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
@@ -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)
-        goto error;
-    qemudReconnectVMs(qemu_driver);
+                                0, NULL, NULL) < 0)
+        goto error;
     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(virConnect
     int pos = -1;
     char ebuf[1024];
     char *pidfile = NULL;
+    int logfile;
 
     struct gemudHookData hookData;
     hookData.conn = conn;
@@ -1370,7 +1370,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;
@@ -1419,29 +1419,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));
 
@@ -1449,7 +1449,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);
@@ -1499,7 +1499,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 */
@@ -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(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 */
@@ -2183,7 +2175,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;
 
@@ -2233,7 +2225,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;
 
@@ -4116,7 +4108,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:
@@ -4238,7 +4230,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
@@ -394,7 +394,7 @@ umlStartup(void) {
                                 &uml_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) {
                             &uml_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 :|




More information about the libvir-list mailing list