All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.