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

John Ferlan jferlan at redhat.com
Fri Apr 27 19:41:42 UTC 2018



On 04/20/2018 04:59 AM, Prerna Saxena wrote:
> 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(-)
> 

I know on IRC you asked Peter or Michal to review (and they're CC'd
here), but before they get a chance next week some time - I'll give you
a quick look. You do understand Peter, Michal, myself, and other Red Hat
libvirt developers follow libvir-list anyway - so CC'ing any of us
doesn't do much since we filter into a mail folder anyway...

This will need a v2 anyway because the patch has too much going on and
needs to be split up more.

You need to break out the domain_conf, docs, etc. changes into one
patch. Much of what you put into the cover that describes the XML should
go into this patch's commit message. There should be xml2xml test
changes as well as adjustments to formatdomain.html.in to describe the
new options. The part of the cover that says automatically reformatting
to use the storage source cannot happen. There's precedence for that
when the <encryption> and <auth> moved *into* the storage source we
still have to accommodate for them outside. Internally, it can be placed
as expected, but when formatting, we have to format as we read. After
that, perhaps add the security changes in another, the cgroup in
another, and finally the qemu adjustments in the last.  Not even sure if
you need a capability as well.

Finally this doesn't even compile for me.  You removed @path from
_virDomainLoaderDef but neglected to adjust all consumers. I suggest
using cscope and egrep'ing on "os.*loader->path" as well as ->nvram
since you changed it's type.

I assume you've considered that network storage types need to deal with
authentication and encryption passphrases, right?  What about using a
srcpool storage source?

I'll briefly scan the rest.

> 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);

loader_src is redundant to loader isn't it?

> +    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;
> +    }

syntax-check would choke here with the unnecessary { }

> +    loader->loader_src->type = VIR_STORAGE_TYPE_LAST;

ug, ah, no.

Consider my comment from above - you have either "path" or "source" and
deal with it from there. When you format you need to format as you read.

>  
>      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;
> +        }
> +    }

You need to find a different way.  If you find <source>, then parse it.
If you find <path> then you parse it instead.

>  
>      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:

This is not the way we handle this.

>      VIR_FREE(readonly_str);
>      VIR_FREE(secure_str);
>      VIR_FREE(type_str);
> +

extraneous

>      return ret;
>  }
>  

Two blank lines.

> +static int
> +virDomainLoaderNvramDefParseXML(xmlNodePtr node,
> +                           xmlXPathContextPtr ctxt,
> +                           virDomainLoaderDefPtr loader)
> +{
> +    int ret = -1;
> +    char *tmp = NULL;
> +    xmlNodePtr cur;
> +
> +    if (VIR_ALLOC(loader->nvram)) {
> +        goto cleanup;
> +    }

Again { }

Similar problem to before w/r/t the XML processing here.

> +
> +    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;

don't reuse "loader_node" for "nvram_node".

I think you need to separate loader patches from nvram patches too.
It'll perhaps make things easier to review again eventually.

>          }
>      }
>  
> @@ -26070,11 +26181,19 @@ virDomainHugepagesFormat(virBufferPtr buf,
>  
>  static void
>  virDomainLoaderDefFormat(virBufferPtr buf,
> -                         virDomainLoaderDefPtr loader)
> +                         virDomainLoaderDefPtr loader,
> +                         unsigned int flags)

As noted earlier reading in one format means we write out in the same
format. If someone wants to use the new format, then they can.

>  {
>      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;

You'll probably need a way to booleanize which format was read. I forget
how things were done for encryption and auth changes that I made.

>      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);

What happens if there's authentication or encryption? is that not supported?

>          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;

wow - changing this code too...  not everyone does this!  I really doubt
the code even really works very well any more.

>  
>      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;
>  
> 

There's still far too much missing... even in the qemu side - there
needs to be xml2argv test changes... *.args output...

Perhaps best to generate a v2 with things separated better and more
complete changes and take it from there.

John




More information about the libvir-list mailing list