From patchwork Tue Jun 15 10:36:18 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Wolf X-Patchwork-Id: 55631 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id DEC3BB7D1C for ; Tue, 15 Jun 2010 20:38:54 +1000 (EST) Received: from localhost ([127.0.0.1]:58513 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OOTXf-0003Gq-9s for incoming@patchwork.ozlabs.org; Tue, 15 Jun 2010 06:38:51 -0400 Received: from [140.186.70.92] (port=46791 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OOTVT-0002Jz-SX for qemu-devel@nongnu.org; Tue, 15 Jun 2010 06:36:37 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1OOTVS-0008Ls-Cb for qemu-devel@nongnu.org; Tue, 15 Jun 2010 06:36:35 -0400 Received: from mx1.redhat.com ([209.132.183.28]:57013) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1OOTVS-0008Le-1G for qemu-devel@nongnu.org; Tue, 15 Jun 2010 06:36:34 -0400 Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id o5FAaVeG031198 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Tue, 15 Jun 2010 06:36:31 -0400 Received: from localhost.localdomain (dhcp-5-217.str.redhat.com [10.32.5.217]) by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id o5FAaTFH013176; Tue, 15 Jun 2010 06:36:30 -0400 From: Kevin Wolf To: qemu-devel@nongnu.org Date: Tue, 15 Jun 2010 12:36:18 +0200 Message-Id: <1276598178-16798-1-git-send-email-kwolf@redhat.com> In-Reply-To: References: X-Scanned-By: MIMEDefang 2.67 on 10.5.11.12 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. Cc: kwolf@redhat.com, stefanha@gmail.com Subject: [Qemu-devel] [PATCH v2 1/2] qcow2: Simplify image creation X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Instead of doing lots of magic for setting up initial refcount blocks and stuff create a minimal (inconsistent) image, open it and initialize the rest with regular qcow2 functions. This is a complete rewrite of the image creation function. The old implementating is #ifdef'd out and will be removed by the next patch (removing it here would have made the diff unreadable because diff tries to find similarities when it's really a rewrite) Signed-off-by: Kevin Wolf --- block/qcow2.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 129 insertions(+), 1 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index 33fa9a9..e237363 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -27,6 +27,7 @@ #include #include "aes.h" #include "block/qcow2.h" +#include "qemu-error.h" /* Differences with QCOW: @@ -767,6 +768,7 @@ static int qcow2_change_backing_file(BlockDriverState *bs, return qcow2_update_ext_header(bs, backing_file, backing_fmt); } +#if 0 static int get_bits_from_size(size_t size) { int res = 0; @@ -787,6 +789,7 @@ static int get_bits_from_size(size_t size) return res; } +#endif static int preallocate(BlockDriverState *bs) @@ -839,6 +842,7 @@ static int preallocate(BlockDriverState *bs) return 0; } +#if 0 static int qcow_create2(const char *filename, int64_t total_size, const char *backing_file, const char *backing_format, int flags, size_t cluster_size, int prealloc) @@ -1036,6 +1040,130 @@ exit: return ret; } +#else +static int qcow_create2(const char *filename, int64_t total_size, + const char *backing_file, const char *backing_format, + int flags, size_t cluster_size, int prealloc, + QEMUOptionParameter *options) +{ + /* Calulate cluster_bits */ + int cluster_bits; + cluster_bits = ffs(cluster_size) - 1; + if (cluster_bits < MIN_CLUSTER_BITS || cluster_bits > MAX_CLUSTER_BITS || + (1 << cluster_bits) != cluster_size) + { + error_report( + "Cluster size must be a power of two between %d and %dk\n", + 1 << MIN_CLUSTER_BITS, 1 << (MAX_CLUSTER_BITS - 10)); + return -EINVAL; + } + + /* + * Open the image file and write a minimal qcow2 header. + * + * We keep things simple and start with a zero-sized image. We also + * do without refcount blocks or a L1 table for now. We'll fix the + * inconsistency later. + * + * We do need a refcount table because growing the refcount table means + * allocating two new refcount blocks - the seconds of which would be at + * 2 GB for 64k clusters, and we don't want to have a 2 GB initial file + * size for any qcow2 image. + */ + BlockDriverState* bs; + QCowHeader header; + uint8_t* refcount_table; + int ret; + + ret = bdrv_create_file(filename, options); + if (ret < 0) { + return ret; + } + + ret = bdrv_file_open(&bs, filename, BDRV_O_RDWR); + if (ret < 0) { + return ret; + } + + /* Write the header */ + memset(&header, 0, sizeof(header)); + header.magic = cpu_to_be32(QCOW_MAGIC); + header.version = cpu_to_be32(QCOW_VERSION); + header.cluster_bits = cpu_to_be32(cluster_bits); + header.size = cpu_to_be64(0); + header.l1_table_offset = cpu_to_be64(0); + header.l1_size = cpu_to_be32(0); + header.refcount_table_offset = cpu_to_be64(cluster_size); + header.refcount_table_clusters = cpu_to_be32(1); + + if (flags & BLOCK_FLAG_ENCRYPT) { + header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES); + } else { + header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE); + } + + ret = bdrv_pwrite(bs, 0, &header, sizeof(header)); + if (ret < 0) { + goto out; + } + + /* Write an empty refcount table */ + refcount_table = qemu_mallocz(cluster_size); + ret = bdrv_pwrite(bs, cluster_size, refcount_table, cluster_size); + qemu_free(refcount_table); + + if (ret < 0) { + goto out; + } + + bdrv_close(bs); + + /* + * And now open the image and make it consistent first (i.e. increase the + * refcount of the cluster that is occupied by the header and the refcount + * table) + */ + BlockDriver* drv = bdrv_find_format("qcow2"); + assert(drv != NULL); + ret = bdrv_open(bs, filename, BDRV_O_RDWR | BDRV_O_NO_FLUSH, drv); + if (ret < 0) { + goto out; + } + + ret = qcow2_alloc_clusters(bs, 2 * cluster_size); + if (ret < 0) { + goto out; + + } else if (ret != 0) { + error_report("Huh, first cluster in empty image is already in use?"); + abort(); + } + + /* Okay, now that we have a valid image, let's give it the right size */ + ret = bdrv_truncate(bs, total_size * BDRV_SECTOR_SIZE); + if (ret < 0) { + goto out; + } + + /* Want a backing file? There you go.*/ + if (backing_file) { + ret = bdrv_change_backing_file(bs, backing_file, backing_format); + if (ret < 0) { + goto out; + } + } + + /* And if we're supposed to preallocate metadata, do that now */ + if (prealloc) { + preallocate(bs); + } + + ret = 0; +out: + bdrv_delete(bs); + return ret; +} +#endif static int qcow_create(const char *filename, QEMUOptionParameter *options) { @@ -1081,7 +1209,7 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options) } return qcow_create2(filename, sectors, backing_file, backing_fmt, flags, - cluster_size, prealloc); + cluster_size, prealloc, options); } static int qcow_make_empty(BlockDriverState *bs)