From nobody Mon Feb 9 13:59:07 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1562250599; cv=none; d=zoho.com; s=zohoarc; b=hE33uwkobE/YPGjechTe/6xsB1gi23NURuwFdaBe97bdBHL9ShK/ywab66cZti21VFzEjyOK6bas3v15/n1bGxlVieVBJyBzoSVC3do3wHRJ+DrxZXOeBKYtPA67REyXkfvgtOAiKy4sYCXWArwpCw982DMcRVnAdWtS27srWdE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1562250599; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=/KkRrX9WQmPAPhzVu4jB0pxZRXWOT5iTYxHtCOj+sgY=; b=JECvPxulWfoG2qkOfI6LLyD7KaIisKJc66nZLi02JcqRB4QnY9Biu3KEdyXHSFSdIKAMF4JYeG9xaIEnGLP2t/ndbqWeLiPQheXiL23zrECWWAvZHkZVhJRy8L4FjIK2wCHxDvGYRjs+JCgxA0NXNPNWDrvH9QWqCkBazxk7Zuc= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) header.from= Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1562250599337805.1896490730102; Thu, 4 Jul 2019 07:29:59 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 11ED36749D; Thu, 4 Jul 2019 14:29:52 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id DA07F7DE4E; Thu, 4 Jul 2019 14:29:50 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 379CE1833003; Thu, 4 Jul 2019 14:29:48 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id x64EQjRE029969 for ; Thu, 4 Jul 2019 10:26:45 -0400 Received: by smtp.corp.redhat.com (Postfix) id 17A2F5B2FE; Thu, 4 Jul 2019 14:26:45 +0000 (UTC) Received: from angien.brq.redhat.com (unknown [10.43.2.229]) by smtp.corp.redhat.com (Postfix) with ESMTP id 710CB5B77E; Thu, 4 Jul 2019 14:26:44 +0000 (UTC) From: Peter Krempa To: libvir-list@redhat.com Date: Thu, 4 Jul 2019 16:26:30 +0200 Message-Id: <02a55a2192f112a146d4f25c03d01e7fa7b08712.1562249939.git.pkrempa@redhat.com> In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 X-loop: libvir-list@redhat.com Cc: Kevin Wolf Subject: [libvirt] [PATCH 06/11] qemu: block: Add generator for image format creation properties X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.30]); Thu, 04 Jul 2019 14:29:57 +0000 (UTC) Content-Type: text/plain; charset="utf-8" '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 Reviewed-by: J=C3=A1n Tomko --- 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(virDomainDiskDef= Ptr disk) return ret; } + + +static int +qemuBlockStorageSourceCreateAddBacking(virStorageSourcePtr backing, + virJSONValuePtr props, + bool format) +{ + VIR_AUTOPTR(virJSONValue) backingProps =3D NULL; + VIR_AUTOFREE(char *) backingJSON =3D NULL; + VIR_AUTOFREE(char *) backingPseudoprotocol =3D NULL; + const char *backingFileStr =3D NULL; + const char *backingFormatStr =3D NULL; + + if (!virStorageSourceIsBacking(backing)) + return 0; + + if (format) { + if (backing->encryption && + backing->encryption->format =3D=3D VIR_STORAGE_ENCRYPTION_FORM= AT_LUKS) + backingFormatStr =3D "luks"; + else + backingFormatStr =3D virStorageFileFormatTypeToString(backing-= >format); + } + + if (virStorageSourceIsLocalStorage(backing)) { + backingFileStr =3D backing->path; + } else { + if (!(backingProps =3D qemuBlockStorageSourceGetBackendProps(backi= ng, false, + true, f= alse))) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("failed to generate backing file JSON propert= ies")); + return -1; + } + + if (!(backingJSON =3D virJSONValueToString(backingProps, false))) + return -1; + + if (virAsprintf(&backingPseudoprotocol, "json:%s", backingJSON) < = 0) + return -1; + + backingFileStr =3D 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 *retprop= s, + virStorageSourcePtr back= ing) +{ + VIR_AUTOPTR(virJSONValue) props =3D 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 =3D QEMU_DOMAIN_STORAGE_SOUR= CE_PRIVATE(src); + VIR_AUTOPTR(virJSONValue) props =3D NULL; + VIR_AUTOFREE(char *) cipheralg =3D NULL; + const char *keysecret =3D NULL; + + if (srcpriv && + srcpriv->encinfo && + srcpriv->encinfo->type =3D=3D VIR_DOMAIN_SECRET_INFO_TYPE_AES) + keysecret =3D 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->encinf= o.cipher_mode, + "S:hash-alg", src->encryption->encinfo.c= ipher_hash, + "S:ivgen-alg", src->encryption->encinfo.= ivgen_name, + "S:ivgen-hash-alg", src->encryption->enc= info.ivgen_hash, + NULL) < 0) + return -1; + } + + VIR_STEAL_PTR(*luksProps, props); + return 0; +} + + +static int +qemuBlockStorageSourceCreateGetFormatPropsLUKS(virStorageSourcePtr src, + virJSONValuePtr *props) +{ + VIR_AUTOPTR(virJSONValue) luksprops =3D 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 =3D NULL; + + if (!src->encryption) + return 0; + + if (src->encryption->format !=3D 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 backin= g, + virJSONValuePtr *props) +{ + VIR_AUTOPTR(virJSONValue) qcow2props =3D NULL; + const char *qcow2version =3D NULL; + + if (STREQ_NULLABLE(src->compat, "0.10")) + qcow2version =3D "v2"; + else if (STREQ_NULLABLE(src->compat, "1.1")) + qcow2version =3D "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 =3D 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 =3D 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 creat= ion + * 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 !=3D VIR_STORAGE_ENCRYPTION_FORMAT_LUK= S) + return 0; + + return qemuBlockStorageSourceCreateGetFormatPropsLUKS(src, props); + + case VIR_STORAGE_FILE_QCOW2: + return qemuBlockStorageSourceCreateGetFormatPropsQcow2(src, backin= g, 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, NU= LL); + + case VIR_STORAGE_FILE_PLOOP: + return qemuBlockStorageSourceCreateGetFormatPropsGeneric(src, "par= allels", + props, NU= LL); + + case VIR_STORAGE_FILE_VDI: + return qemuBlockStorageSourceCreateGetFormatPropsGeneric(src, "vdi= ", + props, NU= LL); + + case VIR_STORAGE_FILE_VHD: + return qemuBlockStorageSourceCreateGetFormatPropsGeneric(src, "vhd= x", + props, NU= LL); + + case VIR_STORAGE_FILE_VMDK: + return qemuBlockStorageSourceCreateGetFormatPropsGeneric(src, "vmd= k", + props, ba= cking); + + /* 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; --=20 2.21.0 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list