[PATCH 13/13] qemu: process: Introduce setup of block-device backed NVRAM

Peter Krempa posted 13 patches 2 weeks, 2 days ago
[PATCH 13/13] qemu: process: Introduce setup of block-device backed NVRAM
Posted by Peter Krempa 2 weeks, 2 days ago
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 <pkrempa@redhat.com>
---
 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:
-- 
2.47.0