[libvirt] [PATCH] Qemu driver: Support network-backed pflash disks.

Prerna Saxena saxenap.ltc at gmail.com
Fri Apr 20 08:59:02 UTC 2018


So far libvirt domain XML only allows local filepaths that can be
used to specify a loader element or its matching NVRAM disk.
Given that Vms may themselves move across hypervisor hosts, it should be
possible to allocate loaders/NVRAM disks on network storage for
uninterrupted access.

Signed-off-by: Prerna Saxena <saxenap.ltc at gmail.com>
---
 docs/schemas/domaincommon.rng   | 108 +++++++++++++++++++----
 src/conf/domain_conf.c          | 188 ++++++++++++++++++++++++++++++++++++----
 src/conf/domain_conf.h          |   7 +-
 src/qemu/qemu_cgroup.c          |  13 ++-
 src/qemu/qemu_command.c         |  21 +++--
 src/qemu/qemu_domain.c          |  16 ++--
 src/qemu/qemu_driver.c          |   7 +-
 src/qemu/qemu_parse_command.c   |  30 ++++++-
 src/qemu/qemu_process.c         |  33 ++++---
 src/security/security_dac.c     |   6 +-
 src/security/security_selinux.c |   6 +-
 11 files changed, 361 insertions(+), 74 deletions(-)

diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 4cab55f..32db395 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -276,7 +276,42 @@
                 </choice>
               </attribute>
             </optional>
-            <ref name="absFilePath"/>
+            <optional>
+              <attribute name="backing">
+                <choice>
+                  <value>file</value>
+                  <value>network</value>
+                </choice>
+              </attribute>
+            </optional>
+            <optional>
+              <choice>
+                 <group>
+                  <ref name="absFilePath"/>
+                 </group>
+                 <group>
+                  <ref name="diskSourceFileElement"/>
+                 </group>
+                 <group>
+                  <ref name="diskSourceNetworkProtocolNBD"/>
+                 </group>
+                 <group>
+                  <ref name="diskSourceNetworkProtocolGluster"/>
+                 </group>
+                 <group>
+                  <ref name="diskSourceNetworkProtocolRBD"/>
+                 </group>
+                 <group>
+                  <ref name="diskSourceNetworkProtocolISCSI"/>
+                 </group>
+                 <group>
+                  <ref name="diskSourceNetworkProtocolHTTP"/>
+                 </group>
+                 <group>
+                  <ref name="diskSourceNetworkProtocolSimple"/>
+                 </group>
+              </choice>
+            </optional>
           </element>
         </optional>
         <optional>
@@ -287,7 +322,40 @@
               </attribute>
             </optional>
             <optional>
-              <ref name="absFilePath"/>
+              <attribute name="backing">
+                <choice>
+                  <value>file</value>
+                  <value>network</value>
+                </choice>
+              </attribute>
+            </optional>
+            <optional>
+              <choice>
+                 <group>
+                  <ref name="absFilePath"/>
+                 </group>
+                 <group>
+                  <ref name="diskSourceFileElement"/>
+                 </group>
+                 <group>
+                  <ref name="diskSourceNetworkProtocolNBD"/>
+                 </group>
+                 <group>
+                  <ref name="diskSourceNetworkProtocolGluster"/>
+                 </group>
+                 <group>
+                  <ref name="diskSourceNetworkProtocolRBD"/>
+                 </group>
+                 <group>
+                  <ref name="diskSourceNetworkProtocolISCSI"/>
+                 </group>
+                 <group>
+                  <ref name="diskSourceNetworkProtocolHTTP"/>
+                 </group>
+                 <group>
+                  <ref name="diskSourceNetworkProtocolSimple"/>
+                 </group>
+              </choice>
             </optional>
           </element>
         </optional>
@@ -1494,25 +1562,29 @@
       </attribute>
     </optional>
     <optional>
-      <element name="source">
-        <optional>
-          <attribute name="file">
-            <ref name="absFilePath"/>
-          </attribute>
-        </optional>
-        <optional>
-          <ref name="storageStartupPolicy"/>
-        </optional>
-        <optional>
-          <ref name="encryption"/>
-        </optional>
-        <zeroOrMore>
-          <ref name='devSeclabel'/>
-        </zeroOrMore>
-      </element>
+      <ref name='diskSourceFileElement'/>
     </optional>
   </define>
 
+  <define name="diskSourceFileElement">
+    <element name="source">
+      <optional>
+        <attribute name="file">
+          <ref name="absFilePath"/>
+        </attribute>
+      </optional>
+      <optional>
+        <ref name="storageStartupPolicy"/>
+      </optional>
+      <optional>
+        <ref name="encryption"/>
+      </optional>
+      <zeroOrMore>
+        <ref name='devSeclabel'/>
+      </zeroOrMore>
+    </element>
+  </define>
+
   <define name="diskSourceBlock">
     <attribute name="type">
       <value>block</value>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 35666c1..c80f9d9 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -2883,8 +2883,8 @@ virDomainLoaderDefFree(virDomainLoaderDefPtr loader)
     if (!loader)
         return;
 
-    VIR_FREE(loader->path);
-    VIR_FREE(loader->nvram);
+    virStorageSourceFree(loader->loader_src);
+    virStorageSourceFree(loader->nvram);
     VIR_FREE(loader->templt);
     VIR_FREE(loader);
 }
@@ -17961,17 +17961,59 @@ virDomainDefMaybeAddHostdevSCSIcontroller(virDomainDefPtr def)
 
 static int
 virDomainLoaderDefParseXML(xmlNodePtr node,
+                           xmlXPathContextPtr ctxt,
                            virDomainLoaderDefPtr loader)
 {
     int ret = -1;
     char *readonly_str = NULL;
     char *secure_str = NULL;
     char *type_str = NULL;
+    char *tmp = NULL;
+    xmlNodePtr cur;
+    xmlXPathContextPtr cur_ctxt = ctxt;
+
+    if (VIR_ALLOC(loader->loader_src)) {
+        goto cleanup;
+    }
+    loader->loader_src->type = VIR_STORAGE_TYPE_LAST;
 
     readonly_str = virXMLPropString(node, "readonly");
     secure_str = virXMLPropString(node, "secure");
     type_str = virXMLPropString(node, "type");
-    loader->path = (char *) xmlNodeGetContent(node);
+
+    if ((tmp = virXMLPropString(node, "backing")) &&
+        (loader->loader_src->type = virStorageTypeFromString(tmp)) <= 0) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("unknown loader type '%s'"), tmp);
+        goto cleanup;
+    }
+    VIR_FREE(tmp);
+
+    for (cur = node->children; cur != NULL; cur = cur->next) {
+        if (cur->type != XML_ELEMENT_NODE) {
+            continue;
+        }
+
+        if (virXMLNodeNameEqual(cur, "source")) {
+            if (virDomainStorageSourceParse(cur, cur_ctxt, loader->loader_src, 0) < 0) {
+                virReportError(VIR_ERR_XML_DETAIL,
+                               _("Error parsing Loader source element"));
+                goto cleanup;
+            }
+            break;
+        }
+    }
+
+    /* Old-style absolute path found ? */
+    if (loader->loader_src->type == VIR_STORAGE_TYPE_LAST) {
+        if (!(loader->loader_src->path = (char *) xmlNodeGetContent(node))) {
+            virReportError(VIR_ERR_XML_ERROR, "%s",
+                           _("missing loader source"));
+            goto cleanup;
+        } else {
+            loader->loader_src->type = VIR_STORAGE_TYPE_FILE;
+        }
+    }
 
     if (readonly_str &&
         (loader->readonly = virTristateBoolTypeFromString(readonly_str)) <= 0) {
@@ -17998,13 +18040,78 @@ virDomainLoaderDefParseXML(xmlNodePtr node,
     }
 
     ret = 0;
- cleanup:
+    goto exit;
+cleanup:
+    if (loader->loader_src)
+      VIR_FREE(loader->loader_src);
+exit:
     VIR_FREE(readonly_str);
     VIR_FREE(secure_str);
     VIR_FREE(type_str);
+
     return ret;
 }
 
