From nobody Thu Dec 18 13:37:25 2025 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; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1520613881920363.52540401748627; Fri, 9 Mar 2018 08:44:41 -0800 (PST) Received: from localhost ([::1]:46428 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1euL8K-00058D-Ku for importer@patchew.org; Fri, 09 Mar 2018 11:44:40 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:33797) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1euKl5-0001EX-T1 for qemu-devel@nongnu.org; Fri, 09 Mar 2018 11:20:42 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1euKl2-00071d-2f for qemu-devel@nongnu.org; Fri, 09 Mar 2018 11:20:39 -0500 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:43182 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1euKkv-0006t2-Bs; Fri, 09 Mar 2018 11:20:29 -0500 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id EC52A40252F5; Fri, 9 Mar 2018 16:20:28 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-234.ams2.redhat.com [10.36.117.234]) by smtp.corp.redhat.com (Postfix) with ESMTP id 461C4215CDAA; Fri, 9 Mar 2018 16:20:28 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Fri, 9 Mar 2018 17:19:04 +0100 Message-Id: <20180309161933.8168-28-kwolf@redhat.com> In-Reply-To: <20180309161933.8168-1-kwolf@redhat.com> References: <20180309161933.8168-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Fri, 09 Mar 2018 16:20:28 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Fri, 09 Mar 2018 16:20:28 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PULL 27/56] 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, qemu-devel@nongnu.org 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" Instead of manually creating the BlockdevCreateOptions object, use a visitor to parse the given options into the QAPI object. This involves translation from the old command line syntax to the syntax mandated by the QAPI schema. Option names are still checked against qcow2_create_opts, so only the old option names are allowed on the command line, even if they are translated in qcow2_create(). In contrast, new option values are optionally recognised besides the old values: 'compat' accepts 'v2'/'v3' as an alias for '0.10'/'1.1', and 'encrypt.format' accepts 'qcow' as an alias for 'aes' now. Signed-off-by: Kevin Wolf Reviewed-by: Max Reitz Reviewed-by: Eric Blake --- block/qcow2.c | 218 ++++++++++++++++-------------------------= ---- tests/qemu-iotests/049.out | 8 +- tests/qemu-iotests/112.out | 4 +- 3 files changed, 84 insertions(+), 146 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index 933c612754..37b0e36c1e 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -37,7 +37,8 @@ #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/qapi-visit-block-core.h" #include "block/crypto.h" =20 /* @@ -2449,37 +2450,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) @@ -2874,7 +2844,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options= , Error **errp) } if (version < 3 && qcow2_opts->lazy_refcounts) { error_setg(errp, "Lazy refcounts only supported with compatibility= " - "level 1.1 and above (use compat=3D1.1 or greater)"); + "level 1.1 and above (use version=3Dv3 or greater)"); ret =3D -EINVAL; goto out; } @@ -2892,7 +2862,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options= , Error **errp) } if (version < 3 && qcow2_opts->refcount_bits !=3D 16) { error_setg(errp, "Different refcount widths than 16 bits require " - "compatibility level 1.1 or above (use compat=3D1.1 or " + "compatibility level 1.1 or above (use version=3Dv3 or " "greater)"); ret =3D -EINVAL; goto out; @@ -3080,144 +3050,112 @@ out: static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpt= s *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 =3D NULL; + QDict *qdict =3D NULL; + QObject *qobj; + Visitor *v; BlockDriverState *bs =3D NULL; Error *local_err =3D NULL; + const char *val; 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); + /* 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"); + } + + /* Convert compat=3D0.10/1.1 into compat=3Dv2/v3, to be renamed into + * version=3Dv2/v3 below. */ + 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, "v2"); + } else if (val && !strcmp(val, "1.1")) { + qdict_put_str(qdict, BLOCK_OPT_COMPAT_LEVEL, "v3"); + } + + /* Change legacy command line options into QMP ones */ + static const QDictRenames 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 }, + { BLOCK_OPT_COMPAT_LEVEL, "version" }, + { NULL, NULL }, + }; + + if (!qdict_rename_keys(qdict, opt_renames, errp)) { ret =3D -EINVAL; goto finish; } =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; - } - } - - 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, "file", 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, - .u.qcow2 =3D { - .file =3D &(BlockdevRef) { - .type =3D QTYPE_QSTRING, - .u.reference =3D bs->node_name, - }, - .size =3D size, - .has_version =3D true, - .version =3D version =3D=3D 2 - ? BLOCKDEV_QCOW2_VERSION_V2 - : BLOCKDEV_QCOW2_VERSION_V3, - .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_co_create(&create_options, errp); + ret =3D qcow2_co_create(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..0871bff564 100644 --- a/tests/qemu-iotests/049.out +++ b/tests/qemu-iotests/049.out @@ -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 @@ -205,7 +205,7 @@ qemu-img create -f qcow2 -o compat=3D0.10,lazy_refcount= s=3Doff TEST_DIR/t.qcow2 64M Formatting 'TEST_DIR/t.qcow2', fmt=3Dqcow2 size=3D67108864 compat=3D0.10 c= luster_size=3D65536 lazy_refcounts=3Doff refcount_bits=3D16 =20 qemu-img create -f qcow2 -o compat=3D0.10,lazy_refcounts=3Don TEST_DIR/t.q= cow2 64M -qemu-img: TEST_DIR/t.qcow2: Lazy refcounts only supported with compatibili= ty level 1.1 and above (use compat=3D1.1 or greater) +qemu-img: TEST_DIR/t.qcow2: Lazy refcounts only supported with compatibili= ty level 1.1 and above (use version=3Dv3 or greater) Formatting 'TEST_DIR/t.qcow2', fmt=3Dqcow2 size=3D67108864 compat=3D0.10 c= luster_size=3D65536 lazy_refcounts=3Don refcount_bits=3D16 =20 *** done diff --git a/tests/qemu-iotests/112.out b/tests/qemu-iotests/112.out index 81b04d1452..86f041075d 100644 --- a/tests/qemu-iotests/112.out +++ b/tests/qemu-iotests/112.out @@ -21,9 +21,9 @@ refcount bits: 16 =20 Formatting 'TEST_DIR/t.IMGFMT', fmt=3DIMGFMT size=3D67108864 refcount bits: 16 -qemu-img: TEST_DIR/t.IMGFMT: Different refcount widths than 16 bits requir= e compatibility level 1.1 or above (use or greater) +qemu-img: TEST_DIR/t.IMGFMT: Different refcount widths than 16 bits requir= e compatibility level 1.1 or above (use version=3Dv3 or greater) Formatting 'TEST_DIR/t.IMGFMT', fmt=3DIMGFMT size=3D67108864 -qemu-img: TEST_DIR/t.IMGFMT: Different refcount widths than 16 bits requir= e compatibility level 1.1 or above (use or greater) +qemu-img: TEST_DIR/t.IMGFMT: Different refcount widths than 16 bits requir= e compatibility level 1.1 or above (use version=3Dv3 or greater) Formatting 'TEST_DIR/t.IMGFMT', fmt=3DIMGFMT size=3D67108864 =20 =3D=3D=3D Snapshot limit on refcount_bits=3D1 =3D=3D=3D --=20 2.13.6