[libvirt] [PATCH v1 3/3] qemu: Automatically create NVRAM store
Paolo Bonzini
pbonzini at redhat.com
Fri Aug 8 12:05:04 UTC 2014
Il 08/08/2014 12:17, Michal Privoznik ha scritto:
> When using split UEFI image, it may come handy if libvirt manages per
> domain _VARS file automatically. While the _CODE file is RO and can be
> shared among multiple domains, you certainly don't want to do that on
> the _VARS file. This latter one needs to be per domain. So at the
> domain startup process, if it's determined that domain needs _VARS
> file it's copied from this master _VARS file. The location of the
> master file is configurable in qemu.conf and the default path can be
> compiled in via --with-qemu-nvram-file configure option.
The only problem I see with this series is in this patch.
The master _VARS file can be different for different machine types, for
different architectures, and even for different _CODE files.
Perhaps you could introduce a format='...' attribute in <nvram> and use
that to pick the right master file (e.g. a format value could be
uefi128k)? I don't like it, but I cannot think of anything else.
Or just leave out this patch for now...
Paolo
> Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
> ---
> configure.ac | 27 ++++++++
> libvirt.spec.in | 2 +
> src/Makefile.am | 1 +
> src/qemu/libvirtd_qemu.aug | 3 +
> src/qemu/qemu.conf | 9 +++
> src/qemu/qemu_conf.c | 8 +++
> src/qemu/qemu_conf.h | 3 +
> src/qemu/qemu_process.c | 125 +++++++++++++++++++++++++++++++++++++
> src/qemu/test_libvirtd_qemu.aug.in | 1 +
> 9 files changed, 179 insertions(+)
>
> diff --git a/configure.ac b/configure.ac
> index 9dd07d2..16ca266 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -569,6 +569,11 @@ AC_ARG_WITH([chrdev-lock-files],
> [location for UUCP style lock files for character devices
> (use auto for default paths on some platforms) @<:@default=auto@:>@])])
> m4_divert_text([DEFAULTS], [with_chrdev_lock_files=auto])
> +AC_ARG_WITH([qemu-nvram-file],
> + [AS_HELP_STRING([--with-qemu-nvram-file],
> + [location of OVMF_VARS.fd file
> + (use auto for default path on some platforms) @<:@default=auto@:>@])])
> +m4_divert_text([DEFAULTS], [with_qemu_nvram_file=auto])
> AC_ARG_WITH([pm-utils],
> [AS_HELP_STRING([--with-pm-utils],
> [use pm-utils for power management @<:@default=yes@:>@])])
> @@ -1418,6 +1423,27 @@ platform])
> fi
> AM_CONDITIONAL([VIR_CHRDEV_LOCK_FILE_PATH], [test "$with_chrdev_lock_files" != "no"])
>
> +dnl OVMF_VARS.fd file
> +if test "$with_qemu_nvram_file" != "no"; then
> + case $with_qemu_nvram_file in
> + yes | auto)
> + dnl Default locations for platforms, or disable if unknown
> + if test "$with_linux" = "yes"; then
> + with_qemu_nvram_file=/usr/share/OVMF/OVMF_VARS.fd
> + elif test "$with_chrdev_lock_files" = "auto"; then
> + with_qemu_nvram_file=no
> + fi ;;
> + esac
> + if test "$with_qemu_nvram_file" = "yes"; then
> + AC_MSG_ERROR([You must specify path for the lock files on this
> +platform])
> + fi
> + if test "$with_qemu_nvram_file" != "no"; then
> + AC_DEFINE_UNQUOTED([VIR_QEMU_NVRAM_FILE_PATH], "$with_qemu_nvram_file",
> + [default path to OVMF_VARS.fd file])
> + fi
> +fi
> +AM_CONDITIONAL([VIR_QEMU_NVRAM_FILE_PATH], [test "$with_qemu_nvram_file" != "no"])
>
> AC_ARG_WITH([secdriver-selinux],
> [AS_HELP_STRING([--with-secdriver-selinux],
> @@ -2925,6 +2951,7 @@ AC_MSG_NOTICE([ numad: $with_numad])
> AC_MSG_NOTICE([ XML Catalog: $XML_CATALOG_FILE])
> AC_MSG_NOTICE([ Init script: $with_init_script])
> AC_MSG_NOTICE([Char device locks: $with_chrdev_lock_files])
> +AC_MSG_NOTICE([ OVMF_VARS.fd loc: $with_qemu_nvram_file])
> AC_MSG_NOTICE([])
> AC_MSG_NOTICE([Developer Tools])
> AC_MSG_NOTICE([])
> diff --git a/libvirt.spec.in b/libvirt.spec.in
> index 29da071..486fc66 100644
> --- a/libvirt.spec.in
> +++ b/libvirt.spec.in
> @@ -1947,6 +1947,7 @@ exit 0
> %dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/lib/libvirt/qemu/
> %dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/lib/libvirt/qemu/channel/
> %dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/lib/libvirt/qemu/channel/target/
> +%dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/lib/libvirt/qemu/nvram/
> %dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/cache/libvirt/qemu/
> %{_datadir}/augeas/lenses/libvirtd_qemu.aug
> %{_datadir}/augeas/lenses/tests/test_libvirtd_qemu.aug
> @@ -2049,6 +2050,7 @@ exit 0
> %dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/lib/libvirt/qemu/
> %dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/lib/libvirt/qemu/channel/
> %dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/lib/libvirt/qemu/channel/target/
> +%dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/lib/libvirt/qemu/nvram/
> %dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/cache/libvirt/qemu/
> %{_datadir}/augeas/lenses/libvirtd_qemu.aug
> %{_datadir}/augeas/lenses/tests/test_libvirtd_qemu.aug
> diff --git a/src/Makefile.am b/src/Makefile.am
> index 982f63d..9bd38f5 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -2632,6 +2632,7 @@ endif WITH_SANLOCK
> if WITH_QEMU
> $(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/qemu"
> $(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/qemu/channel/target"
> + $(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/qemu/nvram"
> $(MKDIR_P) "$(DESTDIR)$(localstatedir)/run/libvirt/qemu"
> $(MKDIR_P) "$(DESTDIR)$(localstatedir)/cache/libvirt/qemu"
> $(MKDIR_P) "$(DESTDIR)$(localstatedir)/log/libvirt/qemu"
> diff --git a/src/qemu/libvirtd_qemu.aug b/src/qemu/libvirtd_qemu.aug
> index e7db7fe..3d9db99 100644
> --- a/src/qemu/libvirtd_qemu.aug
> +++ b/src/qemu/libvirtd_qemu.aug
> @@ -88,6 +88,8 @@ module Libvirtd_qemu =
>
> let log_entry = bool_entry "log_timestamp"
>
> + let nvram_entry = str_entry "nvram"
> +
> (* Each entry in the config is one of the following ... *)
> let entry = vnc_entry
> | spice_entry
> @@ -100,6 +102,7 @@ module Libvirtd_qemu =
> | rpc_entry
> | network_entry
> | log_entry
> + | nvram_entry
>
> let comment = [ label "#comment" . del /#[ \t]*/ "# " . store /([^ \t\n][^\n]*)?/ . del /\n/ "\n" ]
> let empty = [ label "#empty" . eol ]
> diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf
> index 7bbbe09..a0c9485 100644
> --- a/src/qemu/qemu.conf
> +++ b/src/qemu/qemu.conf
> @@ -487,3 +487,12 @@
> # Defaults to 1.
> #
> #log_timestamp = 0
> +
> +
> +# Location of master nvram file
> +#
> +# When a domain is configured to use UEFI instead of standard
> +# BIOS it may use a separate storage for UEFI variables. If
> +# that's the case libvirt creates the variable store per domain
> +# using this master file as image.
> +#nvram = "/usr/share/OVMF/OVMF_VARS.fd"
> diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
> index 6bfa48e..3f6d365 100644
> --- a/src/qemu/qemu_conf.c
> +++ b/src/qemu/qemu_conf.c
> @@ -255,6 +255,11 @@ virQEMUDriverConfigPtr virQEMUDriverConfigNew(bool privileged)
>
> cfg->logTimestamp = true;
>
> +#ifdef VIR_QEMU_NVRAM_FILE_PATH
> + if (VIR_STRDUP(cfg->nvram, VIR_QEMU_NVRAM_FILE_PATH) < 0)
> + goto error;
> +#endif
> +
> return cfg;
>
> error:
> @@ -305,6 +310,7 @@ static void virQEMUDriverConfigDispose(void *obj)
> virStringFreeList(cfg->securityDriverNames);
>
> VIR_FREE(cfg->lockManagerName);
> + VIR_FREE(cfg->nvram);
> }
>
>
> @@ -654,6 +660,8 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg,
>
> GET_VALUE_BOOL("log_timestamp", cfg->logTimestamp);
>
> + GET_VALUE_STR("nvram", cfg->nvram);
> +
> ret = 0;
>
> cleanup:
> diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
> index 90aebef..0bb5333 100644
> --- a/src/qemu/qemu_conf.h
> +++ b/src/qemu/qemu_conf.h
> @@ -172,6 +172,9 @@ struct _virQEMUDriverConfig {
> int migrationPortMax;
>
> bool logTimestamp;
> +
> + char *nvram; /* path to master NVRAM file from which
> + copies per domain are derived */
> };
>
> /* Main driver state */
> diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
> index 407da5e..2cb693a 100644
> --- a/src/qemu/qemu_process.c
> +++ b/src/qemu/qemu_process.c
> @@ -66,6 +66,7 @@
> #include "virnuma.h"
> #include "virstring.h"
> #include "virhostdev.h"
> +#include "configmake.h"
>
> #define VIR_FROM_THIS VIR_FROM_QEMU
>
> @@ -3714,6 +3715,123 @@ qemuProcessVerifyGuestCPU(virQEMUDriverPtr driver, virDomainObjPtr vm)
> }
>
>
> +static int
> +qemuPrepareNVRAM(virQEMUDriverConfigPtr cfg,
> + virDomainDefPtr def,
> + bool migrated)
> +{
> + int ret = -1;
> + int srcFD = -1;
> + int dstFD = -1;
> + virDomainLoaderDefPtr loader = def->os.loader;
> + bool generated = false;
> +
> + /* Unless domain has RO loader of pflash type, we have
> + * nothing to do here. If the loader is RW then it's not
> + * using split code and vars feature, so no nvram file needs
> + * to be created. */
> + if (!loader || loader->type != VIR_DOMAIN_LOADER_TYPE_PFLASH ||
> + loader->readonly != VIR_TRISTATE_SWITCH_ON)
> + return 0;
> +
> + /* If the nvram path is configured already, there's nothing
> + * we need to do. Unless we are starting the destination side
> + * of migration in which case nvram is configured in the
> + * domain XML but the file doesn't exist yet. Moreover, after
> + * the migration is completed, qemu will invoke a
> + * synchronization write into the nvram file so we don't have
> + * to take care about transmitting the real data on the other
> + * side. */
> + if (loader->nvram && !migrated)
> + return 0;
> +
> + /* Autogenerate nvram path if needed.*/
> + if (!loader->nvram) {
> + if (virAsprintf(&loader->nvram,
> + "%s/lib/libvirt/qemu/nvram/%s_VARS.fd",
> + LOCALSTATEDIR, def->name) < 0)
> + goto cleanup;
> +
> + generated = true;
> + }
> +
> + if (!virFileExists(loader->nvram)) {
> + ssize_t r = -1;
> +
> + if (!cfg->nvram) {
> + virReportError(VIR_ERR_OPERATION_FAILED, "%s",
> + _("master NVRAM file is not configured "
> + "or turned off by administrator"));
> + goto cleanup;
> + }
> +
> + if ((srcFD = virFileOpenAs(cfg->nvram, O_RDONLY,
> + 0, -1, -1, 0)) < 0) {
> + virReportSystemError(-srcFD,
> + _("Failed to open file '%s'"),
> + cfg->nvram);
> + goto cleanup;
> + }
> + if ((dstFD = virFileOpenAs(loader->nvram,
> + 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);
> + goto cleanup;
> + }
> +
> + while (r) {
> + char buf[1024];
> + ssize_t w = 0;
> +
> + if ((r = saferead(srcFD, buf, sizeof(buf))) < 0) {
> + virReportSystemError(errno,
> + _("Unable to read from file '%s'"),
> + cfg->nvram);
> + goto cleanup;
> + }
> +
> + do {
> + ssize_t actW;
> + if ((actW = safewrite(dstFD, buf + w, r - w)) < 0) {
> + virReportSystemError(errno,
> + _("Unable to write to file '%s'"),
> + loader->nvram);
> + goto cleanup;
> + }
> + w += actW;
> + } while (w != r);
> + }
> +
> + if (VIR_CLOSE(srcFD) < 0) {
> + virReportSystemError(errno,
> + _("Unable to close file '%s'"),
> + cfg->nvram);
> + goto cleanup;
> + }
> + if (VIR_CLOSE(dstFD) < 0) {
> + virReportSystemError(errno,
> + _("Unable to close file '%s'"),
> + loader->nvram);
> + goto cleanup;
> + }
> + }
> +
> + ret = 0;
> + cleanup:
> + /* We successfully generated the nvram path, but failed to
> + * copy the file content. Roll back. */
> + if (ret < 0 && generated)
> + VIR_FREE(loader->nvram);
> +
> + VIR_FORCE_CLOSE(srcFD);
> + VIR_FORCE_CLOSE(dstFD);
> + return ret;
> +}
> +
> +
> int qemuProcessStart(virConnectPtr conn,
> virQEMUDriverPtr driver,
> virDomainObjPtr vm,
> @@ -3781,6 +3899,13 @@ int qemuProcessStart(virConnectPtr conn,
> if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
> goto cleanup;
>
> + /* Some things, paths, ... are generated here and we want them to persist.
> + * Fill them in prior to setting the domain def as transient. */
> + VIR_DEBUG("Generating paths");
> +
> + if (qemuPrepareNVRAM(cfg, vm->def, migrateFrom) < 0)
> + goto cleanup;
> +
> /* Do this upfront, so any part of the startup process can add
> * runtime state to vm->def that won't be persisted. This let's us
> * report implicit runtime defaults in the XML, like vnc listen/socket
> diff --git a/src/qemu/test_libvirtd_qemu.aug.in b/src/qemu/test_libvirtd_qemu.aug.in
> index 7796acc..1ecb690 100644
> --- a/src/qemu/test_libvirtd_qemu.aug.in
> +++ b/src/qemu/test_libvirtd_qemu.aug.in
> @@ -74,3 +74,4 @@ module Test_libvirtd_qemu =
> { "migration_port_min" = "49152" }
> { "migration_port_max" = "49215" }
> { "log_timestamp" = "0" }
> +{ "nvram" = "/usr/share/OVMF/OVMF_VARS.fd" }
>
More information about the libvir-list
mailing list