qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/2] qcow2: Simplify image creation code
@ 2010-06-14 14:43 Kevin Wolf
  2010-06-14 14:43 ` [Qemu-devel] [PATCH 1/2] qcow2: Simplify image creation Kevin Wolf
  2010-06-14 14:43 ` [Qemu-devel] [PATCH 2/2] qcow2: Remove old image creation function Kevin Wolf
  0 siblings, 2 replies; 9+ messages in thread
From: Kevin Wolf @ 2010-06-14 14:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, quintela

Juan, you've complained a few times in the past about how complicated the
qcow_create2 code was. I hope you'll like this one. :-)

Kevin Wolf (2):
  qcow2: Simplify image creation
  qcow2: Remove old image creation function

 block/qcow2.c |  272 ++++++++++++++++++---------------------------------------
 1 files changed, 86 insertions(+), 186 deletions(-)

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PATCH 1/2] qcow2: Simplify image creation
  2010-06-14 14:43 [Qemu-devel] [PATCH 0/2] qcow2: Simplify image creation code Kevin Wolf
@ 2010-06-14 14:43 ` Kevin Wolf
  2010-06-15 10:14   ` Stefan Hajnoczi
  2010-06-14 14:43 ` [Qemu-devel] [PATCH 2/2] qcow2: Remove old image creation function Kevin Wolf
  1 sibling, 1 reply; 9+ messages in thread
From: Kevin Wolf @ 2010-06-14 14:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, quintela

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 <kwolf@redhat.com>
---
 block/qcow2.c |  126 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 125 insertions(+), 1 deletions(-)

diff --git a/block/qcow2.c b/block/qcow2.c
index 33fa9a9..acb850c 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -27,6 +27,7 @@
 #include <zlib.h>
 #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,126 @@ 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) {
+        return ret;
+    }
+
+    /* 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) {
+        return ret;
+    }
+
+    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) {
+        return ret;
+    }
+
+    ret = qcow2_alloc_clusters(bs, 2 * cluster_size);
+    if (ret < 0) {
+        return ret;
+    } 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) {
+        return ret;
+    }
+
+    /* Want a backing file? There you go.*/
+    if (backing_file) {
+        ret = bdrv_change_backing_file(bs, backing_file, backing_format);
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    /* And if we're supposed to preallocate metadata, do that now */
+    if (prealloc) {
+        preallocate(bs);
+    }
+
+    return 0;
+}
+#endif
 
 static int qcow_create(const char *filename, QEMUOptionParameter *options)
 {
@@ -1081,7 +1205,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)
-- 
1.6.6.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PATCH 2/2] qcow2: Remove old image creation function
  2010-06-14 14:43 [Qemu-devel] [PATCH 0/2] qcow2: Simplify image creation code Kevin Wolf
  2010-06-14 14:43 ` [Qemu-devel] [PATCH 1/2] qcow2: Simplify image creation Kevin Wolf
