--- block/qcow2.c | 79 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 63 insertions(+), 16 deletions(-)
diff --git a/block/qcow2.c b/block/qcow2.c index 376bb416fd..8dff4c6b5f 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -171,6 +171,25 @@ static ssize_t qcow2_crypto_hdr_write_func(QCryptoBlock *block, size_t offset, return ret; } +static QCryptoBlockCreateOptions* +qcow2_extract_crypto_create_opts(QemuOpts *opts, const char *fmt, Error **errp) +{ + QDict *cryptoopts_qdict; + QCryptoBlockCreateOptions *cryptoopts; + QDict *opts_qdict; + + /* 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); + return cryptoopts; +} + /* * read qcow2 extension and fill bs @@ -4366,20 +4385,10 @@ static ssize_t qcow2_measure_crypto_hdr_write_func(QCryptoBlock *block, 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); + cryptoopts = qcow2_extract_crypto_create_opts(opts, "luks", errp); if (!cryptoopts) { return false; } @@ -4756,6 +4765,7 @@ typedef enum Qcow2AmendOperation { * invocation from an operation change */ QCOW2_NO_OPERATION = 0, + QCOW2_UPDATING_ENCRYPTION, QCOW2_CHANGING_REFCOUNT_ORDER, QCOW2_DOWNGRADING, } Qcow2AmendOperation; @@ -4840,6 +4850,7 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, int ret; QemuOptDesc *desc = opts->list->desc; Qcow2AmendHelperCBInfo helper_cb_info; + bool encryption_update = false; while (desc && desc->name) { if (!qemu_opt_find(opts, desc->name)) { @@ -4888,9 +4899,22 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, return -ENOTSUP; } } else if (g_str_has_prefix(desc->name, "encrypt.")) { - error_setg(errp, - "Changing the encryption parameters is not supported"); - return -ENOTSUP; + + if (!s->crypto) { + error_setg(errp, + "Can't amend encryption options - encryption not supported"); + return -ENOTSUP; + + } + + if (s->crypt_method_header != QCOW_CRYPT_LUKS) { + error_setg(errp, + "Only LUKS encryption options can be amended"); + return -ENOTSUP; + } + + encryption_update = true; + } else if (!strcmp(desc->name, BLOCK_OPT_CLUSTER_SIZE)) { cluster_size = qemu_opt_get_size(opts, BLOCK_OPT_CLUSTER_SIZE, cluster_size); @@ -4927,7 +4951,7 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, "images"); return -EINVAL; } - } else { + } else { /* if this point is reached, this probably means a new option was * added without having it covered here */ abort(); @@ -4940,7 +4964,8 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, .original_status_cb = status_cb, .original_cb_opaque = cb_opaque, .total_operations = (new_version < old_version) - + (s->refcount_bits != refcount_bits) + + (s->refcount_bits != refcount_bits) + + (encryption_update == true) }; /* Upgrade first (some features may require compat=1.1) */ @@ -4954,6 +4979,28 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, } } + if (encryption_update) { + + QCryptoBlockCreateOptions *cryptoopts; + + cryptoopts = qcow2_extract_crypto_create_opts(opts, "luks", errp); + if (!cryptoopts) + return -EINVAL; + + helper_cb_info.current_operation = QCOW2_UPDATING_ENCRYPTION; + + ret = qcrypto_block_amend_options(s->crypto, + qcow2_crypto_hdr_read_func, + qcow2_crypto_hdr_write_func, + bs, + cryptoopts, + force, + errp); + if (ret) { + return ret; + } + } + if (s->refcount_bits != refcount_bits) { int refcount_order = ctz32(refcount_bits); -- 2.17.2