* [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
* 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
* [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
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).