@ 2010-06-14 14:43 ` Kevin Wolf
  1 sibling, 0 replies; 9+ messages in thread
From: Kevin Wolf @ 2010-06-14 14:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, quintela

They have been #ifdef'd out by the previous patch.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block/qcow2.c |  224 ---------------------------------------------------------
 1 files changed, 0 insertions(+), 224 deletions(-)

diff --git a/block/qcow2.c b/block/qcow2.c
index acb850c..6f26564 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -768,30 +768,6 @@ 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;
-
-    if (size == 0) {
-        return -1;
-    }
-
-    while (size != 1) {
-        /* Not a power of two */
-        if (size & 1) {
-            return -1;
-        }
-
-        size >>= 1;
-        res++;
-    }
-
-    return res;
-}
-#endif
-
-
 static int preallocate(BlockDriverState *bs)
 {
     uint64_t nb_sectors;
@@ -842,205 +818,6 @@ 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)
-{
-
-    int fd, header_size, backing_filename_len, l1_size, i, shift, l2_bits;
-    int ref_clusters, reftable_clusters, backing_format_len = 0;
-    int rounded_ext_bf_len = 0;
-    QCowHeader header;
-    uint64_t tmp, offset;
-    uint64_t old_ref_clusters;
-    QCowCreateState s1, *s = &s1;
-    QCowExtension ext_bf = {0, 0};
-    int ret;
-
-    memset(s, 0, sizeof(*s));
-
-    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
-    if (fd < 0)
-        return -errno;
-    memset(&header, 0, sizeof(header));
-    header.magic = cpu_to_be32(QCOW_MAGIC);
-    header.version = cpu_to_be32(QCOW_VERSION);
-    header.size = cpu_to_be64(total_size * 512);
-    header_size = sizeof(header);
-    backing_filename_len = 0;
-    if (backing_file) {
-        if (backing_format) {
-            ext_bf.magic = QCOW_EXT_MAGIC_BACKING_FORMAT;
-            backing_format_len = strlen(backing_format);
-            ext_bf.len = backing_format_len;
-            rounded_ext_bf_len = (sizeof(ext_bf) + ext_bf.len + 7) & ~7;
-            header_size += rounded_ext_bf_len;
-        }
-        header.backing_file_offset = cpu_to_be64(header_size);
-        backing_filename_len = strlen(backing_file);
-        header.backing_file_size = cpu_to_be32(backing_filename_len);
-        header_size += backing_filename_len;
-    }
-
-    /* Cluster size */
-    s->cluster_bits = get_bits_from_size(cluster_size);
-    if (s->cluster_bits < MIN_CLUSTER_BITS ||
-        s->cluster_bits > MAX_CLUSTER_BITS)
-    {
-        fprintf(stderr, "Cluster size must be a power of two between "
-            "%d and %dk\n",
-            1 << MIN_CLUSTER_BITS,
-            1 << (MAX_CLUSTER_BITS - 10));
-        return -EINVAL;
-    }
-    s->cluster_size = 1 << s->cluster_bits;
-
-    header.cluster_bits = cpu_to_be32(s->cluster_bits);
-    header_size = (header_size + 7) & ~7;
-    if (flags & BLOCK_FLAG_ENCRYPT) {
-        header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES);
-    } else {
-        header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE);
-    }
-    l2_bits = s->cluster_bits - 3;
-    shift = s->cluster_bits + l2_bits;
-    l1_size = (((total_size * 512) + (1LL << shift) - 1) >> shift);
-    offset = align_offset(header_size, s->cluster_size);
-    s->l1_table_offset = offset;
-    header.l1_table_offset = cpu_to_be64(s->l1_table_offset);
-    header.l1_size = cpu_to_be32(l1_size);
-    offset += align_offset(l1_size * sizeof(uint64_t), s->cluster_size);
-
-    /* count how many refcount blocks needed */
-
-#define NUM_CLUSTERS(bytes) \
-    (((bytes) + (s->cluster_size) - 1) / (s->cluster_size))
-
-    ref_clusters = NUM_CLUSTERS(NUM_CLUSTERS(offset) * sizeof(uint16_t));
-
-    do {
-        uint64_t image_clusters;
-        old_ref_clusters = ref_clusters;
-
-        /* Number of clusters used for the refcount table */
-        reftable_clusters = NUM_CLUSTERS(ref_clusters * sizeof(uint64_t));
-
-        /* Number of clusters that the whole image will have */
-        image_clusters = NUM_CLUSTERS(offset) + ref_clusters
-            + reftable_clusters;
-
-        /* Number of refcount blocks needed for the image */
-        ref_clusters = NUM_CLUSTERS(image_clusters * sizeof(uint16_t));
-
-    } while (ref_clusters != old_ref_clusters);
-
-    s->refcount_table = qemu_mallocz(reftable_clusters * s->cluster_size);
-
-    s->refcount_table_offset = offset;
-    header.refcount_table_offset = cpu_to_be64(offset);
-    header.refcount_table_clusters = cpu_to_be32(reftable_clusters);
-    offset += (reftable_clusters * s->cluster_size);
-    s->refcount_block_offset = offset;
-
-    for (i=0; i < ref_clusters; i++) {
-        s->refcount_table[i] = cpu_to_be64(offset);
-        offset += s->cluster_size;
-    }
-
-    s->refcount_block = qemu_mallocz(ref_clusters * s->cluster_size);
-
-    /* update refcounts */
-    qcow2_create_refcount_update(s, 0, header_size);
-    qcow2_create_refcount_update(s, s->l1_table_offset,
-        l1_size * sizeof(uint64_t));
-    qcow2_create_refcount_update(s, s->refcount_table_offset,
-        reftable_clusters * s->cluster_size);
-    qcow2_create_refcount_update(s, s->refcount_block_offset,
-        ref_clusters * s->cluster_size);
-
-    /* write all the data */
-    ret = qemu_write_full(fd, &header, sizeof(header));
-    if (ret != sizeof(header)) {
-        ret = -errno;
-        goto exit;
-    }
-    if (backing_file) {
-        if (backing_format_len) {
-            char zero[16];
-            int padding = rounded_ext_bf_len - (ext_bf.len + sizeof(ext_bf));
-
-            memset(zero, 0, sizeof(zero));
-            cpu_to_be32s(&ext_bf.magic);
-            cpu_to_be32s(&ext_bf.len);
-            ret = qemu_write_full(fd, &ext_bf, sizeof(ext_bf));
-            if (ret != sizeof(ext_bf)) {
-                ret = -errno;
-                goto exit;
-            }
-            ret = qemu_write_full(fd, backing_format, backing_format_len);
-            if (ret != backing_format_len) {
-                ret = -errno;
-                goto exit;
-            }
-            if (padding > 0) {
-                ret = qemu_write_full(fd, zero, padding);
-                if (ret != padding) {
-                    ret = -errno;
-                    goto exit;
-                }
-            }
-        }
-        ret = qemu_write_full(fd, backing_file, backing_filename_len);
-        if (ret != backing_filename_len) {
-            ret = -errno;
-            goto exit;
-        }
-    }
-    lseek(fd, s->l1_table_offset, SEEK_SET);
-    tmp = 0;
-    for(i = 0;i < l1_size; i++) {
-        ret = qemu_write_full(fd, &tmp, sizeof(tmp));
-        if (ret != sizeof(tmp)) {
-            ret = -errno;
-            goto exit;
-        }
-    }
-    lseek(fd, s->refcount_table_offset, SEEK_SET);
-    ret = qemu_write_full(fd, s->refcount_table,
-        reftable_clusters * s->cluster_size);
-    if (ret != reftable_clusters * s->cluster_size) {
-        ret = -errno;
-        goto exit;
-    }
-
-    lseek(fd, s->refcount_block_offset, SEEK_SET);
-    ret = qemu_write_full(fd, s->refcount_block,
-		    ref_clusters * s->cluster_size);
-    if (ret != ref_clusters * s->cluster_size) {
-        ret = -errno;
-        goto exit;
-    }
-
-    ret = 0;
-exit:
-    qemu_free(s->refcount_table);
-    qemu_free(s->refcount_block);
-    close(fd);
-
-    /* Preallocate metadata */
-    if (ret == 0 && prealloc) {
-        BlockDriverState *bs;
-        BlockDriver *drv = bdrv_find_format("qcow2");
-        bs = bdrv_new("");
-        bdrv_open(bs, filename, BDRV_O_CACHE_WB | BDRV_O_RDWR, drv);
-        preallocate(bs);
-        bdrv_close(bs);
-    }
-
-    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,
@@ -1159,7 +936,6 @@ static int qcow_create2(const char *filename, int64_t total_size,
 
     return 0;
 }
-#endif
 
 static int qcow_create(const char *filename, QEMUOptionParameter *options)
 {
-- 
1.6.6.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] [PATCH 1/2] qcow2: Simplify image creation
  2010-06-14 14:43 ` [Qemu-devel] [PATCH 1/2] qcow2: Simplify image creation Kevin Wolf