+static int
+virDomainLoaderNvramDefParseXML(xmlNodePtr node,
+                           xmlXPathContextPtr ctxt,
+                           virDomainLoaderDefPtr loader)
+{
+    int ret = -1;
+    char *tmp = NULL;
+    xmlNodePtr cur;
+
+    if (VIR_ALLOC(loader->nvram)) {
+        goto cleanup;
+    }
+
+    loader->nvram->type = VIR_STORAGE_TYPE_LAST;
+
+    if ((tmp = virXMLPropString(node, "backing")) &&
+        (loader->nvram->type = virStorageTypeFromString(tmp)) <= 0) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("unknown nvram type '%s'"), tmp);
+        goto cleanup;
+    }
+    VIR_FREE(tmp);
+
+    for (cur = node->children; cur != NULL; cur = cur->next) {
+        if (cur->type != XML_ELEMENT_NODE) {
+            continue;
+        }
+
+        if (virXMLNodeNameEqual(cur, "template")) {
+            loader->templt = virXPathString("string(./os/nvram[1]/@template)", ctxt);
+            continue;
+        }
+
+        if (virXMLNodeNameEqual(cur, "source")) {
+            if (virDomainStorageSourceParse(cur, ctxt, loader->nvram, 0) < 0) {
+                virReportError(VIR_ERR_XML_DETAIL,
+                               _("Error parsing nvram source element"));
+                goto cleanup;
+            }
+            ret = 0;
+        }
+    }
+
+    if (loader->nvram->type == VIR_STORAGE_TYPE_LAST) {
+        if (!(loader->nvram->path = (char *) xmlNodeGetContent(node))) {
+            virReportError(VIR_ERR_XML_ERROR, "%s",
+                           _("missing nvram source"));
+            goto cleanup;
+        } else {
+            loader->nvram->type = VIR_STORAGE_TYPE_FILE;
+            ret = 0;
+        }
+    }
+    return ret;
+
+cleanup:
+    if (loader->nvram)
+      VIR_FREE(loader->nvram);
+    return ret;
+}
 
 static virBitmapPtr
 virDomainSchedulerParse(xmlNodePtr node,
@@ -18397,11 +18504,15 @@ virDomainDefParseBootOptions(virDomainDefPtr def,
             if (VIR_ALLOC(def->os.loader) < 0)
                 goto error;
 
-            if (virDomainLoaderDefParseXML(loader_node, def->os.loader) < 0)
+            def->os.loader->loader_src = NULL;
+            def->os.loader->nvram = NULL;
+            if (virDomainLoaderDefParseXML(loader_node, ctxt, def->os.loader) < 0)
                 goto error;
 
-            def->os.loader->nvram = virXPathString("string(./os/nvram[1])", ctxt);
-            def->os.loader->templt = virXPathString("string(./os/nvram[1]/@template)", ctxt);
+            if ((loader_node = virXPathNode("./os/nvram[1]", ctxt)) &&
+                (virDomainLoaderNvramDefParseXML(loader_node, ctxt,
+                                                 def->os.loader) < 0))
+                    goto error;
         }
     }
 
