From nobody Tue Feb 10 21:19:26 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1515700888887714.2574693714162; Thu, 11 Jan 2018 12:01:28 -0800 (PST) Received: from localhost ([::1]:38131 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eZj2W-0004HZ-13 for importer@patchew.org; Thu, 11 Jan 2018 15:01:28 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:58300) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eZiv9-0005sD-1w for qemu-devel@nongnu.org; Thu, 11 Jan 2018 14:53:52 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1eZiv5-0000wM-4k for qemu-devel@nongnu.org; Thu, 11 Jan 2018 14:53:51 -0500 Received: from mx1.redhat.com ([209.132.183.28]:50576) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1eZiv0-0000qh-PB; Thu, 11 Jan 2018 14:53:42 -0500 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id C9F3AC059721; Thu, 11 Jan 2018 19:53:41 +0000 (UTC) Received: from localhost.localdomain.com (unknown [10.36.118.59]) by smtp.corp.redhat.com (Postfix) with ESMTP id 05E5B5C258; Thu, 11 Jan 2018 19:53:36 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Thu, 11 Jan 2018 20:52:24 +0100 Message-Id: <20180111195225.4226-10-kwolf@redhat.com> In-Reply-To: <20180111195225.4226-1-kwolf@redhat.com> References: <20180111195225.4226-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Thu, 11 Jan 2018 19:53:41 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC PATCH 09/10] qcow2: Use visitor for options in qcow2_create() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: kwolf@redhat.com, pkrempa@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Signed-off-by: Kevin Wolf --- block/qcow2.c | 227 ++++++++++++++++++-----------------------= ---- tests/qemu-iotests/049.out | 10 +- 2 files changed, 93 insertions(+), 144 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index 868e0e8a62..4031a18a77 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -36,7 +36,7 @@ #include "qemu/option_int.h" #include "qemu/cutils.h" #include "qemu/bswap.h" -#include "qapi/opts-visitor.h" +#include "qapi/qobject-input-visitor.h" #include "qapi-visit.h" #include "block/crypto.h" =20 @@ -2379,37 +2379,6 @@ static int qcow2_crypt_method_from_format(const char= *encryptfmt) } } =20 -static QCryptoBlockCreateOptions * -qcow2_parse_encryption(const char *encryptfmt, QemuOpts *opts, Error **err= p) -{ - QCryptoBlockCreateOptions *cryptoopts =3D NULL; - QDict *options, *encryptopts; - int fmt; - - options =3D qemu_opts_to_qdict(opts, NULL); - qdict_extract_subqdict(options, &encryptopts, "encrypt."); - QDECREF(options); - - fmt =3D qcow2_crypt_method_from_format(encryptfmt); - - switch (fmt) { - case QCOW_CRYPT_LUKS: - cryptoopts =3D block_crypto_create_opts_init( - Q_CRYPTO_BLOCK_FORMAT_LUKS, encryptopts, errp); - break; - case QCOW_CRYPT_AES: - cryptoopts =3D block_crypto_create_opts_init( - Q_CRYPTO_BLOCK_FORMAT_QCOW, encryptopts, errp); - break; - default: - error_setg(errp, "Unknown encryption format '%s'", encryptfmt); - break; - } - - QDECREF(encryptopts); - return cryptoopts; -} - static int qcow2_set_up_encryption(BlockDriverState *bs, QCryptoBlockCreateOptions *cryptoopts, Error **errp) @@ -3003,144 +2972,124 @@ out: =20 static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp) { - BlockdevCreateOptions create_options; - char *backing_file =3D NULL; - char *backing_fmt =3D NULL; - BlockdevDriver backing_drv; - char *buf =3D NULL; - uint64_t size =3D 0; - int flags =3D 0; - size_t cluster_size =3D DEFAULT_CLUSTER_SIZE; - PreallocMode prealloc; - int version; - uint64_t refcount_bits; - char *encryptfmt =3D NULL; - QCryptoBlockCreateOptions *cryptoopts =3D NULL; + BlockdevCreateOptions *create_options; + QDict *qdict =3D NULL; + QObject *qobj; + Visitor *v; BlockDriverState *bs =3D NULL; + const char *val; + int i, ret; Error *local_err =3D NULL; - int ret; =20 - /* Read out options */ - size =3D ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0), - BDRV_SECTOR_SIZE); - backing_file =3D qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE); - backing_fmt =3D qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FMT); - backing_drv =3D qapi_enum_parse(&BlockdevDriver_lookup, backing_fmt, - 0, &local_err); - if (local_err) { - error_propagate(errp, local_err); - ret =3D -EINVAL; - goto finish; - } + /* Only the keyval visitor supports the dotted syntax needed for + * encryption, so go through a QDict before getting a QAPI type. Ignore + * options meant for the protocol layer so that the visitor doesn't + * complain. */ + qdict =3D qemu_opts_to_qdict_filtered(opts, NULL, bdrv_qcow2.create_op= ts, + true); + + /* Handle encryption options */ + val =3D qdict_get_try_str(qdict, BLOCK_OPT_ENCRYPT); + if (val && !strcmp(val, "on")) { + qdict_put_str(qdict, BLOCK_OPT_ENCRYPT, "qcow"); + } else if (val && !strcmp(val, "off")) { + qdict_del(qdict, BLOCK_OPT_ENCRYPT); + } + + val =3D qdict_get_try_str(qdict, BLOCK_OPT_ENCRYPT_FORMAT); + if (val && !strcmp(val, "aes")) { + qdict_put_str(qdict, BLOCK_OPT_ENCRYPT_FORMAT, "qcow"); + } + + /* TODO QAPI doesn't allow dots in enum values. Either change QAPI or + * decide on the proper new representation for blockdev-create */ + val =3D qdict_get_try_str(qdict, BLOCK_OPT_COMPAT_LEVEL); + if (val && !strcmp(val, "0.10")) { + qdict_put_str(qdict, BLOCK_OPT_COMPAT_LEVEL, "0_10"); + } else if (val && !strcmp(val, "1.1")) { + qdict_put_str(qdict, BLOCK_OPT_COMPAT_LEVEL, "1_1"); + } + + /* Change legacy command line options into QMP ones */ + static const struct { + const char *from; + const char *to; + } opt_renames[] =3D { + { BLOCK_OPT_BACKING_FILE, "backing-file" }, + { BLOCK_OPT_BACKING_FMT, "backing-fmt" }, + { BLOCK_OPT_CLUSTER_SIZE, "cluster-size" }, + { BLOCK_OPT_LAZY_REFCOUNTS, "lazy-refcounts" }, + { BLOCK_OPT_REFCOUNT_BITS, "refcount-bits" }, + { BLOCK_OPT_ENCRYPT, BLOCK_OPT_ENCRYPT_FORMAT }, + }; =20 - encryptfmt =3D qemu_opt_get_del(opts, BLOCK_OPT_ENCRYPT_FORMAT); - if (encryptfmt) { - if (qemu_opt_get(opts, BLOCK_OPT_ENCRYPT)) { - error_setg(errp, "Options " BLOCK_OPT_ENCRYPT " and " - BLOCK_OPT_ENCRYPT_FORMAT " are mutually exclusive"); - ret =3D -EINVAL; - goto finish; - } - } else if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ENCRYPT, false)) { - encryptfmt =3D g_strdup("aes"); - } - if (encryptfmt) { - cryptoopts =3D qcow2_parse_encryption(encryptfmt, opts, errp); - if (cryptoopts =3D=3D NULL) { - ret =3D -EINVAL; - goto finish; + for (i =3D 0; i < ARRAY_SIZE(opt_renames); i++) { + if (qdict_haskey(qdict, opt_renames[i].from)) { + if (qdict_haskey(qdict, opt_renames[i].to)) { + error_setg(errp, "'%s' and its alias '%s' can't be used at= the " + "same time", opt_renames[i].to, opt_renames[i].= from); + ret =3D -EINVAL; + goto finish; + } + + qobj =3D qdict_get(qdict, opt_renames[i].from); + qobject_incref(qobj); + qdict_put_obj(qdict, opt_renames[i].to, qobj); + qdict_del(qdict, opt_renames[i].from); } } =20 - cluster_size =3D qcow2_opt_get_cluster_size_del(opts, &local_err); - if (local_err) { - error_propagate(errp, local_err); - ret =3D -EINVAL; + /* Create and open the file (protocol layer) */ + ret =3D bdrv_create_file(filename, opts, errp); + if (ret < 0) { goto finish; } - buf =3D qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC); - prealloc =3D qapi_enum_parse(&PreallocMode_lookup, buf, - PREALLOC_MODE_OFF, &local_err); - if (local_err) { - error_propagate(errp, local_err); - ret =3D -EINVAL; + + bs =3D bdrv_open(filename, NULL, NULL, + BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); + if (bs =3D=3D NULL) { + ret =3D -EIO; goto finish; } =20 - version =3D qcow2_opt_get_version_del(opts, &local_err); - if (local_err) { - error_propagate(errp, local_err); + /* Set 'driver' and 'node' options */ + qdict_put_str(qdict, "driver", "qcow2"); + qdict_put_str(qdict, "node", bs->node_name); + + /* Now get the QAPI type BlockdevCreateOptions */ + qobj =3D qdict_crumple(qdict, errp); + QDECREF(qdict); + qdict =3D qobject_to_qdict(qobj); + if (qdict =3D=3D NULL) { ret =3D -EINVAL; goto finish; } =20 - if (qemu_opt_get_bool_del(opts, BLOCK_OPT_LAZY_REFCOUNTS, false)) { - flags |=3D BLOCK_FLAG_LAZY_REFCOUNTS; - } + v =3D qobject_input_visitor_new_keyval(QOBJECT(qdict)); + visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err); + visit_free(v); =20 - refcount_bits =3D qcow2_opt_get_refcount_bits_del(opts, version, &loca= l_err); if (local_err) { error_propagate(errp, local_err); ret =3D -EINVAL; goto finish; } =20 - - /* Create and open the file (protocol layer */ - ret =3D bdrv_create_file(filename, opts, errp); - if (ret < 0) { - goto finish; - } - - bs =3D bdrv_open(filename, NULL, NULL, - BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); - if (bs =3D=3D NULL) { - ret =3D -EIO; - goto finish; - } + /* Silently round up size */ + create_options->u.qcow2.size =3D ROUND_UP(create_options->u.qcow2.size, + BDRV_SECTOR_SIZE); =20 /* Create the qcow2 image (format layer) */ - create_options =3D (BlockdevCreateOptions) { - .driver =3D BLOCKDEV_DRIVER_QCOW2, - .node =3D & (BlockdevRef) { - .type =3D QTYPE_QSTRING, - .u.reference =3D bs->node_name, - }, - .u.qcow2 =3D { - .size =3D size, - .has_compat =3D true, - .compat =3D version =3D=3D 2 - ? BLOCKDEV_QCOW2_COMPAT_LEVEL_0_10 - : BLOCKDEV_QCOW2_COMPAT_LEVEL_1_1, - .has_backing_file =3D (backing_file !=3D NULL), - .backing_file =3D backing_file, - .has_backing_fmt =3D (backing_fmt !=3D NULL), - .backing_fmt =3D backing_drv, - .has_encrypt =3D (encryptfmt !=3D NULL), - .encrypt =3D cryptoopts, - .has_cluster_size =3D true, - .cluster_size =3D cluster_size, - .has_preallocation =3D true, - .preallocation =3D prealloc, - .has_lazy_refcounts =3D true, - .lazy_refcounts =3D (flags & BLOCK_FLAG_LAZY_REFCOUNTS), - .has_refcount_bits =3D true, - .refcount_bits =3D refcount_bits, - }, - }; - ret =3D qcow2_create2(&create_options, errp); + ret =3D qcow2_create2(create_options, errp); if (ret < 0) { goto finish; } =20 + ret =3D 0; finish: + QDECREF(qdict); bdrv_unref(bs); - - qapi_free_QCryptoBlockCreateOptions(cryptoopts); - g_free(backing_file); - g_free(backing_fmt); - g_free(encryptfmt); - g_free(buf); + qapi_free_BlockdevCreateOptions(create_options); return ret; } =20 diff --git a/tests/qemu-iotests/049.out b/tests/qemu-iotests/049.out index 003247023e..1115c27ccf 100644 --- a/tests/qemu-iotests/049.out +++ b/tests/qemu-iotests/049.out @@ -106,7 +106,7 @@ qemu-img: Value '-1k' is out of range for parameter 'si= ze' qemu-img: TEST_DIR/t.qcow2: Invalid options for file format 'qcow2' =20 qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- 1kilobyte -qemu-img: Invalid image size specified! You may use k, M, G, T, P or E suf= fixes for +qemu-img: Invalid image size specified! You may use k, M, G, T, P or E suf= fixes for=20 qemu-img: kilobytes, megabytes, gigabytes, terabytes, petabytes and exabyt= es. =20 qemu-img create -f qcow2 -o size=3D1kilobyte TEST_DIR/t.qcow2 @@ -116,7 +116,7 @@ and exabytes, respectively. qemu-img: TEST_DIR/t.qcow2: Invalid options for file format 'qcow2' =20 qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- foobar -qemu-img: Invalid image size specified! You may use k, M, G, T, P or E suf= fixes for +qemu-img: Invalid image size specified! You may use k, M, G, T, P or E suf= fixes for=20 qemu-img: kilobytes, megabytes, gigabytes, terabytes, petabytes and exabyt= es. =20 qemu-img create -f qcow2 -o size=3Dfoobar TEST_DIR/t.qcow2 @@ -166,11 +166,11 @@ qemu-img create -f qcow2 -o compat=3D1.1 TEST_DIR/t.q= cow2 64M Formatting 'TEST_DIR/t.qcow2', fmt=3Dqcow2 size=3D67108864 compat=3D1.1 cl= uster_size=3D65536 lazy_refcounts=3Doff refcount_bits=3D16 =20 qemu-img create -f qcow2 -o compat=3D0.42 TEST_DIR/t.qcow2 64M -qemu-img: TEST_DIR/t.qcow2: Invalid compatibility level: '0.42' +qemu-img: TEST_DIR/t.qcow2: Invalid parameter '0.42' Formatting 'TEST_DIR/t.qcow2', fmt=3Dqcow2 size=3D67108864 compat=3D0.42 c= luster_size=3D65536 lazy_refcounts=3Doff refcount_bits=3D16 =20 qemu-img create -f qcow2 -o compat=3Dfoobar TEST_DIR/t.qcow2 64M -qemu-img: TEST_DIR/t.qcow2: Invalid compatibility level: 'foobar' +qemu-img: TEST_DIR/t.qcow2: Invalid parameter 'foobar' Formatting 'TEST_DIR/t.qcow2', fmt=3Dqcow2 size=3D67108864 compat=3Dfoobar= cluster_size=3D65536 lazy_refcounts=3Doff refcount_bits=3D16 =20 =3D=3D Check preallocation option =3D=3D @@ -182,7 +182,7 @@ qemu-img create -f qcow2 -o preallocation=3Dmetadata TE= ST_DIR/t.qcow2 64M Formatting 'TEST_DIR/t.qcow2', fmt=3Dqcow2 size=3D67108864 cluster_size=3D= 65536 preallocation=3Dmetadata lazy_refcounts=3Doff refcount_bits=3D16 =20 qemu-img create -f qcow2 -o preallocation=3D1234 TEST_DIR/t.qcow2 64M -qemu-img: TEST_DIR/t.qcow2: invalid parameter value: 1234 +qemu-img: TEST_DIR/t.qcow2: Invalid parameter '1234' Formatting 'TEST_DIR/t.qcow2', fmt=3Dqcow2 size=3D67108864 cluster_size=3D= 65536 preallocation=3D1234 lazy_refcounts=3Doff refcount_bits=3D16 =20 =3D=3D Check encryption option =3D=3D --=20 2.13.6