@ 2010-06-15 10:14   ` Stefan Hajnoczi
  2010-06-15 10:31     ` Kevin Wolf
  2010-06-15 10:36     ` [Qemu-devel] [PATCH v2 " Kevin Wolf
  0 siblings, 2 replies; 9+ messages in thread
From: Stefan Hajnoczi @ 2010-06-15 10:14 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: qemu-devel, quintela

On Mon, Jun 14, 2010 at 3:43 PM, Kevin Wolf <kwolf@redhat.com> wrote:
> 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.

Nice idea.

> +    ret = bdrv_pwrite(bs, 0, &header, sizeof(header));
> +    if (ret < 0) {
> +        return ret;
> +    }

The bs is not closed on error.  Also, this function will leave a
partially created file on disk if it fails.

> +    /* And if we're supposed to preallocate metadata, do that now */
> +    if (prealloc) {
> +        preallocate(bs);
> +    }
> +
> +    return 0;
> +}

The bs is leaked when the function succeeds.

Stefan

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] [PATCH 1/2] qcow2: Simplify image creation
  2010-06-15 10:14   ` Stefan Hajnoczi
@ 2010-06-15 10:31     ` Kevin Wolf
  2010-06-15 10:36     ` [Qemu-devel] [PATCH v2 " Kevin Wolf
  1 sibling, 0 replies; 9+ messages in thread
From: Kevin Wolf @ 2010-06-15 10:31 UTC (permalink / raw)
  To: Stefan Hajnoczi; +Cc: qemu-devel, quintela

Am 15.06.2010 12:14, schrieb Stefan Hajnoczi:
> On Mon, Jun 14, 2010 at 3:43 PM, Kevin Wolf <kwolf@redhat.com> wrote:
>> 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.
> 
> Nice idea.
> 
>> +    ret = bdrv_pwrite(bs, 0, &header, sizeof(header));
>> +    if (ret < 0) {
>> +        return ret;
>> +    }
> 
> The bs is not closed on error.  

Right, will fix the missing bdrv_delete here and in other cases.

> Also, this function will leave a
> partially created file on disk if it fails.

As did the old one, and the bdrv_create functions of most other formats
behave the same. We could implement a bdrv_remove to remove that file
again, but it would be ununsed except for these very unlikely error
cases. If you can't access the disk, usually the bdrv_create_file would
fail already.

Kevin

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PATCH v2 1/2] qcow2: Simplify image creation
  2010-06-15 10:14   ` Stefan Hajnoczi
  2010-06-15 10:31     ` Kevin Wolf
