From f35f817ebf944392066d0cbc0502d16ecfcbc10e Mon Sep 17 00:00:00 2001 From: Peter Krempa Date: Fri, 18 Oct 2024 15:55:44 +0200 Subject: [PATCH] qemu: process: Introduce setup of block-device backed NVRAM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In case when a management application will require to store the nvram in a block device instead of a file libvirt needs to be able to set up the block device. This patch introduces support for setting up the block device by using 'qemu-img convert' to produce a qcow2-formatted block device. The use of 'qcow2' is made mandatory as the UEFI firmware requires that the NVRAM image has the exact expected size, which is almost impossible with block devices. 'qcow2' also allows libvirt to detect wheher the block device is formatted allowing file-like semantics. Signed-off-by: Peter Krempa Reviewed-by: Michal Privoznik Reviewed-by: Ján Tomko --- src/qemu/qemu_process.c | 74 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 66 insertions(+), 8 deletions(-) diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 7fbf18ec10..c25929da90 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -101,6 +101,7 @@ #include "virutil.h" #include "storage_source.h" #include "backup_conf.h" +#include "storage_file_probe.h" #include "logging/log_manager.h" #include "logging/log_protocol.h" @@ -4583,6 +4584,70 @@ qemuPrepareNVRAMHelper(int dstFD, } +static int +qemuPrepareNVRAMBlock(virDomainObj *vm, + bool reset_nvram) +{ + virDomainLoaderDef *loader = vm->def->os.loader; + g_autoptr(virCommand) qemuimg = NULL; + const char *templateFormatStr = "raw"; + + if (!virFileExists(loader->nvram->path)) { + virReportError(VIR_ERR_INVALID_ARG, + _("'block' nvram backing device '%1$s' doesn't exist"), + loader->nvram->path); + return -1; + } + + if (!reset_nvram) { + int format; + + if (loader->nvram->format == VIR_STORAGE_FILE_RAW) { + /* For 'raw' image libvirt can't check if the image is correct */ + return 0; + } + + if ((format = virStorageFileProbeFormat(loader->nvram->path, 0, 0)) < 0) + return -1; + + /* If we find a qcow2 image assume it's correct */ + if (format == VIR_STORAGE_FILE_QCOW2) + return 0; + } + + /* The PFLASH device backing the NVRAM must have the exact size the + * firmware expects. This is almost impossible to achieve using a block + * device. Avoid headaches -> force users to use qcow2 which can + * restrict the size if libvirt is to format the image. */ + if (loader->nvram->format != VIR_STORAGE_FILE_QCOW2) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("only 'qcow2' formatted 'block' nvram backing can be formatted")); + return -1; + } + + if (!loader->nvramTemplate) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("unable to find nvram template image")); + return -1; + } + + if (loader->nvramTemplateFormat != VIR_STORAGE_FILE_NONE) + templateFormatStr = virStorageFileFormatTypeToString(loader->nvramTemplateFormat); + + qemuimg = virCommandNewArgList("qemu-img", "convert", + "-f", templateFormatStr, + "-O", "qcow2", + loader->nvramTemplate, + loader->nvram->path, + NULL); + + if (virCommandRun(qemuimg, NULL) < 0) + return -1; + + return 0; +} + + static int qemuPrepareNVRAMFile(virDomainObj *vm, bool reset_nvram) @@ -4646,14 +4711,7 @@ qemuPrepareNVRAM(virDomainObj *vm, return qemuPrepareNVRAMFile(vm, reset_nvram); case VIR_STORAGE_TYPE_BLOCK: - /* virFileRewrite() would overwrite the device node-file/symlink rather than - * just write the data to it, thus block-device nvram is not yet supported */ - if (virFileExists(loader->nvram->path) && !reset_nvram) - return 0; - - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", - _("creation or formatting of nvram type='block' is not supported")); - return -1; + return qemuPrepareNVRAMBlock(vm, reset_nvram); case VIR_STORAGE_TYPE_DIR: case VIR_STORAGE_TYPE_NETWORK: