From patchwork Thu Feb 8 19:23:05 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Wolf X-Patchwork-Id: 10207871 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id AFE4660247 for ; Thu, 8 Feb 2018 19:40:47 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9FC7729343 for ; Thu, 8 Feb 2018 19:40:47 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 92C5729377; Thu, 8 Feb 2018 19:40:47 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id C8C0429343 for ; Thu, 8 Feb 2018 19:40:46 +0000 (UTC) Received: from localhost ([::1]:40485 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ejs3p-0001Kd-Ug for patchwork-qemu-devel@patchwork.kernel.org; Thu, 08 Feb 2018 14:40:45 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:57613) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ejrno-0002sR-6X for qemu-devel@nongnu.org; Thu, 08 Feb 2018 14:24:15 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ejrnm-0000mz-Bd for qemu-devel@nongnu.org; Thu, 08 Feb 2018 14:24:12 -0500 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:52586 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 1ejrnh-0000gG-V0; Thu, 08 Feb 2018 14:24:06 -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 925984040093; Thu, 8 Feb 2018 19:24:05 +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 DA57EB3008; Thu, 8 Feb 2018 19:24:02 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Thu, 8 Feb 2018 20:23:05 +0100 Message-Id: <20180208192328.16550-5-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.5]); Thu, 08 Feb 2018 19:24:05 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Thu, 08 Feb 2018 19:24:05 +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 04/27] qcow2: Pass BlockdevCreateOptions to qcow2_create2() 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+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP All of the simple options are now passed to qcow2_create2() in a BlockdevCreateOptions object. Still missing: node-name and the encryption options. Signed-off-by: Kevin Wolf Reviewed-by: Max Reitz --- block/qcow2.c | 190 ++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 152 insertions(+), 38 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index 6134c0d40c..4ab6ed15c2 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -2638,19 +2638,26 @@ static int64_t qcow2_calc_prealloc_size(int64_t total_size, return meta_size + aligned_total_size; } -static size_t qcow2_opt_get_cluster_size_del(QemuOpts *opts, Error **errp) +static bool validate_cluster_size(size_t cluster_size, Error **errp) { - size_t cluster_size; - int cluster_bits; - - cluster_size = qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE, - DEFAULT_CLUSTER_SIZE); - cluster_bits = ctz32(cluster_size); + int cluster_bits = ctz32(cluster_size); if (cluster_bits < MIN_CLUSTER_BITS || cluster_bits > MAX_CLUSTER_BITS || (1 << cluster_bits) != cluster_size) { error_setg(errp, "Cluster size must be a power of two between %d and " "%dk", 1 << MIN_CLUSTER_BITS, 1 << (MAX_CLUSTER_BITS - 10)); + return false; + } + return true; +} + +static size_t qcow2_opt_get_cluster_size_del(QemuOpts *opts, Error **errp) +{ + size_t cluster_size; + + cluster_size = qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE, + DEFAULT_CLUSTER_SIZE); + if (!validate_cluster_size(cluster_size, errp)) { return 0; } return cluster_size; @@ -2698,12 +2705,11 @@ static uint64_t qcow2_opt_get_refcount_bits_del(QemuOpts *opts, int version, return refcount_bits; } -static int qcow2_create2(BlockDriverState *bs, int64_t total_size, - const char *backing_file, const char *backing_format, - int flags, size_t cluster_size, PreallocMode prealloc, - QemuOpts *opts, int version, int refcount_order, - const char *encryptfmt, Error **errp) +static int qcow2_create2(BlockDriverState *bs, + BlockdevCreateOptions *create_options, + QemuOpts *opts, const char *encryptfmt, Error **errp) { + BlockdevCreateOptionsQcow2 *qcow2_opts; QDict *options; /* @@ -2720,10 +2726,92 @@ static int qcow2_create2(BlockDriverState *bs, int64_t total_size, */ BlockBackend *blk; QCowHeader *header; + size_t cluster_size; + int version; + int refcount_order; uint64_t* refcount_table; Error *local_err = NULL; int ret; + /* Validate options and set default values */ + assert(create_options->driver == BLOCKDEV_DRIVER_QCOW2); + qcow2_opts = &create_options->u.qcow2; + + if (!QEMU_IS_ALIGNED(qcow2_opts->size, BDRV_SECTOR_SIZE)) { + error_setg(errp, "Image size must be a multiple of 512 bytes"); + ret = -EINVAL; + goto out; + } + + if (qcow2_opts->has_version) { + switch (qcow2_opts->version) { + case BLOCKDEV_QCOW2_VERSION_V2: + version = 2; + break; + case BLOCKDEV_QCOW2_VERSION_V3: + version = 3; + break; + default: + g_assert_not_reached(); + } + } else { + version = 3; + } + + if (qcow2_opts->has_cluster_size) { + cluster_size = qcow2_opts->cluster_size; + } else { + cluster_size = DEFAULT_CLUSTER_SIZE; + } + + if (!validate_cluster_size(cluster_size, errp)) { + return -EINVAL; + } + + if (!qcow2_opts->has_preallocation) { + qcow2_opts->preallocation = PREALLOC_MODE_OFF; + } + if (qcow2_opts->has_backing_file && + qcow2_opts->preallocation != PREALLOC_MODE_OFF) + { + error_setg(errp, "Backing file and preallocation cannot be used at " + "the same time"); + return -EINVAL; + } + if (qcow2_opts->has_backing_fmt && !qcow2_opts->has_backing_file) { + error_setg(errp, "Backing format cannot be used without backing file"); + return -EINVAL; + } + + if (!qcow2_opts->has_lazy_refcounts) { + qcow2_opts->lazy_refcounts = false; + } + if (version < 3 && qcow2_opts->lazy_refcounts) { + error_setg(errp, "Lazy refcounts only supported with compatibility " + "level 1.1 and above (use compat=1.1 or greater)"); + return -EINVAL; + } + + if (!qcow2_opts->has_refcount_bits) { + qcow2_opts->refcount_bits = 16; + } + if (qcow2_opts->refcount_bits > 64 || + !is_power_of_2(qcow2_opts->refcount_bits)) + { + error_setg(errp, "Refcount width must be a power of two and may not " + "exceed 64 bits"); + return -EINVAL; + } + if (version < 3 && qcow2_opts->refcount_bits != 16) { + error_setg(errp, "Different refcount widths than 16 bits require " + "compatibility level 1.1 or above (use compat=1.1 or " + "greater)"); + return -EINVAL; + } + refcount_order = ctz32(qcow2_opts->refcount_bits); + + + /* Create BlockBackend to write to the image */ blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL); ret = blk_insert_bs(blk, bs, errp); if (ret < 0) { @@ -2750,7 +2838,7 @@ static int qcow2_create2(BlockDriverState *bs, int64_t total_size, /* We'll update this to correct value later */ header->crypt_method = cpu_to_be32(QCOW_CRYPT_NONE); - if (flags & BLOCK_FLAG_LAZY_REFCOUNTS) { + if (qcow2_opts->lazy_refcounts) { header->compatible_features |= cpu_to_be64(QCOW2_COMPAT_LAZY_REFCOUNTS); } @@ -2812,18 +2900,26 @@ static int qcow2_create2(BlockDriverState *bs, int64_t total_size, } /* Okay, now that we have a valid image, let's give it the right size */ - ret = blk_truncate(blk, total_size, PREALLOC_MODE_OFF, errp); + ret = blk_truncate(blk, qcow2_opts->size, PREALLOC_MODE_OFF, errp); if (ret < 0) { error_prepend(errp, "Could not resize image: "); goto out; } /* Want a backing file? There you go.*/ - if (backing_file) { - ret = bdrv_change_backing_file(blk_bs(blk), backing_file, backing_format); + if (qcow2_opts->has_backing_file) { + const char *backing_format = NULL; + + if (qcow2_opts->has_backing_fmt) { + backing_format = BlockdevDriver_str(qcow2_opts->backing_fmt); + } + + ret = bdrv_change_backing_file(blk_bs(blk), qcow2_opts->backing_file, + backing_format); if (ret < 0) { error_setg_errno(errp, -ret, "Could not assign backing file '%s' " - "with format '%s'", backing_file, backing_format); + "with format '%s'", qcow2_opts->backing_file, + backing_format); goto out; } } @@ -2837,8 +2933,8 @@ static int qcow2_create2(BlockDriverState *bs, int64_t total_size, } /* And if we're supposed to preallocate metadata, do that now */ - if (prealloc != PREALLOC_MODE_OFF) { - ret = preallocate(blk_bs(blk), 0, total_size); + if (qcow2_opts->preallocation != PREALLOC_MODE_OFF) { + ret = preallocate(blk_bs(blk), 0, qcow2_opts->size); if (ret < 0) { error_setg_errno(errp, -ret, "Could not preallocate metadata"); goto out; @@ -2876,8 +2972,10 @@ out: static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp) { + BlockdevCreateOptions create_options; char *backing_file = NULL; char *backing_fmt = NULL; + BlockdevDriver backing_drv; char *buf = NULL; uint64_t size = 0; int flags = 0; @@ -2885,7 +2983,6 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp) PreallocMode prealloc; int version; uint64_t refcount_bits; - int refcount_order; char *encryptfmt = NULL; BlockDriverState *bs = NULL; Error *local_err = NULL; @@ -2896,6 +2993,13 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp) BDRV_SECTOR_SIZE); backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE); backing_fmt = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FMT); + backing_drv = qapi_enum_parse(&BlockdevDriver_lookup, backing_fmt, + 0, &local_err); + if (local_err) { + error_propagate(errp, local_err); + ret = -EINVAL; + goto finish; + } encryptfmt = qemu_opt_get_del(opts, BLOCK_OPT_ENCRYPT_FORMAT); if (encryptfmt) { if (qemu_opt_get(opts, BLOCK_OPT_ENCRYPT)) { @@ -2933,20 +3037,6 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp) flags |= BLOCK_FLAG_LAZY_REFCOUNTS; } - if (backing_file && prealloc != PREALLOC_MODE_OFF) { - error_setg(errp, "Backing file and preallocation cannot be used at " - "the same time"); - ret = -EINVAL; - goto finish; - } - - if (version < 3 && (flags & BLOCK_FLAG_LAZY_REFCOUNTS)) { - error_setg(errp, "Lazy refcounts only supported with compatibility " - "level 1.1 and above (use compat=1.1 or greater)"); - ret = -EINVAL; - goto finish; - } - refcount_bits = qcow2_opt_get_refcount_bits_del(opts, version, &local_err); if (local_err) { error_propagate(errp, local_err); @@ -2954,10 +3044,10 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp) goto finish; } - refcount_order = ctz32(refcount_bits); /* Create and open the file (protocol layer) */ if (prealloc == PREALLOC_MODE_FULL || prealloc == PREALLOC_MODE_FALLOC) { + int refcount_order = ctz32(refcount_bits); int64_t prealloc_size = qcow2_calc_prealloc_size(size, cluster_size, refcount_order); qemu_opt_set_number(opts, BLOCK_OPT_SIZE, prealloc_size, &error_abort); @@ -2978,9 +3068,33 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp) } /* Create the qcow2 image (format layer) */ - ret = qcow2_create2(bs, size, backing_file, backing_fmt, flags, - cluster_size, prealloc, opts, version, refcount_order, - encryptfmt, errp); + create_options = (BlockdevCreateOptions) { + .driver = BLOCKDEV_DRIVER_QCOW2, + .u.qcow2 = { + .file = &(BlockdevRef) { + .type = QTYPE_QSTRING, + .u.reference = bs->node_name, + }, + .size = size, + .has_version = true, + .version = version == 2 + ? BLOCKDEV_QCOW2_VERSION_V2 + : BLOCKDEV_QCOW2_VERSION_V3, + .has_backing_file = (backing_file != NULL), + .backing_file = backing_file, + .has_backing_fmt = (backing_fmt != NULL), + .backing_fmt = backing_drv, + .has_cluster_size = true, + .cluster_size = cluster_size, + .has_preallocation = true, + .preallocation = prealloc, + .has_lazy_refcounts = true, + .lazy_refcounts = (flags & BLOCK_FLAG_LAZY_REFCOUNTS), + .has_refcount_bits = true, + .refcount_bits = refcount_bits, + }, + }; + ret = qcow2_create2(bs, &create_options, opts, encryptfmt, errp); if (ret < 0) { goto finish; }