@ 2010-06-15 10:36     ` Kevin Wolf
  2010-06-15 11:08       ` [Qemu-devel] " Stefan Hajnoczi
  1 sibling, 1 reply; 9+ messages in thread
From: Kevin Wolf @ 2010-06-15 10:36 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, stefanha

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 <kwolf@redhat.com>
---
 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 <zlib.h>
 #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)
-- 
1.6.6.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] Re: [PATCH v2 1/2] qcow2: Simplify image creation
  2010-06-15 10:36     ` [Qemu-devel] [PATCH v2 " Kevin Wolf
@ 2010-06-15 11:08       ` Stefan Hajnoczi
  2010-06-15 11:31         ` Kevin Wolf
  0 siblings, 1 reply; 9+ messages in thread
From: Stefan Hajnoczi @ 2010-06-15 11:08 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: qemu-devel

On Tue, Jun 15, 2010 at 11:36 AM, Kevin Wolf <kwolf@redhat.com> wrote:
> +    /*
> +     * 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;
> +    }

Here I think we should really return directly on error.
bdrv_delete(bs) doesn't work since bs isn't initialized when
bdrv_open() fails.

Stefan

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] Re: [PATCH v2 1/2] qcow2: Simplify image creation
  2010-06-15 11:08       ` [Qemu-devel] " Stefan Hajnoczi
@ 2010-06-15 11:31         ` Kevin Wolf
  2010-06-15 11:53           ` Stefan Hajnoczi
  0 siblings, 1 reply; 9+ messages in thread
From: Kevin Wolf @ 2010-06-15 11:31 UTC (permalink / raw)
  To: Stefan Hajnoczi; +Cc: qemu-devel

Am 15.06.2010 13:08, schrieb Stefan Hajnoczi:
> On Tue, Jun 15, 2010 at 11:36 AM, Kevin Wolf <kwolf@redhat.com> wrote:
>> +    /*
>> +     * 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;
>> +    }
> 
> Here I think we should really return directly on error.
> bdrv_delete(bs) doesn't work since bs isn't initialized when
> bdrv_open() fails.

I did consider returning directly here at first, but decided against it
because usually you expect that a function that uses some goto does so
consistently. Also, I noticed later that returning directly we would
leak the BlockDriverState which is malloc'd in bdrv_file_open.

bs should still be initialized at this point and bs->drv = NULL after
the bdrv_close() above, so that bdrv_delete(bs) will just free the
BlockDriverState.

Kevin

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] Re: [PATCH v2 1/2] qcow2: Simplify image creation
  2010-06-15 11:31         ` Kevin Wolf
@ 2010-06-15 11:53           ` Stefan Hajnoczi
  0 siblings, 0 replies; 9+ messages in thread
From: Stefan Hajnoczi @ 2010-06-15 11:53 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: qemu-devel

On Tue, Jun 15, 2010 at 12:31 PM, Kevin Wolf <kwolf@redhat.com> wrote:
> Am 15.06.2010 13:08, schrieb Stefan Hajnoczi:
>> On Tue, Jun 15, 2010 at 11:36 AM, Kevin Wolf <kwolf@redhat.com> wrote:
>>> +    /*
>>> +     * 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;
>>> +    }
>>
>> Here I think we should really return directly on error.
>> bdrv_delete(bs) doesn't work since bs isn't initialized when
>> bdrv_open() fails.
>
> I did consider returning directly here at first, but decided against it
> because usually you expect that a function that uses some goto does so
> consistently. Also, I noticed later that returning directly we would
> leak the BlockDriverState which is malloc'd in bdrv_file_open.
>
> bs should still be initialized at this point and bs->drv = NULL after
> the bdrv_close() above, so that bdrv_delete(bs) will just free the
> BlockDriverState.

I see, you're right.

Looks good.

Stefan

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2010-06-15 11:53 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-06-14 14:43 [Qemu-devel] [PATCH 0/2] qcow2: Simplify image creation code Kevin Wolf
2010-06-14 14:43 ` [Qemu-devel] [PATCH 1/2] qcow2: Simplify image creation Kevin Wolf
2010-06-15 10:14   ` Stefan Hajnoczi
2010-06-15 10:31     ` Kevin Wolf
2010-06-15 10:36     ` [Qemu-devel] [PATCH v2 " Kevin Wolf
2010-06-15 11:08       ` [Qemu-devel] " Stefan Hajnoczi
2010-06-15 11:31         ` Kevin Wolf
2010-06-15 11:53           ` Stefan Hajnoczi
2010-06-14 14:43 ` [Qemu-devel] [PATCH 2/2] qcow2: Remove old image creation function Kevin Wolf

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).