|
|
9119d9 |
From 2f7b1149c58002de91314c409df97723226db6e2 Mon Sep 17 00:00:00 2001
|
|
|
9119d9 |
Message-Id: <2f7b1149c58002de91314c409df97723226db6e2@dist-git>
|
|
|
9119d9 |
From: Michal Privoznik <mprivozn@redhat.com>
|
|
|
9119d9 |
Date: Wed, 10 Sep 2014 10:11:45 +0200
|
|
|
9119d9 |
Subject: [PATCH] qemu: Automatically create NVRAM store
|
|
|
9119d9 |
|
|
|
9119d9 |
https://bugzilla.redhat.com/show_bug.cgi?id=1112257
|
|
|
9119d9 |
|
|
|
9119d9 |
When using split UEFI image, it may come handy if libvirt manages per
|
|
|
9119d9 |
domain _VARS file automatically. While the _CODE file is RO and can be
|
|
|
9119d9 |
shared among multiple domains, you certainly don't want to do that on
|
|
|
9119d9 |
the _VARS file. This latter one needs to be per domain. So at the
|
|
|
9119d9 |
domain startup process, if it's determined that domain needs _VARS
|
|
|
9119d9 |
file it's copied from this master _VARS file. The location of the
|
|
|
9119d9 |
master file is configurable in qemu.conf.
|
|
|
9119d9 |
|
|
|
9119d9 |
Temporary, on per domain basis the location of master NVRAM file can
|
|
|
9119d9 |
be overridden by this @template attribute I'm inventing to the
|
|
|
9119d9 |
<nvram/> element. All it does is holding path to the master NVRAM file
|
|
|
9119d9 |
from which local copy is created. If that's the case, the map in
|
|
|
9119d9 |
qemu.conf is not consulted.
|
|
|
9119d9 |
|
|
|
9119d9 |
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
|
|
|
9119d9 |
Acked-by: Laszlo Ersek <lersek@redhat.com>
|
|
|
9119d9 |
(cherry picked from commit 742b08e30fd503bc992e864828cbabd7e6a099ec)
|
|
|
9119d9 |
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
|
|
|
9119d9 |
---
|
|
|
9119d9 |
docs/formatdomain.html.in | 11 +-
|
|
|
9119d9 |
docs/schemas/domaincommon.rng | 9 +-
|
|
|
9119d9 |
libvirt.spec.in | 2 +
|
|
|
9119d9 |
src/Makefile.am | 1 +
|
|
|
9119d9 |
src/conf/domain_conf.c | 11 +-
|
|
|
9119d9 |
src/conf/domain_conf.h | 1 +
|
|
|
9119d9 |
src/qemu/libvirtd_qemu.aug | 3 +
|
|
|
9119d9 |
src/qemu/qemu.conf | 14 +++
|
|
|
9119d9 |
src/qemu/qemu_conf.c | 94 ++++++++++++++
|
|
|
9119d9 |
src/qemu/qemu_conf.h | 5 +
|
|
|
9119d9 |
src/qemu/qemu_process.c | 137 +++++++++++++++++++++
|
|
|
9119d9 |
src/qemu/test_libvirtd_qemu.aug.in | 3 +
|
|
|
9119d9 |
tests/domainschemadata/domain-bios-nvram-empty.xml | 40 ++++++
|
|
|
9119d9 |
13 files changed, 325 insertions(+), 6 deletions(-)
|
|
|
9119d9 |
create mode 100644 tests/domainschemadata/domain-bios-nvram-empty.xml
|
|
|
9119d9 |
|
|
|
9119d9 |
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
|
|
|
9119d9 |
index 757035a..a2ea758 100644
|
|
|
9119d9 |
--- a/docs/formatdomain.html.in
|
|
|
9119d9 |
+++ b/docs/formatdomain.html.in
|
|
|
9119d9 |
@@ -103,7 +103,7 @@
|
|
|
9119d9 |
<os>
|
|
|
9119d9 |
<type>hvm</type>
|
|
|
9119d9 |
<loader readonly='on' type='rom'>/usr/lib/xen/boot/hvmloader</loader>
|
|
|
9119d9 |
- <nvram>/var/lib/libvirt/nvram/guest_VARS.fd</nvram>
|
|
|
9119d9 |
+ <nvram template='/usr/share/OVMF/OVMF_VARS.fd'>/var/lib/libvirt/nvram/guest_VARS.fd</nvram>
|
|
|
9119d9 |
<boot dev='hd'/>
|
|
|
9119d9 |
<boot dev='cdrom'/>
|
|
|
9119d9 |
<bootmenu enable='yes' timeout='3000'/>
|
|
|
9119d9 |
@@ -142,9 +142,12 @@
|
|
|
9119d9 |
pflash .
|
|
|
9119d9 |
nvram
|
|
|
9119d9 |
Some UEFI firmwares may want to use a non-volatile memory to store
|
|
|
9119d9 |
- some variables. In the host, this is represented as a file and the
|
|
|
9119d9 |
- path to the file is stored in this element. Since
|
|
|
9119d9 |
- 1.2.8
|
|
|
9119d9 |
+ some variables. In the host, this is represented as a file and the path
|
|
|
9119d9 |
+ to the file is stored in this element. Moreover, when the domain is
|
|
|
9119d9 |
+ started up libvirt copies so called master NVRAM store file defined
|
|
|
9119d9 |
+ in qemu.conf . If needed, the template
|
|
|
9119d9 |
+ attribute can be used to per domain override map of master NVRAM stores
|
|
|
9119d9 |
+ from the config file. Since 1.2.8
|
|
|
9119d9 |
boot
|
|
|
9119d9 |
The dev attribute takes one of the values "fd", "hd",
|
|
|
9119d9 |
"cdrom" or "network" and is used to specify the next boot device
|
|
|
9119d9 |
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
|
|
|
9119d9 |
index 5d9c21c..6ae940a 100644
|
|
|
9119d9 |
--- a/docs/schemas/domaincommon.rng
|
|
|
9119d9 |
+++ b/docs/schemas/domaincommon.rng
|
|
|
9119d9 |
@@ -263,7 +263,14 @@
|
|
|
9119d9 |
</optional>
|
|
|
9119d9 |
<optional>
|
|
|
9119d9 |
<element name="nvram">
|
|
|
9119d9 |
- <ref name="absFilePath"/>
|
|
|
9119d9 |
+ <optional>
|
|
|
9119d9 |
+ <attribute name="template">
|
|
|
9119d9 |
+ <ref name="absFilePath"/>
|
|
|
9119d9 |
+ </attribute>
|
|
|
9119d9 |
+ </optional>
|
|
|
9119d9 |
+ <optional>
|
|
|
9119d9 |
+ <ref name="absFilePath"/>
|
|
|
9119d9 |
+ </optional>
|
|
|
9119d9 |
</element>
|
|
|
9119d9 |
</optional>
|
|
|
9119d9 |
<optional>
|
|
|
9119d9 |
diff --git a/src/Makefile.am b/src/Makefile.am
|
|
|
9119d9 |
index 46e411e..fa741a8 100644
|
|
|
9119d9 |
--- a/src/Makefile.am
|
|
|
9119d9 |
+++ b/src/Makefile.am
|
|
|
9119d9 |
@@ -2679,6 +2679,7 @@ endif WITH_SANLOCK
|
|
|
9119d9 |
if WITH_QEMU
|
|
|
9119d9 |
$(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/qemu"
|
|
|
9119d9 |
$(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/qemu/channel/target"
|
|
|
9119d9 |
+ $(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/qemu/nvram"
|
|
|
9119d9 |
$(MKDIR_P) "$(DESTDIR)$(localstatedir)/run/libvirt/qemu"
|
|
|
9119d9 |
$(MKDIR_P) "$(DESTDIR)$(localstatedir)/cache/libvirt/qemu"
|
|
|
9119d9 |
$(MKDIR_P) "$(DESTDIR)$(localstatedir)/log/libvirt/qemu"
|
|
|
9119d9 |
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
|
|
|
9119d9 |
index 6ee5c17..84f5f1d 100644
|
|
|
9119d9 |
--- a/src/conf/domain_conf.c
|
|
|
9119d9 |
+++ b/src/conf/domain_conf.c
|
|
|
9119d9 |
@@ -2023,6 +2023,7 @@ virDomainLoaderDefFree(virDomainLoaderDefPtr loader)
|
|
|
9119d9 |
|
|
|
9119d9 |
VIR_FREE(loader->path);
|
|
|
9119d9 |
VIR_FREE(loader->nvram);
|
|
|
9119d9 |
+ VIR_FREE(loader->templt);
|
|
|
9119d9 |
VIR_FREE(loader);
|
|
|
9119d9 |
}
|
|
|
9119d9 |
|
|
|
9119d9 |
@@ -12768,6 +12769,7 @@ virDomainDefParseXML(xmlDocPtr xml,
|
|
|
9119d9 |
goto error;
|
|
|
9119d9 |
|
|
|
9119d9 |
def->os.loader->nvram = virXPathString("string(./os/nvram[1])", ctxt);
|
|
|
9119d9 |
+ def->os.loader->templt = virXPathString("string(./os/nvram[1]/@template)", ctxt);
|
|
|
9119d9 |
}
|
|
|
9119d9 |
}
|
|
|
9119d9 |
|
|
|
9119d9 |
@@ -17866,7 +17868,14 @@ virDomainLoaderDefFormat(virBufferPtr buf,
|
|
|
9119d9 |
virBufferAsprintf(buf, " type='%s'>", type);
|
|
|
9119d9 |
|
|
|
9119d9 |
virBufferEscapeString(buf, "%s</loader>\n", loader->path);
|
|
|
9119d9 |
- virBufferEscapeString(buf, "<nvram>%s</nvram>\n", loader->nvram);
|
|
|
9119d9 |
+ if (loader->nvram || loader->templt) {
|
|
|
9119d9 |
+ virBufferAddLit(buf, "
|
|
|
9119d9 |
+ virBufferEscapeString(buf, " template='%s'", loader->templt);
|
|
|
9119d9 |
+ if (loader->nvram)
|
|
|
9119d9 |
+ virBufferEscapeString(buf, ">%s</nvram>\n", loader->nvram);
|
|
|
9119d9 |
+ else
|
|
|
9119d9 |
+ virBufferAddLit(buf, "/>\n");
|
|
|
9119d9 |
+ }
|
|
|
9119d9 |
}
|
|
|
9119d9 |
|
|
|
9119d9 |
static bool
|
|
|
9119d9 |
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
|
|
|
9119d9 |
index c97a10c..3316fb6 100644
|
|
|
9119d9 |
--- a/src/conf/domain_conf.h
|
|
|
9119d9 |
+++ b/src/conf/domain_conf.h
|
|
|
9119d9 |
@@ -1644,6 +1644,7 @@ struct _virDomainLoaderDef {
|
|
|
9119d9 |
int readonly; /* enum virTristateBool */
|
|
|
9119d9 |
virDomainLoader type;
|
|
|
9119d9 |
char *nvram; /* path to non-volatile RAM */
|
|
|
9119d9 |
+ char *templt; /* user override of path to master nvram */
|
|
|
9119d9 |
};
|
|
|
9119d9 |
|
|
|
9119d9 |
void virDomainLoaderDefFree(virDomainLoaderDefPtr loader);
|
|
|
9119d9 |
diff --git a/src/qemu/libvirtd_qemu.aug b/src/qemu/libvirtd_qemu.aug
|
|
|
9119d9 |
index e7db7fe..62951da 100644
|
|
|
9119d9 |
--- a/src/qemu/libvirtd_qemu.aug
|
|
|
9119d9 |
+++ b/src/qemu/libvirtd_qemu.aug
|
|
|
9119d9 |
@@ -88,6 +88,8 @@ module Libvirtd_qemu =
|
|
|
9119d9 |
|
|
|
9119d9 |
let log_entry = bool_entry "log_timestamp"
|
|
|
9119d9 |
|
|
|
9119d9 |
+ let nvram_entry = str_array_entry "nvram"
|
|
|
9119d9 |
+
|
|
|
9119d9 |
(* Each entry in the config is one of the following ... *)
|
|
|
9119d9 |
let entry = vnc_entry
|
|
|
9119d9 |
| spice_entry
|
|
|
9119d9 |
@@ -100,6 +102,7 @@ module Libvirtd_qemu =
|
|
|
9119d9 |
| rpc_entry
|
|
|
9119d9 |
| network_entry
|
|
|
9119d9 |
| log_entry
|
|
|
9119d9 |
+ | nvram_entry
|
|
|
9119d9 |
|
|
|
9119d9 |
let comment = [ label "#comment" . del /#[ \t]*/ "# " . store /([^ \t\n][^\n]*)?/ . del /\n/ "\n" ]
|
|
|
9119d9 |
let empty = [ label "#empty" . eol ]
|
|
|
9119d9 |
diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf
|
|
|
9119d9 |
index 7bbbe09..79bba36 100644
|
|
|
9119d9 |
--- a/src/qemu/qemu.conf
|
|
|
9119d9 |
+++ b/src/qemu/qemu.conf
|
|
|
9119d9 |
@@ -487,3 +487,17 @@
|
|
|
9119d9 |
# Defaults to 1.
|
|
|
9119d9 |
#
|
|
|
9119d9 |
#log_timestamp = 0
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+# Location of master nvram file
|
|
|
9119d9 |
+#
|
|
|
9119d9 |
+# When a domain is configured to use UEFI instead of standard
|
|
|
9119d9 |
+# BIOS it may use a separate storage for UEFI variables. If
|
|
|
9119d9 |
+# that's the case libvirt creates the variable store per domain
|
|
|
9119d9 |
+# using this master file as image. Each UEFI firmware can,
|
|
|
9119d9 |
+# however, have different variables store. Therefore the nvram is
|
|
|
9119d9 |
+# a list of strings when a single item is in form of:
|
|
|
9119d9 |
+# ${PATH_TO_UEFI_FW}:${PATH_TO_UEFI_VARS}.
|
|
|
9119d9 |
+# Later, when libvirt creates per domain variable store, this
|
|
|
9119d9 |
+# list is searched for the master image.
|
|
|
9119d9 |
+#nvram = [ "/usr/share/OVMF/OVMF_CODE.fd:/usr/share/OVMF/OVMF_VARS.fd" ]
|
|
|
9119d9 |
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
|
|
|
9119d9 |
index e2ec54f..ac10b64 100644
|
|
|
9119d9 |
--- a/src/qemu/qemu_conf.c
|
|
|
9119d9 |
+++ b/src/qemu/qemu_conf.c
|
|
|
9119d9 |
@@ -107,6 +107,9 @@ void qemuDomainCmdlineDefFree(qemuDomainCmdlineDefPtr def)
|
|
|
9119d9 |
VIR_FREE(def);
|
|
|
9119d9 |
}
|
|
|
9119d9 |
|
|
|
9119d9 |
+#define VIR_QEMU_LOADER_FILE_PATH "/usr/share/OVMF/OVMF_CODE.fd"
|
|
|
9119d9 |
+#define VIR_QEMU_NVRAM_FILE_PATH "/usr/share/OVMF/OVMF_VARS.fd"
|
|
|
9119d9 |
+
|
|
|
9119d9 |
virQEMUDriverConfigPtr virQEMUDriverConfigNew(bool privileged)
|
|
|
9119d9 |
{
|
|
|
9119d9 |
virQEMUDriverConfigPtr cfg;
|
|
|
9119d9 |
@@ -255,6 +258,15 @@ virQEMUDriverConfigPtr virQEMUDriverConfigNew(bool privileged)
|
|
|
9119d9 |
|
|
|
9119d9 |
cfg->logTimestamp = true;
|
|
|
9119d9 |
|
|
|
9119d9 |
+ if (VIR_ALLOC_N(cfg->loader, 1) < 0 ||
|
|
|
9119d9 |
+ VIR_ALLOC_N(cfg->nvram, 1) < 0)
|
|
|
9119d9 |
+ goto error;
|
|
|
9119d9 |
+ cfg->nloader = 1;
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ if (VIR_STRDUP(cfg->loader[0], VIR_QEMU_LOADER_FILE_PATH) < 0 ||
|
|
|
9119d9 |
+ VIR_STRDUP(cfg->nvram[0], VIR_QEMU_NVRAM_FILE_PATH) < 0)
|
|
|
9119d9 |
+ goto error;
|
|
|
9119d9 |
+
|
|
|
9119d9 |
return cfg;
|
|
|
9119d9 |
|
|
|
9119d9 |
error:
|
|
|
9119d9 |
@@ -305,6 +317,14 @@ static void virQEMUDriverConfigDispose(void *obj)
|
|
|
9119d9 |
virStringFreeList(cfg->securityDriverNames);
|
|
|
9119d9 |
|
|
|
9119d9 |
VIR_FREE(cfg->lockManagerName);
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ while (cfg->nloader) {
|
|
|
9119d9 |
+ VIR_FREE(cfg->loader[cfg->nloader - 1]);
|
|
|
9119d9 |
+ VIR_FREE(cfg->nvram[cfg->nloader - 1]);
|
|
|
9119d9 |
+ cfg->nloader--;
|
|
|
9119d9 |
+ }
|
|
|
9119d9 |
+ VIR_FREE(cfg->loader);
|
|
|
9119d9 |
+ VIR_FREE(cfg->nvram);
|
|
|
9119d9 |
}
|
|
|
9119d9 |
|
|
|
9119d9 |
|
|
|
9119d9 |
@@ -328,6 +348,43 @@ virQEMUDriverConfigHugeTLBFSInit(virHugeTLBFSPtr hugetlbfs,
|
|
|
9119d9 |
}
|
|
|
9119d9 |
|
|
|
9119d9 |
|
|
|
9119d9 |
+static int
|
|
|
9119d9 |
+virQEMUDriverConfigNVRAMParse(const char *str,
|
|
|
9119d9 |
+ char **loader,
|
|
|
9119d9 |
+ char **nvram)
|
|
|
9119d9 |
+{
|
|
|
9119d9 |
+ int ret = -1;
|
|
|
9119d9 |
+ char **token;
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ if (!(token = virStringSplit(str, ":", 0)))
|
|
|
9119d9 |
+ goto cleanup;
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ if (token[0]) {
|
|
|
9119d9 |
+ virSkipSpaces((const char **) &token[0]);
|
|
|
9119d9 |
+ if (token[1])
|
|
|
9119d9 |
+ virSkipSpaces((const char **) &token[1]);
|
|
|
9119d9 |
+ }
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ /* Exactly two tokens are expected */
|
|
|
9119d9 |
+ if (!token[0] || !token[1] || token[2] ||
|
|
|
9119d9 |
+ STREQ(token[0], "") || STREQ(token[1], "")) {
|
|
|
9119d9 |
+ virReportError(VIR_ERR_CONF_SYNTAX,
|
|
|
9119d9 |
+ _("Invalid nvram format: '%s'"),
|
|
|
9119d9 |
+ str);
|
|
|
9119d9 |
+ goto cleanup;
|
|
|
9119d9 |
+ }
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ if (VIR_STRDUP(*loader, token[0]) < 0 ||
|
|
|
9119d9 |
+ VIR_STRDUP(*nvram, token[1]) < 0)
|
|
|
9119d9 |
+ goto cleanup;
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ ret = 0;
|
|
|
9119d9 |
+ cleanup:
|
|
|
9119d9 |
+ virStringFreeList(token);
|
|
|
9119d9 |
+ return ret;
|
|
|
9119d9 |
+}
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+
|
|
|
9119d9 |
int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg,
|
|
|
9119d9 |
const char *filename)
|
|
|
9119d9 |
{
|
|
|
9119d9 |
@@ -654,6 +711,43 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg,
|
|
|
9119d9 |
|
|
|
9119d9 |
GET_VALUE_BOOL("log_timestamp", cfg->logTimestamp);
|
|
|
9119d9 |
|
|
|
9119d9 |
+ if ((p = virConfGetValue(conf, "nvram"))) {
|
|
|
9119d9 |
+ size_t len;
|
|
|
9119d9 |
+ virConfValuePtr pp;
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ CHECK_TYPE("nvram", VIR_CONF_LIST);
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ while (cfg->nloader) {
|
|
|
9119d9 |
+ VIR_FREE(cfg->loader[cfg->nloader - 1]);
|
|
|
9119d9 |
+ VIR_FREE(cfg->nvram[cfg->nloader - 1]);
|
|
|
9119d9 |
+ cfg->nloader--;
|
|
|
9119d9 |
+ }
|
|
|
9119d9 |
+ VIR_FREE(cfg->loader);
|
|
|
9119d9 |
+ VIR_FREE(cfg->nvram);
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ /* Calc length and check items */
|
|
|
9119d9 |
+ for (len = 0, pp = p->list; pp; len++, pp = pp->next) {
|
|
|
9119d9 |
+ if (pp->type != VIR_CONF_STRING) {
|
|
|
9119d9 |
+ virReportError(VIR_ERR_CONF_SYNTAX, "%s",
|
|
|
9119d9 |
+ _("nvram must be a list of strings"));
|
|
|
9119d9 |
+ goto cleanup;
|
|
|
9119d9 |
+ }
|
|
|
9119d9 |
+ }
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ if (len &&
|
|
|
9119d9 |
+ (VIR_ALLOC_N(cfg->loader, len) < 0 ||
|
|
|
9119d9 |
+ VIR_ALLOC_N(cfg->nvram, len) < 0))
|
|
|
9119d9 |
+ goto cleanup;
|
|
|
9119d9 |
+ cfg->nloader = len;
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ for (i = 0, pp = p->list; pp; i++, pp = pp->next) {
|
|
|
9119d9 |
+ if (virQEMUDriverConfigNVRAMParse(pp->str,
|
|
|
9119d9 |
+ &cfg->loader[i],
|
|
|
9119d9 |
+ &cfg->nvram[i]) < 0)
|
|
|
9119d9 |
+ goto cleanup;
|
|
|
9119d9 |
+ }
|
|
|
9119d9 |
+ }
|
|
|
9119d9 |
+
|
|
|
9119d9 |
ret = 0;
|
|
|
9119d9 |
|
|
|
9119d9 |
cleanup:
|
|
|
9119d9 |
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
|
|
|
9119d9 |
index ae7ac56..1f521e5 100644
|
|
|
9119d9 |
--- a/src/qemu/qemu_conf.h
|
|
|
9119d9 |
+++ b/src/qemu/qemu_conf.h
|
|
|
9119d9 |
@@ -172,6 +172,11 @@ struct _virQEMUDriverConfig {
|
|
|
9119d9 |
int migrationPortMax;
|
|
|
9119d9 |
|
|
|
9119d9 |
bool logTimestamp;
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ /* Pairs of loader:nvram paths. The list is @nloader items long */
|
|
|
9119d9 |
+ char **loader;
|
|
|
9119d9 |
+ char **nvram;
|
|
|
9119d9 |
+ size_t nloader;
|
|
|
9119d9 |
};
|
|
|
9119d9 |
|
|
|
9119d9 |
/* Main driver state */
|
|
|
9119d9 |
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
|
|
|
9119d9 |
index 0f269b9..d7f6bdf 100644
|
|
|
9119d9 |
--- a/src/qemu/qemu_process.c
|
|
|
9119d9 |
+++ b/src/qemu/qemu_process.c
|
|
|
9119d9 |
@@ -67,6 +67,7 @@
|
|
|
9119d9 |
#include "virstring.h"
|
|
|
9119d9 |
#include "virhostdev.h"
|
|
|
9119d9 |
#include "storage/storage_driver.h"
|
|
|
9119d9 |
+#include "configmake.h"
|
|
|
9119d9 |
|
|
|
9119d9 |
#define VIR_FROM_THIS VIR_FROM_QEMU
|
|
|
9119d9 |
|
|
|
9119d9 |
@@ -3741,6 +3742,135 @@ qemuProcessVerifyGuestCPU(virQEMUDriverPtr driver,
|
|
|
9119d9 |
}
|
|
|
9119d9 |
|
|
|
9119d9 |
|
|
|
9119d9 |
+static int
|
|
|
9119d9 |
+qemuPrepareNVRAM(virQEMUDriverConfigPtr cfg,
|
|
|
9119d9 |
+ virDomainDefPtr def,
|
|
|
9119d9 |
+ bool migrated)
|
|
|
9119d9 |
+{
|
|
|
9119d9 |
+ int ret = -1;
|
|
|
9119d9 |
+ int srcFD = -1;
|
|
|
9119d9 |
+ int dstFD = -1;
|
|
|
9119d9 |
+ virDomainLoaderDefPtr loader = def->os.loader;
|
|
|
9119d9 |
+ bool generated = false;
|
|
|
9119d9 |
+ bool created = false;
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ /* Unless domain has RO loader of pflash type, we have
|
|
|
9119d9 |
+ * nothing to do here. If the loader is RW then it's not
|
|
|
9119d9 |
+ * using split code and vars feature, so no nvram file needs
|
|
|
9119d9 |
+ * to be created. */
|
|
|
9119d9 |
+ if (!loader || loader->type != VIR_DOMAIN_LOADER_TYPE_PFLASH ||
|
|
|
9119d9 |
+ loader->readonly != VIR_TRISTATE_SWITCH_ON)
|
|
|
9119d9 |
+ return 0;
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ /* If the nvram path is configured already, there's nothing
|
|
|
9119d9 |
+ * we need to do. Unless we are starting the destination side
|
|
|
9119d9 |
+ * of migration in which case nvram is configured in the
|
|
|
9119d9 |
+ * domain XML but the file doesn't exist yet. Moreover, after
|
|
|
9119d9 |
+ * the migration is completed, qemu will invoke a
|
|
|
9119d9 |
+ * synchronization write into the nvram file so we don't have
|
|
|
9119d9 |
+ * to take care about transmitting the real data on the other
|
|
|
9119d9 |
+ * side. */
|
|
|
9119d9 |
+ if (loader->nvram && !migrated)
|
|
|
9119d9 |
+ return 0;
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ /* Autogenerate nvram path if needed.*/
|
|
|
9119d9 |
+ if (!loader->nvram) {
|
|
|
9119d9 |
+ if (virAsprintf(&loader->nvram,
|
|
|
9119d9 |
+ "%s/lib/libvirt/qemu/nvram/%s_VARS.fd",
|
|
|
9119d9 |
+ LOCALSTATEDIR, def->name) < 0)
|
|
|
9119d9 |
+ goto cleanup;
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ generated = true;
|
|
|
9119d9 |
+ }
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ if (!virFileExists(loader->nvram)) {
|
|
|
9119d9 |
+ const char *master_nvram_path = loader->templt;
|
|
|
9119d9 |
+ ssize_t r;
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ if (!loader->templt) {
|
|
|
9119d9 |
+ size_t i;
|
|
|
9119d9 |
+ for (i = 0; i < cfg->nloader; i++) {
|
|
|
9119d9 |
+ if (STREQ(cfg->loader[i], loader->path)) {
|
|
|
9119d9 |
+ master_nvram_path = cfg->nvram[i];
|
|
|
9119d9 |
+ break;
|
|
|
9119d9 |
+ }
|
|
|
9119d9 |
+ }
|
|
|
9119d9 |
+ }
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ if (!master_nvram_path) {
|
|
|
9119d9 |
+ virReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
9119d9 |
+ _("unable to find any master var store for "
|
|
|
9119d9 |
+ "loader: %s"), loader->path);
|
|
|
9119d9 |
+ goto cleanup;
|
|
|
9119d9 |
+ }
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ if ((srcFD = virFileOpenAs(master_nvram_path, O_RDONLY,
|
|
|
9119d9 |
+ 0, -1, -1, 0)) < 0) {
|
|
|
9119d9 |
+ virReportSystemError(-srcFD,
|
|
|
9119d9 |
+ _("Failed to open file '%s'"),
|
|
|
9119d9 |
+ master_nvram_path);
|
|
|
9119d9 |
+ goto cleanup;
|
|
|
9119d9 |
+ }
|
|
|
9119d9 |
+ if ((dstFD = virFileOpenAs(loader->nvram,
|
|
|
9119d9 |
+ O_WRONLY | O_CREAT | O_EXCL,
|
|
|
9119d9 |
+ S_IRUSR | S_IWUSR,
|
|
|
9119d9 |
+ cfg->user, cfg->group, 0)) < 0) {
|
|
|
9119d9 |
+ virReportSystemError(-dstFD,
|
|
|
9119d9 |
+ _("Failed to create file '%s'"),
|
|
|
9119d9 |
+ loader->nvram);
|
|
|
9119d9 |
+ goto cleanup;
|
|
|
9119d9 |
+ }
|
|
|
9119d9 |
+ created = true;
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ do {
|
|
|
9119d9 |
+ char buf[1024];
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ if ((r = saferead(srcFD, buf, sizeof(buf))) < 0) {
|
|
|
9119d9 |
+ virReportSystemError(errno,
|
|
|
9119d9 |
+ _("Unable to read from file '%s'"),
|
|
|
9119d9 |
+ master_nvram_path);
|
|
|
9119d9 |
+ goto cleanup;
|
|
|
9119d9 |
+ }
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ if (safewrite(dstFD, buf, r) < 0) {
|
|
|
9119d9 |
+ virReportSystemError(errno,
|
|
|
9119d9 |
+ _("Unable to write to file '%s'"),
|
|
|
9119d9 |
+ loader->nvram);
|
|
|
9119d9 |
+ goto cleanup;
|
|
|
9119d9 |
+ }
|
|
|
9119d9 |
+ } while (r);
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ if (VIR_CLOSE(srcFD) < 0) {
|
|
|
9119d9 |
+ virReportSystemError(errno,
|
|
|
9119d9 |
+ _("Unable to close file '%s'"),
|
|
|
9119d9 |
+ master_nvram_path);
|
|
|
9119d9 |
+ goto cleanup;
|
|
|
9119d9 |
+ }
|
|
|
9119d9 |
+ if (VIR_CLOSE(dstFD) < 0) {
|
|
|
9119d9 |
+ virReportSystemError(errno,
|
|
|
9119d9 |
+ _("Unable to close file '%s'"),
|
|
|
9119d9 |
+ loader->nvram);
|
|
|
9119d9 |
+ goto cleanup;
|
|
|
9119d9 |
+ }
|
|
|
9119d9 |
+ }
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ ret = 0;
|
|
|
9119d9 |
+ cleanup:
|
|
|
9119d9 |
+ /* We successfully generated the nvram path, but failed to
|
|
|
9119d9 |
+ * copy the file content. Roll back. */
|
|
|
9119d9 |
+ if (ret < 0) {
|
|
|
9119d9 |
+ if (created)
|
|
|
9119d9 |
+ unlink(loader->nvram);
|
|
|
9119d9 |
+ if (generated)
|
|
|
9119d9 |
+ VIR_FREE(loader->nvram);
|
|
|
9119d9 |
+ }
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ VIR_FORCE_CLOSE(srcFD);
|
|
|
9119d9 |
+ VIR_FORCE_CLOSE(dstFD);
|
|
|
9119d9 |
+ return ret;
|
|
|
9119d9 |
+}
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+
|
|
|
9119d9 |
int qemuProcessStart(virConnectPtr conn,
|
|
|
9119d9 |
virQEMUDriverPtr driver,
|
|
|
9119d9 |
virDomainObjPtr vm,
|
|
|
9119d9 |
@@ -3809,6 +3939,13 @@ int qemuProcessStart(virConnectPtr conn,
|
|
|
9119d9 |
if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
|
|
|
9119d9 |
goto cleanup;
|
|
|
9119d9 |
|
|
|
9119d9 |
+ /* Some things, paths, ... are generated here and we want them to persist.
|
|
|
9119d9 |
+ * Fill them in prior to setting the domain def as transient. */
|
|
|
9119d9 |
+ VIR_DEBUG("Generating paths");
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ if (qemuPrepareNVRAM(cfg, vm->def, migrateFrom) < 0)
|
|
|
9119d9 |
+ goto cleanup;
|
|
|
9119d9 |
+
|
|
|
9119d9 |
/* Do this upfront, so any part of the startup process can add
|
|
|
9119d9 |
* runtime state to vm->def that won't be persisted. This let's us
|
|
|
9119d9 |
* report implicit runtime defaults in the XML, like vnc listen/socket
|
|
|
9119d9 |
diff --git a/src/qemu/test_libvirtd_qemu.aug.in b/src/qemu/test_libvirtd_qemu.aug.in
|
|
|
9119d9 |
index 7796acc..d2bc2c0 100644
|
|
|
9119d9 |
--- a/src/qemu/test_libvirtd_qemu.aug.in
|
|
|
9119d9 |
+++ b/src/qemu/test_libvirtd_qemu.aug.in
|
|
|
9119d9 |
@@ -74,3 +74,6 @@ module Test_libvirtd_qemu =
|
|
|
9119d9 |
{ "migration_port_min" = "49152" }
|
|
|
9119d9 |
{ "migration_port_max" = "49215" }
|
|
|
9119d9 |
{ "log_timestamp" = "0" }
|
|
|
9119d9 |
+{ "nvram"
|
|
|
9119d9 |
+ { "1" = "/usr/share/OVMF/OVMF_CODE.fd:/usr/share/OVMF/OVMF_VARS.fd" }
|
|
|
9119d9 |
+}
|
|
|
9119d9 |
diff --git a/tests/domainschemadata/domain-bios-nvram-empty.xml b/tests/domainschemadata/domain-bios-nvram-empty.xml
|
|
|
9119d9 |
new file mode 100644
|
|
|
9119d9 |
index 0000000..e7643f3
|
|
|
9119d9 |
--- /dev/null
|
|
|
9119d9 |
+++ b/tests/domainschemadata/domain-bios-nvram-empty.xml
|
|
|
9119d9 |
@@ -0,0 +1,40 @@
|
|
|
9119d9 |
+<domain type='qemu'>
|
|
|
9119d9 |
+ <name>test-bios</name>
|
|
|
9119d9 |
+ <uuid>362d1fc1-df7d-193e-5c18-49a71bd1da66</uuid>
|
|
|
9119d9 |
+ <memory unit='KiB'>1048576</memory>
|
|
|
9119d9 |
+ <currentMemory unit='KiB'>1048576</currentMemory>
|
|
|
9119d9 |
+ <vcpu placement='static'>1</vcpu>
|
|
|
9119d9 |
+ <os>
|
|
|
9119d9 |
+ <type arch='x86_64' machine='pc'>hvm</type>
|
|
|
9119d9 |
+ <loader readonly='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.fd</loader>
|
|
|
9119d9 |
+ <nvram template='/usr/share/OVMF/OVMF_VARS.fd'/>
|
|
|
9119d9 |
+ <boot dev='hd'/>
|
|
|
9119d9 |
+ <bootmenu enable='yes'/>
|
|
|
9119d9 |
+ </os>
|
|
|
9119d9 |
+ <features>
|
|
|
9119d9 |
+ <acpi/>
|
|
|
9119d9 |
+ </features>
|
|
|
9119d9 |
+ <clock offset='utc'/>
|
|
|
9119d9 |
+ <on_poweroff>destroy</on_poweroff>
|
|
|
9119d9 |
+ <on_reboot>restart</on_reboot>
|
|
|
9119d9 |
+ <on_crash>restart</on_crash>
|
|
|
9119d9 |
+ <devices>
|
|
|
9119d9 |
+ <emulator>/usr/bin/qemu</emulator>
|
|
|
9119d9 |
+ <disk type='block' device='disk'>
|
|
|
9119d9 |
+ <source dev='/dev/HostVG/QEMUGuest1'/>
|
|
|
9119d9 |
+ <target dev='hda' bus='ide'/>
|
|
|
9119d9 |
+ <address type='drive' controller='0' bus='0' target='0' unit='0'/>
|
|
|
9119d9 |
+ </disk>
|
|
|
9119d9 |
+ <controller type='usb' index='0'/>
|
|
|
9119d9 |
+ <controller type='ide' index='0'/>
|
|
|
9119d9 |
+ <controller type='pci' index='0' model='pci-root'/>
|
|
|
9119d9 |
+ <serial type='pty'>
|
|
|
9119d9 |
+ <target port='0'/>
|
|
|
9119d9 |
+ </serial>
|
|
|
9119d9 |
+ <console type='pty'>
|
|
|
9119d9 |
+ <target type='serial' port='0'/>
|
|
|
9119d9 |
+ </console>
|
|
|
9119d9 |
+ <input type='tablet' bus='usb'/>
|
|
|
9119d9 |
+ <memballoon model='virtio'/>
|
|
|
9119d9 |
+ </devices>
|
|
|
9119d9 |
+</domain>
|
|
|
9119d9 |
--
|
|
|
9119d9 |
2.1.0
|
|
|
9119d9 |
|