[libvirt] [PATCH 06/11] qemu: block: Add generator for image format creation properties

Peter Krempa pkrempa at redhat.com
Thu Jul 4 14:26:30 UTC 2019


'blockdev-add' allows us to use qemu to format images to our desired
format. This patch implements helpers which convert a
virStorageSourcePtr into JSON objects describing the required
configuration.

Signed-off-by: Peter Krempa <pkrempa at redhat.com>
---
 src/qemu/qemu_block.c | 321 ++++++++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_block.h |   6 +
 2 files changed, 327 insertions(+)

diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c
index 9abdac5ca3..54dd2b5328 100644
--- a/src/qemu/qemu_block.c
+++ b/src/qemu/qemu_block.c
@@ -1866,3 +1866,324 @@ qemuBlockStorageGetCopyOnReadProps(virDomainDiskDefPtr disk)

     return ret;
 }
+
+
+static int
+qemuBlockStorageSourceCreateAddBacking(virStorageSourcePtr backing,
+                                       virJSONValuePtr props,
+                                       bool format)
+{
+    VIR_AUTOPTR(virJSONValue) backingProps = NULL;
+    VIR_AUTOFREE(char *) backingJSON = NULL;
+    VIR_AUTOFREE(char *) backingPseudoprotocol = NULL;
+    const char *backingFileStr = NULL;
+    const char *backingFormatStr = NULL;
+
+    if (!virStorageSourceIsBacking(backing))
+        return 0;
+
+    if (format) {
+        if (backing->encryption &&
+            backing->encryption->format == VIR_STORAGE_ENCRYPTION_FORMAT_LUKS)
+            backingFormatStr = "luks";
+        else
+            backingFormatStr = virStorageFileFormatTypeToString(backing->format);
+    }
+
+    if (virStorageSourceIsLocalStorage(backing)) {
+        backingFileStr = backing->path;
+    } else {
+        if (!(backingProps = qemuBlockStorageSourceGetBackendProps(backing, false,
+                                                                   true, false))) {
+            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+                           _("failed to generate backing file JSON properties"));
+            return -1;
+        }
+
+        if (!(backingJSON = virJSONValueToString(backingProps, false)))
+            return -1;
+
+        if (virAsprintf(&backingPseudoprotocol, "json:%s", backingJSON) < 0)
+            return -1;
+
+        backingFileStr = backingPseudoprotocol;
+    }
+
+    if (virJSONValueObjectAdd(props,
+                              "S:backing-file", backingFileStr,
+                              "S:backing-fmt", backingFormatStr,
+                              NULL) < 0)
+        return -1;
+
+    return 0;
+}
+
+
+static int
+qemuBlockStorageSourceCreateGetFormatPropsGeneric(virStorageSourcePtr src,
+                                                  const char *driver,
+                                                  virJSONValuePtr *retprops,
+                                                  virStorageSourcePtr backing)
+{
+    VIR_AUTOPTR(virJSONValue) props = NULL;
+
+    if (virJSONValueObjectCreate(&props,
+                                 "s:driver", driver,
+                                 "s:file", src->nodestorage,
+                                 "u:size", src->capacity,
+                                 NULL) < 0)
+        return -1;
+
+    if (backing &&
+        qemuBlockStorageSourceCreateAddBacking(backing, props, false) < 0)
+        return -1;
+
+    VIR_STEAL_PTR(*retprops, props);
+    return 0;
+}
+
+
+static int
+qemuBlockStorageSourceCreateGetEncryptionLUKS(virStorageSourcePtr src,
+                                              virJSONValuePtr *luksProps)
+{
+    qemuDomainStorageSourcePrivatePtr srcpriv = QEMU_DOMAIN_STORAGE_SOURCE_PRIVATE(src);
+    VIR_AUTOPTR(virJSONValue) props = NULL;
+    VIR_AUTOFREE(char *) cipheralg = NULL;
+    const char *keysecret = NULL;
+
+    if (srcpriv &&
+        srcpriv->encinfo &&
+        srcpriv->encinfo->type == VIR_DOMAIN_SECRET_INFO_TYPE_AES)
+        keysecret = srcpriv->encinfo->s.aes.alias;
+
+    if (virJSONValueObjectCreate(&props,
+                                 "s:key-secret", keysecret,
+                                 NULL) < 0)
+        return -1;
+
+    if (src->encryption) {
+        if (src->encryption->encinfo.cipher_name &&
+            virAsprintf(&cipheralg, "%s-%u",
+                        src->encryption->encinfo.cipher_name,
+                        src->encryption->encinfo.cipher_size) < 0)
+            return -1;
+
+        if (virJSONValueObjectAdd(props,
+                                  "S:cipher-alg", cipheralg,
+                                  "S:cipher-mode", src->encryption->encinfo.cipher_mode,
+                                  "S:hash-alg", src->encryption->encinfo.cipher_hash,
+                                  "S:ivgen-alg", src->encryption->encinfo.ivgen_name,
+                                  "S:ivgen-hash-alg", src->encryption->encinfo.ivgen_hash,
+                                  NULL) < 0)
+            return -1;
+    }
+
+    VIR_STEAL_PTR(*luksProps, props);
+    return 0;
+}
+
+
+static int
+qemuBlockStorageSourceCreateGetFormatPropsLUKS(virStorageSourcePtr src,
+                                               virJSONValuePtr *props)
+{
+    VIR_AUTOPTR(virJSONValue) luksprops = NULL;
+
+    if (qemuBlockStorageSourceCreateGetEncryptionLUKS(src, &luksprops) < 0)
+        return -1;
+
+    if (virJSONValueObjectAdd(luksprops,
+                              "s:driver", "luks",
+                              "s:file", src->nodestorage,
+                              "u:size", src->capacity,
+                              NULL) < 0)
+        return -1;
+
+    VIR_STEAL_PTR(*props, luksprops);
+    return 0;
+}
+
+
+static int
+qemuBlockStorageSourceCreateAddEncryptionQcow(virStorageSourcePtr src,
+                                              virJSONValuePtr props)
+{
+    VIR_AUTOPTR(virJSONValue) encryptProps = NULL;
+
+    if (!src->encryption)
+        return 0;
+
+    if (src->encryption->format != VIR_STORAGE_ENCRYPTION_FORMAT_LUKS) {
+        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+                       _("creation of qcow/qcow2 files supports only 'luks' encryption"));
+        return -1;
+    }
+
+    if (qemuBlockStorageSourceCreateGetEncryptionLUKS(src, &encryptProps) < 0)
+        return -1;
+
+    if (virJSONValueObjectAdd(encryptProps, "s:format", "luks", NULL) < 0)
+        return -1;
+
+    if (virJSONValueObjectAdd(props, "a:encrypt", &encryptProps, NULL) < 0)
+        return -1;
+
+    return 0;
+}
+
+
+static int
+qemuBlockStorageSourceCreateGetFormatPropsQcow2(virStorageSourcePtr src,
+                                                virStorageSourcePtr backing,
+                                                virJSONValuePtr *props)
+{
+    VIR_AUTOPTR(virJSONValue) qcow2props = NULL;
+    const char *qcow2version = NULL;
+
+    if (STREQ_NULLABLE(src->compat, "0.10"))
+        qcow2version = "v2";
+    else if (STREQ_NULLABLE(src->compat, "1.1"))
+        qcow2version = "v3";
+
+    if (virJSONValueObjectCreate(&qcow2props,
+                                 "s:driver", "qcow2",
+                                 "s:file", src->nodestorage,
+                                 "u:size", src->capacity,
+                                 "S:version", qcow2version,
+                                 NULL) < 0)
+        return -1;
+
+    if (qemuBlockStorageSourceCreateAddBacking(backing, qcow2props, true) < 0 ||
+        qemuBlockStorageSourceCreateAddEncryptionQcow(src, qcow2props) < 0)
+        return -1;
+
+    VIR_STEAL_PTR(*props, qcow2props);
+    return 0;
+}
+
+
+static int
+qemuBlockStorageSourceCreateGetFormatPropsQcow(virStorageSourcePtr src,
+                                               virStorageSourcePtr backing,
+                                               virJSONValuePtr *props)
+{
+    VIR_AUTOPTR(virJSONValue) qcowprops = NULL;
+
+    if (virJSONValueObjectCreate(&qcowprops,
+                                 "s:driver", "qcow",
+                                 "s:file", src->nodestorage,
+                                 "u:size", src->capacity,
+                                 NULL) < 0)
+        return -1;
+
+    if (qemuBlockStorageSourceCreateAddBacking(backing, qcowprops, false) < 0 ||
+        qemuBlockStorageSourceCreateAddEncryptionQcow(src, qcowprops) < 0)
+        return -1;
+
+    VIR_STEAL_PTR(*props, qcowprops);
+    return 0;
+}
+
+
+static int
+qemuBlockStorageSourceCreateGetFormatPropsQed(virStorageSourcePtr src,
+                                              virStorageSourcePtr backing,
+                                              virJSONValuePtr *props)
+{
+    VIR_AUTOPTR(virJSONValue) qedprops = NULL;
+
+    if (virJSONValueObjectCreate(&qedprops,
+                                 "s:driver", "qed",
+                                 "s:file", src->nodestorage,
+                                 "u:size", src->capacity,
+                                 NULL) < 0)
+        return -1;
+
+    if (qemuBlockStorageSourceCreateAddBacking(backing, qedprops, true) < 0)
+        return -1;
+
+    VIR_STEAL_PTR(*props, qedprops);
+    return 0;
+}
+
+
+/**
+ * qemuBlockStorageSourceCreateGetFormatProps:
+ * @src: storage source to format
+ * @backing: storage source describing backing image of @src (if necessary)
+ * @props: filled with props to be used with 'blockdev-create' to format @src
+ *
+ * @src must be properly initialized to contain node-names of the protocol layer
+ * which should be formatted. @props may be NULL with success returned in which
+ * case creation of given storage format is not supported. Note that creation
+ * of 'raw' storage is also returns NULL as there is nothing to do.
+ */
+int
+qemuBlockStorageSourceCreateGetFormatProps(virStorageSourcePtr src,
+                                           virStorageSourcePtr backing,
+                                           virJSONValuePtr *props)
+{
+    switch ((virStorageFileFormat) src->format) {
+    case VIR_STORAGE_FILE_RAW:
+        if (!src->encryption ||
+            src->encryption->format != VIR_STORAGE_ENCRYPTION_FORMAT_LUKS)
+            return 0;
+
+        return qemuBlockStorageSourceCreateGetFormatPropsLUKS(src, props);
+
+    case VIR_STORAGE_FILE_QCOW2:
+        return qemuBlockStorageSourceCreateGetFormatPropsQcow2(src, backing, props);
+
+    case VIR_STORAGE_FILE_QCOW:
+        return qemuBlockStorageSourceCreateGetFormatPropsQcow(src, backing, props);
+
+    case VIR_STORAGE_FILE_QED:
+        return qemuBlockStorageSourceCreateGetFormatPropsQed(src, backing, props);
+
+    case VIR_STORAGE_FILE_VPC:
+        return qemuBlockStorageSourceCreateGetFormatPropsGeneric(src, "vpc",
+                                                                 props, NULL);
+
+    case VIR_STORAGE_FILE_PLOOP:
+        return qemuBlockStorageSourceCreateGetFormatPropsGeneric(src, "parallels",
+                                                                 props, NULL);
+
+    case VIR_STORAGE_FILE_VDI:
+        return qemuBlockStorageSourceCreateGetFormatPropsGeneric(src, "vdi",
+                                                                 props, NULL);
+
+    case VIR_STORAGE_FILE_VHD:
+        return qemuBlockStorageSourceCreateGetFormatPropsGeneric(src, "vhdx",
+                                                                 props, NULL);
+
+    case VIR_STORAGE_FILE_VMDK:
+        return qemuBlockStorageSourceCreateGetFormatPropsGeneric(src, "vmdk",
+                                                                 props, backing);
+
+    /* unsupported by qemu / impossible */
+    case VIR_STORAGE_FILE_FAT:
+    case VIR_STORAGE_FILE_BOCHS:
+    case VIR_STORAGE_FILE_CLOOP:
+    case VIR_STORAGE_FILE_DMG:
+    case VIR_STORAGE_FILE_COW:
+    case VIR_STORAGE_FILE_ISO:
+    case VIR_STORAGE_FILE_DIR:
+        return 0;
+
+    case VIR_STORAGE_FILE_AUTO_SAFE:
+    case VIR_STORAGE_FILE_AUTO:
+    case VIR_STORAGE_FILE_NONE:
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("mishandled storage format '%s'"),
+                       virStorageFileFormatTypeToString(src->format));
+        return -1;
+
+    case VIR_STORAGE_FILE_LAST:
+    default:
+        break;
+    }
+
+    virReportEnumRangeError(virStorageFileFormat, src->format);
+    return -1;
+}
diff --git a/src/qemu/qemu_block.h b/src/qemu/qemu_block.h
index 12ddfad2ac..738ef9e8b0 100644
--- a/src/qemu/qemu_block.h
+++ b/src/qemu/qemu_block.h
@@ -162,3 +162,9 @@ qemuBlockSnapshotAddLegacy(virJSONValuePtr actions,
                            virDomainDiskDefPtr disk,
                            virStorageSourcePtr newsrc,
                            bool reuse);
+
+int
+qemuBlockStorageSourceCreateGetFormatProps(virStorageSourcePtr src,
+                                           virStorageSourcePtr backing,
+                                           virJSONValuePtr *props)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3) ATTRIBUTE_RETURN_CHECK;
-- 
2.21.0




More information about the libvir-list mailing list