@@ -26070,11 +26181,19 @@ virDomainHugepagesFormat(virBufferPtr buf,
 
 static void
 virDomainLoaderDefFormat(virBufferPtr buf,
-                         virDomainLoaderDefPtr loader)
+                         virDomainLoaderDefPtr loader,
+                         unsigned int flags)
 {
     const char *readonly = virTristateBoolTypeToString(loader->readonly);
     const char *secure = virTristateBoolTypeToString(loader->secure);
     const char *type = virDomainLoaderTypeToString(loader->type);
+    const char *backing = NULL;
+
+    virBuffer attrBuf = VIR_BUFFER_INITIALIZER;
+    virBuffer childBuf = VIR_BUFFER_INITIALIZER;
+
+    virBufferSetChildIndent(&childBuf, buf);
+
 
     virBufferAddLit(buf, "<loader");
 
@@ -26084,17 +26203,54 @@ virDomainLoaderDefFormat(virBufferPtr buf,
     if (loader->secure)
         virBufferAsprintf(buf, " secure='%s'", secure);
 
-    virBufferAsprintf(buf, " type='%s'>", type);
+    virBufferAsprintf(buf, " type='%s'", type);
+    if (loader->loader_src &&
+        loader->loader_src->type != VIR_STORAGE_TYPE_LAST) {
+        if (virDomainStorageSourceFormat(&attrBuf, &childBuf, loader->loader_src,
+                                     flags, 0) < 0)
+            goto cleanup;
+
+        backing = virStorageTypeToString(loader->loader_src->type);
+        virBufferAsprintf(buf, " backing='%s'>", backing);
+
+        if (virXMLFormatElement(buf, "source", &attrBuf, &childBuf) < 0)
+            goto cleanup;
+    } else {
+        virBufferAddLit(buf, ">\n");
+    }
+
+    virBufferAddLit(buf, "</loader>\n");
 
-    virBufferEscapeString(buf, "%s</loader>\n", loader->path);
     if (loader->nvram || loader->templt) {
-        virBufferAddLit(buf, "<nvram");
-        virBufferEscapeString(buf, " template='%s'", loader->templt);
+        ignore_value(virBufferContentAndReset(&attrBuf));
+        ignore_value(virBufferContentAndReset(&childBuf));
+        virBufferSetChildIndent(&childBuf, buf);
+
         if (loader->nvram)
-            virBufferEscapeString(buf, ">%s</nvram>\n", loader->nvram);
-        else
-            virBufferAddLit(buf, "/>\n");
+            backing = virStorageTypeToString(loader->nvram->type);
+
+        virBufferAddLit(buf, "<nvram");
+        if (loader->templt) {
+            virBufferEscapeString(buf, " template='%s'", loader->templt);
+        }
+        if (loader->nvram &&
+            (virDomainStorageSourceFormat(&attrBuf, &childBuf,
+                                         loader->nvram, flags, 0) < 0)) {
+            virBufferAddLit(buf, ">\n</nvram>\n");
+            goto cleanup;
+        }
+
+        virBufferEscapeString(buf, " backing='%s'>", backing);
+        if (virXMLFormatElement(buf, "source", &attrBuf, &childBuf) < 0) {
+            virBufferAddLit(buf, "</nvram>\n");
+            goto cleanup;
+        }
+        virBufferAddLit(buf, "</nvram>\n");
     }
+cleanup:
+    virBufferFreeAndReset(&attrBuf);
+    virBufferFreeAndReset(&childBuf);
+    return;
 }
 
 static void
@@ -26757,7 +26913,7 @@ virDomainDefFormatInternal(virDomainDefPtr def,
         virBufferAsprintf(buf, "<initgroup>%s</initgroup>\n", def->os.initgroup);
 
     if (def->os.loader)
-        virDomainLoaderDefFormat(buf, def->os.loader);
+        virDomainLoaderDefFormat(buf, def->os.loader, flags);
     virBufferEscapeString(buf, "<kernel>%s</kernel>\n",
                           def->os.kernel);
     virBufferEscapeString(buf, "<initrd>%s</initrd>\n",
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 3c7eccb..50d5ac3 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1857,14 +1857,17 @@ typedef enum {
 
 VIR_ENUM_DECL(virDomainLoader)
 
+struct _virStorageSource;
+typedef struct _virStorageSource* virStorageSourcePtr;
+
 typedef struct _virDomainLoaderDef virDomainLoaderDef;
 typedef virDomainLoaderDef *virDomainLoaderDefPtr;
 struct _virDomainLoaderDef {
-    char *path;
+    virStorageSourcePtr loader_src;
     int readonly;   /* enum virTristateBool */
     virDomainLoader type;
     int secure;     /* enum virTristateBool */
-    char *nvram;    /* path to non-volatile RAM */
+    virStorageSourcePtr nvram;  /* path to non-voliatile RAM */
     char *templt;   /* user override of path to master nvram */
 };
 
diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c
index d88eb78..aa5d071 100644
--- a/src/qemu/qemu_cgroup.c
+++ b/src/qemu/qemu_cgroup.c
@@ -580,16 +580,21 @@ qemuSetupMemoryCgroup(virDomainObjPtr vm)
 static int
 qemuSetupFirmwareCgroup(virDomainObjPtr vm)
 {
+    virStorageSourcePtr src = NULL;
+
     if (!vm->def->os.loader)
         return 0;
 
-    if (vm->def->os.loader->path &&
-        qemuSetupImagePathCgroup(vm, vm->def->os.loader->path,
-                                 vm->def->os.loader->readonly == VIR_TRISTATE_BOOL_YES) < 0)
+    src = vm->def->os.loader->loader_src;
+    if (src->path &&
+        src->type == VIR_STORAGE_TYPE_FILE &&
+        qemuSetupImagePathCgroup(vm, src->path,
+                                 src->readonly == VIR_TRISTATE_BOOL_YES) < 0)
         return -1;
 
     if (vm->def->os.loader->nvram &&
-        qemuSetupImagePathCgroup(vm, vm->def->os.loader->nvram, false) < 0)
+        vm->def->os.loader->nvram->type == VIR_STORAGE_TYPE_FILE &&
+        qemuSetupImagePathCgroup(vm, vm->def->os.loader->nvram->path, false) < 0)
         return -1;
 
     return 0;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 238c6ed..279a06c 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -9293,6 +9293,7 @@ qemuBuildDomainLoaderCommandLine(virCommandPtr cmd,
     virDomainLoaderDefPtr loader = def->os.loader;
     virBuffer buf = VIR_BUFFER_INITIALIZER;
     int unit = 0;
+    char *source = NULL;
 
     if (!loader)
         return;
@@ -9300,7 +9301,7 @@ qemuBuildDomainLoaderCommandLine(virCommandPtr cmd,
     switch ((virDomainLoader) loader->type) {
     case VIR_DOMAIN_LOADER_TYPE_ROM:
         virCommandAddArg(cmd, "-bios");
-        virCommandAddArg(cmd, loader->path);
+        virCommandAddArg(cmd, loader->loader_src->path);
         break;
 
     case VIR_DOMAIN_LOADER_TYPE_PFLASH:
@@ -9312,9 +9313,14 @@ qemuBuildDomainLoaderCommandLine(virCommandPtr cmd,
                                  NULL);
         }
 
+        if (qemuGetDriveSourceString(loader->loader_src, NULL, &source) < 0)
+            break;
+
         virBufferAddLit(&buf, "file=");
-        virQEMUBuildBufferEscapeComma(&buf, loader->path);
-        virBufferAsprintf(&buf, ",if=pflash,format=raw,unit=%d", unit);
+        virQEMUBuildBufferEscapeComma(&buf, source);
+        free(source);
+        virBufferAsprintf(&buf, ",if=pflash,format=raw,unit=%d",
+                          unit);
         unit++;
 
         if (loader->readonly) {
@@ -9327,9 +9333,14 @@ qemuBuildDomainLoaderCommandLine(virCommandPtr cmd,
 
         if (loader->nvram) {
             virBufferFreeAndReset(&buf);
+            if (qemuGetDriveSourceString(loader->nvram, NULL, &source) < 0)
+                break;
+
             virBufferAddLit(&buf, "file=");
-            virQEMUBuildBufferEscapeComma(&buf, loader->nvram);
-            virBufferAsprintf(&buf, ",if=pflash,format=raw,unit=%d", unit);
+            virQEMUBuildBufferEscapeComma(&buf, source);
+            virBufferAsprintf(&buf, ",if=pflash,format=raw,unit=%d",
+                              unit);
+            unit++;
 
             virCommandAddArg(cmd, "-drive");
             virCommandAddArgBuffer(cmd, &buf);
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 21897cb..c1cb751 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -3312,8 +3312,10 @@ qemuDomainDefPostParse(virDomainDefPtr def,
     if (def->os.loader &&
         def->os.loader->type == VIR_DOMAIN_LOADER_TYPE_PFLASH &&
         def->os.loader->readonly == VIR_TRISTATE_SWITCH_ON &&
-        !def->os.loader->nvram) {
-        if (virAsprintf(&def->os.loader->nvram, "%s/%s_VARS.fd",
+        def->os.loader->nvram &&
+        def->os.loader->nvram->type == VIR_STORAGE_TYPE_FILE &&
+        !def->os.loader->nvram->path) {
+        if (virAsprintf(&def->os.loader->nvram->path, "%s/%s_VARS.fd",
                         cfg->nvramDir, def->name) < 0)
             goto cleanup;
     }
@@ -10477,19 +10479,21 @@ qemuDomainSetupLoader(virQEMUDriverConfigPtr cfg ATTRIBUTE_UNUSED,
 
     VIR_DEBUG("Setting up loader");
 
-    if (loader) {
+    if (loader && loader->loader_src &&
+        loader->loader_src->type == VIR_STORAGE_TYPE_FILE) {
         switch ((virDomainLoader) loader->type) {
         case VIR_DOMAIN_LOADER_TYPE_ROM:
-            if (qemuDomainCreateDevice(loader->path, data, false) < 0)
+            if (qemuDomainCreateDevice(loader->loader_src->path, data, false) < 0)
                 goto cleanup;
             break;
 
         case VIR_DOMAIN_LOADER_TYPE_PFLASH:
-            if (qemuDomainCreateDevice(loader->path, data, false) < 0)
+            if (qemuDomainCreateDevice(loader->loader_src->path, data, false) < 0)
                 goto cleanup;
 
             if (loader->nvram &&
-                qemuDomainCreateDevice(loader->nvram, data, false) < 0)
+                loader->nvram->type == VIR_STORAGE_TYPE_FILE &&
+                qemuDomainCreateDevice(loader->nvram->path, data, false) < 0)
                 goto cleanup;
             break;
 
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 5673d9f..ce6339d 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -7542,12 +7542,13 @@ qemuDomainUndefineFlags(virDomainPtr dom,
 
     if (vm->def->os.loader &&
         vm->def->os.loader->nvram &&
-        virFileExists(vm->def->os.loader->nvram)) {
+        vm->def->os.loader->nvram->type == VIR_STORAGE_TYPE_FILE &&
+        virFileExists(vm->def->os.loader->nvram->path)) {
         if ((flags & VIR_DOMAIN_UNDEFINE_NVRAM)) {
-            if (unlink(vm->def->os.loader->nvram) < 0) {
+            if (unlink(vm->def->os.loader->nvram->path) < 0) {
                 virReportSystemError(errno,
                                      _("failed to remove nvram: %s"),
-                                     vm->def->os.loader->nvram);
+                                     vm->def->os.loader->nvram->path);
                 goto endjob;
             }
         } else if (!(flags & VIR_DOMAIN_UNDEFINE_KEEP_NVRAM)) {
diff --git a/src/qemu/qemu_parse_command.c b/src/qemu/qemu_parse_command.c
index 0ce9632..2a0b200 100644
--- a/src/qemu/qemu_parse_command.c
+++ b/src/qemu/qemu_parse_command.c
@@ -650,6 +650,7 @@ qemuParseCommandLineDisk(virDomainXMLOptionPtr xmlopt,
     int idx = -1;
     int busid = -1;
     int unitid = -1;
+    bool is_firmware = false;
 
     if (qemuParseKeywords(val,
                           &keywords,
@@ -772,6 +773,9 @@ qemuParseCommandLineDisk(virDomainXMLOptionPtr xmlopt,
                 def->bus = VIR_DOMAIN_DISK_BUS_VIRTIO;
             } else if (STREQ(values[i], "xen")) {
                 def->bus = VIR_DOMAIN_DISK_BUS_XEN;
+            } else if (STREQ(values[i], "pflash")) {
+                def->bus = VIR_DOMAIN_DISK_BUS_LAST;
+                is_firmware = true;
             } else if (STREQ(values[i], "sd")) {
                 def->bus = VIR_DOMAIN_DISK_BUS_SD;
             }
@@ -943,8 +947,25 @@ qemuParseCommandLineDisk(virDomainXMLOptionPtr xmlopt,
         ignore_value(VIR_STRDUP(def->dst, "hda"));
     }
 
-    if (!def->dst)
-        goto error;
+    if (!def->dst) {
+        if (is_firmware && def->bus == VIR_DOMAIN_DISK_BUS_LAST) {
+            if (!dom->os.loader && (VIR_ALLOC(dom->os.loader) < 0))
+                goto error;
+            if (def->src->readonly) {
+                /* Loader spec */
+                dom->os.loader->loader_src = def->src;
+                dom->os.loader->type = VIR_DOMAIN_LOADER_TYPE_PFLASH;
+            } else {
+                /* NVRAM Spec */
+                if (!dom->os.loader->nvram && (VIR_ALLOC(dom->os.loader->nvram) < 0))
+                    goto error;
+                dom->os.loader->nvram = def->src;
+            }
+        } else {
+            goto error;
+        }
+    }
+
     if (STREQ(def->dst, "xvda"))
         def->dst[3] = 'a' + idx;
     else
@@ -2215,8 +2236,11 @@ qemuParseCommandLine(virCapsPtr caps,
         } else if (STREQ(arg, "-bios")) {
             WANT_VALUE();
             if (VIR_ALLOC(def->os.loader) < 0 ||
-                VIR_STRDUP(def->os.loader->path, val) < 0)
+                VIR_ALLOC(def->os.loader->loader_src) < 0 ||
+                VIR_STRDUP(def->os.loader->loader_src->path, val) < 0)
                 goto error;
+            def->os.loader->loader_src->type = VIR_STORAGE_TYPE_FILE;
+            def->os.loader->type = VIR_DOMAIN_LOADER_TYPE_ROM;
         } else if (STREQ(arg, "-initrd")) {
             WANT_VALUE();
             if (VIR_STRDUP(def->os.initrd, val) < 0)
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 6a5262a..725dd6e 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -3994,25 +3994,32 @@ qemuPrepareNVRAM(virQEMUDriverConfigPtr cfg,
     const char *master_nvram_path;
     ssize_t r;
 
-    if (!loader || !loader->nvram || virFileExists(loader->nvram))
+    if (!loader || !loader->loader_src || !loader->nvram ||
+        loader->nvram->type == VIR_STORAGE_TYPE_NETWORK)
         return 0;
 
     master_nvram_path = loader->templt;
-    if (!loader->templt) {
+    /* Even if a template is not specified, we associate "known" EFI firmware
+     * to their NVRAM templates.
+     * Ofcourse this only applies to local firmware paths, as it is diffcult
+     * for libvirt to parse all network paths.
+     */
+    if (!loader->templt && loader->loader_src->type == VIR_STORAGE_TYPE_FILE) {
         size_t i;
         for (i = 0; i < cfg->nfirmwares; i++) {
-            if (STREQ(cfg->firmwares[i]->name, loader->path)) {
+            if (STREQ(cfg->firmwares[i]->name, loader->loader_src->path)) {
                 master_nvram_path = cfg->firmwares[i]->nvram;
                 break;
             }
         }
     }
 
-    if (!master_nvram_path) {
-        virReportError(VIR_ERR_OPERATION_FAILED,
-                       _("unable to find any master var store for "
-                         "loader: %s"), loader->path);
-        goto cleanup;
+    if (!master_nvram_path && loader->nvram) {
+        /* There is no template description, but an NVRAM spec
+         * has already been provided.
+         * Trust the client to have generated the right spec here
+         */
+        return 0;
     }
 
     if ((srcFD = virFileOpenAs(master_nvram_path, O_RDONLY,
@@ -4022,13 +4029,13 @@ qemuPrepareNVRAM(virQEMUDriverConfigPtr cfg,
                              master_nvram_path);
         goto cleanup;
     }
-    if ((dstFD = virFileOpenAs(loader->nvram,
+    if ((dstFD = virFileOpenAs(loader->nvram->path,
                                O_WRONLY | O_CREAT | O_EXCL,
                                S_IRUSR | S_IWUSR,
                                cfg->user, cfg->group, 0)) < 0) {
         virReportSystemError(-dstFD,
                              _("Failed to create file '%s'"),
-                             loader->nvram);
+                             loader->nvram->path);
         goto cleanup;
     }
     created = true;
@@ -4046,7 +4053,7 @@ qemuPrepareNVRAM(virQEMUDriverConfigPtr cfg,
         if (safewrite(dstFD, buf, r) < 0) {
             virReportSystemError(errno,
                                  _("Unable to write to file '%s'"),
-                                 loader->nvram);
+                                 loader->nvram->path);
             goto cleanup;
         }
     } while (r);
@@ -4060,7 +4067,7 @@ qemuPrepareNVRAM(virQEMUDriverConfigPtr cfg,
     if (VIR_CLOSE(dstFD) < 0) {
         virReportSystemError(errno,
                              _("Unable to close file '%s'"),
-                             loader->nvram);
+                             loader->nvram->path);
         goto cleanup;
     }
 
@@ -4070,7 +4077,7 @@ qemuPrepareNVRAM(virQEMUDriverConfigPtr cfg,
      * copy the file content. Roll back. */
     if (ret < 0) {
         if (created)
-            unlink(loader->nvram);
+            unlink(loader->nvram->path);
     }
 
     VIR_FORCE_CLOSE(srcFD);
diff --git a/src/security/security_dac.c b/src/security/security_dac.c
index 663c8c9..fce4204 100644
--- a/src/security/security_dac.c
+++ b/src/security/security_dac.c
@@ -1604,7 +1604,8 @@ virSecurityDACRestoreAllLabel(virSecurityManagerPtr mgr,
     }
 
     if (def->os.loader && def->os.loader->nvram &&
-        virSecurityDACRestoreFileLabel(priv, def->os.loader->nvram) < 0)
+        def->os.loader->nvram->type == VIR_STORAGE_TYPE_FILE &&
+        virSecurityDACRestoreFileLabel(priv, def->os.loader->nvram->path) < 0)
         rc = -1;
 
     return rc;
@@ -1732,8 +1733,9 @@ virSecurityDACSetAllLabel(virSecurityManagerPtr mgr,
         return -1;
 
     if (def->os.loader && def->os.loader->nvram &&
+        def->os.loader->nvram->type == VIR_STORAGE_TYPE_FILE &&
         virSecurityDACSetOwnership(priv, NULL,
-                                   def->os.loader->nvram, user, group) < 0)
+                                   def->os.loader->nvram->path, user, group) < 0)
         return -1;
 
     if (def->os.kernel &&
diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
index c26cdac..396e7fc 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -2459,7 +2459,8 @@ virSecuritySELinuxRestoreAllLabel(virSecurityManagerPtr mgr,
         rc = -1;
 
     if (def->os.loader && def->os.loader->nvram &&
-        virSecuritySELinuxRestoreFileLabel(mgr, def->os.loader->nvram) < 0)
+        def->os.loader->nvram->type == VIR_STORAGE_TYPE_FILE &&
+        virSecuritySELinuxRestoreFileLabel(mgr, def->os.loader->nvram->path) < 0)
         rc = -1;
 
     return rc;
@@ -2851,8 +2852,9 @@ virSecuritySELinuxSetAllLabel(virSecurityManagerPtr mgr,
     /* This is different than kernel or initrd. The nvram store
      * is really a disk, qemu can read and write to it. */
     if (def->os.loader && def->os.loader->nvram &&
+        def->os.loader->nvram->type == VIR_STORAGE_TYPE_FILE &&
         secdef && secdef->imagelabel &&
-        virSecuritySELinuxSetFilecon(mgr, def->os.loader->nvram,
+        virSecuritySELinuxSetFilecon(mgr, def->os.loader->nvram->path,
                                      secdef->imagelabel) < 0)
         return -1;
 
-- 
1.8.1.2




More information about the libvir-list mailing list