From nobody Mon Feb 9 01:30:45 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; 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 1518119221339520.6432927020065; Thu, 8 Feb 2018 11:47:01 -0800 (PST) Received: from localhost ([::1]:40533 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ejs9s-0005kt-CA for importer@patchew.org; Thu, 08 Feb 2018 14:47:00 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:57786) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ejro6-00037b-H2 for qemu-devel@nongnu.org; Thu, 08 Feb 2018 14:24:33 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ejro4-00016e-Rd for qemu-devel@nongnu.org; Thu, 08 Feb 2018 14:24:30 -0500 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:51342 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 1ejro0-00012R-Mm; Thu, 08 Feb 2018 14:24:24 -0500 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 43BA58182D11; Thu, 8 Feb 2018 19:24:24 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-117-74.ams2.redhat.com [10.36.117.74]) by smtp.corp.redhat.com (Postfix) with ESMTP id 90195B3008; Thu, 8 Feb 2018 19:24:21 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Thu, 8 Feb 2018 20:23:11 +0100 Message-Id: <20180208192328.16550-11-kwolf@redhat.com> In-Reply-To: <20180208192328.16550-1-kwolf@redhat.com> References: <20180208192328.16550-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Thu, 08 Feb 2018 19:24:24 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Thu, 08 Feb 2018 19:24:24 +0000 (UTC) for IP:'10.11.54.5' DOMAIN:'int-mx05.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] [PATCH 10/27] 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, jdurgin@redhat.com, pkrempa@redhat.com, mitake.hitoshi@lab.ntt.co.jp, jcody@redhat.com, qemu-devel@nongnu.org, mreitz@redhat.com, namei.unix@gmail.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 Reviewed-by: Eric Blake Reviewed-by: Max Reitz --- block/qcow2.c | 219 ++++++++++++++++-------------------------= ---- tests/qemu-iotests/049.out | 8 +- tests/qemu-iotests/112.out | 4 +- 3 files changed, 84 insertions(+), 147 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index 0316335614..02e331a938 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 @@ -2387,37 +2387,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) @@ -2811,7 +2780,7 @@ static int qcow2_create2(BlockdevCreateOptions *creat= e_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; } @@ -2829,7 +2798,7 @@ static int qcow2_create2(BlockdevCreateOptions *creat= e_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; @@ -3016,144 +2985,112 @@ 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 =3D NULL; + QDict *qdict =3D NULL; + QObject *qobj; + Visitor *v; BlockDriverState *bs =3D NULL; - Error *local_err =3D NULL; + const char *val; int ret; + Error *local_err =3D NULL; =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_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..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