149 lines
5.3 KiB
Diff
149 lines
5.3 KiB
Diff
|
From e5d1850f80df1b548b1c3bdc0914e7790702d543 Mon Sep 17 00:00:00 2001
|
||
|
From: Stefan Hajnoczi <stefanha@redhat.com>
|
||
|
Date: Mon, 4 Mar 2019 08:54:26 +0000
|
||
|
Subject: [PATCH 3/9] qcow2: include LUKS payload overhead in qemu-img measure
|
||
|
MIME-Version: 1.0
|
||
|
Content-Type: text/plain; charset=UTF-8
|
||
|
Content-Transfer-Encoding: 8bit
|
||
|
|
||
|
RH-Author: Stefan Hajnoczi <stefanha@redhat.com>
|
||
|
Message-id: <20190304085427.8148-2-stefanha@redhat.com>
|
||
|
Patchwork-id: 84778
|
||
|
O-Subject: [RHEL-8.0/AV qemu-kvm PATCH 1/2] qcow2: include LUKS payload overhead in qemu-img measure
|
||
|
Bugzilla: 1655065
|
||
|
RH-Acked-by: Philippe Mathieu-Daudé <philmd@redhat.com>
|
||
|
RH-Acked-by: Stefano Garzarella <sgarzare@redhat.com>
|
||
|
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
|
||
|
|
||
|
LUKS encryption reserves clusters for its own payload data. The size of
|
||
|
this area must be included in the qemu-img measure calculation so that
|
||
|
we arrive at the correct minimum required image size.
|
||
|
|
||
|
(Ab)use the qcrypto_block_create() API to determine the payload
|
||
|
overhead. We discard the payload data that qcrypto thinks will be
|
||
|
written to the image.
|
||
|
|
||
|
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||
|
Reviewed-by: Max Reitz <mreitz@redhat.com>
|
||
|
Message-id: 20190218104525.23674-2-stefanha@redhat.com
|
||
|
Signed-off-by: Max Reitz <mreitz@redhat.com>
|
||
|
(cherry picked from commit 61914f8906fabbae26372a576d9dd988c5e22b75)
|
||
|
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||
|
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
|
||
|
---
|
||
|
block/qcow2.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
|
||
|
1 file changed, 71 insertions(+), 1 deletion(-)
|
||
|
|
||
|
diff --git a/block/qcow2.c b/block/qcow2.c
|
||
|
index 991d6ac..1b41e4c 100644
|
||
|
--- a/block/qcow2.c
|
||
|
+++ b/block/qcow2.c
|
||
|
@@ -4113,6 +4113,60 @@ static coroutine_fn int qcow2_co_flush_to_os(BlockDriverState *bs)
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
+static ssize_t qcow2_measure_crypto_hdr_init_func(QCryptoBlock *block,
|
||
|
+ size_t headerlen, void *opaque, Error **errp)
|
||
|
+{
|
||
|
+ size_t *headerlenp = opaque;
|
||
|
+
|
||
|
+ /* Stash away the payload size */
|
||
|
+ *headerlenp = headerlen;
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static ssize_t qcow2_measure_crypto_hdr_write_func(QCryptoBlock *block,
|
||
|
+ size_t offset, const uint8_t *buf, size_t buflen,
|
||
|
+ void *opaque, Error **errp)
|
||
|
+{
|
||
|
+ /* Discard the bytes, we're not actually writing to an image */
|
||
|
+ return buflen;
|
||
|
+}
|
||
|
+
|
||
|
+/* Determine the number of bytes for the LUKS payload */
|
||
|
+static bool qcow2_measure_luks_headerlen(QemuOpts *opts, size_t *len,
|
||
|
+ Error **errp)
|
||
|
+{
|
||
|
+ QDict *opts_qdict;
|
||
|
+ QDict *cryptoopts_qdict;
|
||
|
+ QCryptoBlockCreateOptions *cryptoopts;
|
||
|
+ QCryptoBlock *crypto;
|
||
|
+
|
||
|
+ /* Extract "encrypt." options into a qdict */
|
||
|
+ opts_qdict = qemu_opts_to_qdict(opts, NULL);
|
||
|
+ qdict_extract_subqdict(opts_qdict, &cryptoopts_qdict, "encrypt.");
|
||
|
+ qobject_unref(opts_qdict);
|
||
|
+
|
||
|
+ /* Build QCryptoBlockCreateOptions object from qdict */
|
||
|
+ qdict_put_str(cryptoopts_qdict, "format", "luks");
|
||
|
+ cryptoopts = block_crypto_create_opts_init(cryptoopts_qdict, errp);
|
||
|
+ qobject_unref(cryptoopts_qdict);
|
||
|
+ if (!cryptoopts) {
|
||
|
+ return false;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Fake LUKS creation in order to determine the payload size */
|
||
|
+ crypto = qcrypto_block_create(cryptoopts, "encrypt.",
|
||
|
+ qcow2_measure_crypto_hdr_init_func,
|
||
|
+ qcow2_measure_crypto_hdr_write_func,
|
||
|
+ len, errp);
|
||
|
+ qapi_free_QCryptoBlockCreateOptions(cryptoopts);
|
||
|
+ if (!crypto) {
|
||
|
+ return false;
|
||
|
+ }
|
||
|
+
|
||
|
+ qcrypto_block_free(crypto);
|
||
|
+ return true;
|
||
|
+}
|
||
|
+
|
||
|
static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
|
||
|
Error **errp)
|
||
|
{
|
||
|
@@ -4122,11 +4176,13 @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
|
||
|
uint64_t virtual_size; /* disk size as seen by guest */
|
||
|
uint64_t refcount_bits;
|
||
|
uint64_t l2_tables;
|
||
|
+ uint64_t luks_payload_size = 0;
|
||
|
size_t cluster_size;
|
||
|
int version;
|
||
|
char *optstr;
|
||
|
PreallocMode prealloc;
|
||
|
bool has_backing_file;
|
||
|
+ bool has_luks;
|
||
|
|
||
|
/* Parse image creation options */
|
||
|
cluster_size = qcow2_opt_get_cluster_size_del(opts, &local_err);
|
||
|
@@ -4156,6 +4212,20 @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
|
||
|
has_backing_file = !!optstr;
|
||
|
g_free(optstr);
|
||
|
|
||
|
+ optstr = qemu_opt_get_del(opts, BLOCK_OPT_ENCRYPT_FORMAT);
|
||
|
+ has_luks = optstr && strcmp(optstr, "luks") == 0;
|
||
|
+ g_free(optstr);
|
||
|
+
|
||
|
+ if (has_luks) {
|
||
|
+ size_t headerlen;
|
||
|
+
|
||
|
+ if (!qcow2_measure_luks_headerlen(opts, &headerlen, &local_err)) {
|
||
|
+ goto err;
|
||
|
+ }
|
||
|
+
|
||
|
+ luks_payload_size = ROUND_UP(headerlen, cluster_size);
|
||
|
+ }
|
||
|
+
|
||
|
virtual_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
|
||
|
virtual_size = ROUND_UP(virtual_size, cluster_size);
|
||
|
|
||
|
@@ -4226,7 +4296,7 @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
|
||
|
info = g_new(BlockMeasureInfo, 1);
|
||
|
info->fully_allocated =
|
||
|
qcow2_calc_prealloc_size(virtual_size, cluster_size,
|
||
|
- ctz32(refcount_bits));
|
||
|
+ ctz32(refcount_bits)) + luks_payload_size;
|
||
|
|
||
|
/* Remove data clusters that are not required. This overestimates the
|
||
|
* required size because metadata needed for the fully allocated file is
|
||
|
--
|
||
|
1.8.3.1
|
||
|
|