diff mbox

[RFC,4/4] qcow2: Add full image preallocation option

Message ID 3bdffb8a85c3563a38f31846f4687b4c435730ab.1384227383.git.hutao@cn.fujitsu.com
State New
Headers show

Commit Message

Hu Tao Nov. 12, 2013, 7:47 a.m. UTC
This adds a preallocation=full mode to qcow2 image creation, which
creates a non-sparse image file.

Signed-off-by: Hu Tao <hutao@cn.fujitsu.com>
---
 block/qcow2.c | 28 ++++++++++++++++++++++------
 1 file changed, 22 insertions(+), 6 deletions(-)

Comments

Kevin Wolf Nov. 12, 2013, 10:31 a.m. UTC | #1
Am 12.11.2013 um 08:47 hat Hu Tao geschrieben:
> This adds a preallocation=full mode to qcow2 image creation, which
> creates a non-sparse image file.
> 
> Signed-off-by: Hu Tao <hutao@cn.fujitsu.com>
> ---
>  block/qcow2.c | 28 ++++++++++++++++++++++------
>  1 file changed, 22 insertions(+), 6 deletions(-)
> 
> diff --git a/block/qcow2.c b/block/qcow2.c
> index 359030f..d3ca6cf 100644
> --- a/block/qcow2.c
> +++ b/block/qcow2.c
> @@ -1385,7 +1385,13 @@ static int qcow2_change_backing_file(BlockDriverState *bs,
>      return qcow2_update_header(bs);
>  }
>  
> -static int preallocate(BlockDriverState *bs)
> +enum prealloc_mode {
> +    PREALLOC_OFF = 0,
> +    PREALLOC_METADATA,
> +    PREALLOC_FULL,
> +};
> +
> +static int preallocate(BlockDriverState *bs, enum prealloc_mode mode)
>  {
>      uint64_t nb_sectors;
>      uint64_t offset;
> @@ -1394,9 +1400,12 @@ static int preallocate(BlockDriverState *bs)
>      int ret;
>      QCowL2Meta *meta;
>  
> +    assert(mode != PREALLOC_OFF);
> +
>      nb_sectors = bdrv_getlength(bs) >> 9;
>      offset = 0;
>  
> +    /* First allocate metadata in _really_ big chunks */
>      while (nb_sectors) {
>          num = MIN(nb_sectors, INT_MAX >> 9);
>          ret = qcow2_alloc_cluster_offset(bs, offset, 0, num, &num,
> @@ -1424,6 +1433,11 @@ static int preallocate(BlockDriverState *bs)
>          offset += num << 9;
>      }
>  
> +    /* Then write zeros to the cluster data, if requested */
> +    if (mode == PREALLOC_FULL) {
> +        bdrv_zero_init(bs->file, offset, bdrv_getlength(bs));
> +    }

bdrv_zero_init() is completely optional. It is only implemented for
raw-posix and errors are not checked. You can't assume that after this
point anything is preallocated.

Kevin
Hu Tao Nov. 13, 2013, 2:46 a.m. UTC | #2
On Tue, Nov 12, 2013 at 11:31:03AM +0100, Kevin Wolf wrote:
> Am 12.11.2013 um 08:47 hat Hu Tao geschrieben:
> > This adds a preallocation=full mode to qcow2 image creation, which
> > creates a non-sparse image file.
> > 
> > Signed-off-by: Hu Tao <hutao@cn.fujitsu.com>
> > ---
> >  block/qcow2.c | 28 ++++++++++++++++++++++------
> >  1 file changed, 22 insertions(+), 6 deletions(-)
> > 
> > diff --git a/block/qcow2.c b/block/qcow2.c
> > index 359030f..d3ca6cf 100644
> > --- a/block/qcow2.c
> > +++ b/block/qcow2.c
> > @@ -1385,7 +1385,13 @@ static int qcow2_change_backing_file(BlockDriverState *bs,
> >      return qcow2_update_header(bs);
> >  }
> >  
> > -static int preallocate(BlockDriverState *bs)
> > +enum prealloc_mode {
> > +    PREALLOC_OFF = 0,
> > +    PREALLOC_METADATA,
> > +    PREALLOC_FULL,
> > +};
> > +
> > +static int preallocate(BlockDriverState *bs, enum prealloc_mode mode)
> >  {
> >      uint64_t nb_sectors;
> >      uint64_t offset;
> > @@ -1394,9 +1400,12 @@ static int preallocate(BlockDriverState *bs)
> >      int ret;
> >      QCowL2Meta *meta;
> >  
> > +    assert(mode != PREALLOC_OFF);
> > +
> >      nb_sectors = bdrv_getlength(bs) >> 9;
> >      offset = 0;
> >  
> > +    /* First allocate metadata in _really_ big chunks */
> >      while (nb_sectors) {
> >          num = MIN(nb_sectors, INT_MAX >> 9);
> >          ret = qcow2_alloc_cluster_offset(bs, offset, 0, num, &num,
> > @@ -1424,6 +1433,11 @@ static int preallocate(BlockDriverState *bs)
> >          offset += num << 9;
> >      }
> >  
> > +    /* Then write zeros to the cluster data, if requested */
> > +    if (mode == PREALLOC_FULL) {
> > +        bdrv_zero_init(bs->file, offset, bdrv_getlength(bs));
> > +    }
> 
> bdrv_zero_init() is completely optional. It is only implemented for
> raw-posix and errors are not checked. You can't assume that after this
> point anything is preallocated.

Yes, errores should have been checked here.
Peter Lieven Nov. 13, 2013, 6:03 a.m. UTC | #3
What is your use case for this seris? QCOW2 creation or converting
anything to QCOW2? For the later case you could use "qemu-img convert -S 0
..."
starting in 1.8.

Peter

Hu Tao wrote:
> This adds a preallocation=full mode to qcow2 image creation, which
> creates a non-sparse image file.
>
> Signed-off-by: Hu Tao <hutao@cn.fujitsu.com>
> ---
>  block/qcow2.c | 28 ++++++++++++++++++++++------
>  1 file changed, 22 insertions(+), 6 deletions(-)
>
> diff --git a/block/qcow2.c b/block/qcow2.c
> index 359030f..d3ca6cf 100644
> --- a/block/qcow2.c
> +++ b/block/qcow2.c
> @@ -1385,7 +1385,13 @@ static int
> qcow2_change_backing_file(BlockDriverState *bs,
>      return qcow2_update_header(bs);
>  }
>
> -static int preallocate(BlockDriverState *bs)
> +enum prealloc_mode {
> +    PREALLOC_OFF = 0,
> +    PREALLOC_METADATA,
> +    PREALLOC_FULL,
> +};
> +
> +static int preallocate(BlockDriverState *bs, enum prealloc_mode mode)
>  {
>      uint64_t nb_sectors;
>      uint64_t offset;
> @@ -1394,9 +1400,12 @@ static int preallocate(BlockDriverState *bs)
>      int ret;
>      QCowL2Meta *meta;
>
> +    assert(mode != PREALLOC_OFF);
> +
>      nb_sectors = bdrv_getlength(bs) >> 9;
>      offset = 0;
>
> +    /* First allocate metadata in _really_ big chunks */
>      while (nb_sectors) {
>          num = MIN(nb_sectors, INT_MAX >> 9);
>          ret = qcow2_alloc_cluster_offset(bs, offset, 0, num, &num,
> @@ -1424,6 +1433,11 @@ static int preallocate(BlockDriverState *bs)
>          offset += num << 9;
>      }
>
> +    /* Then write zeros to the cluster data, if requested */
> +    if (mode == PREALLOC_FULL) {
> +        bdrv_zero_init(bs->file, offset, bdrv_getlength(bs));
> +    }
> +
>      /*
>       * It is expected that the image file is large enough to actually
> contain
>       * all of the allocated clusters (otherwise we get failing reads
> after
> @@ -1572,11 +1586,11 @@ static int qcow2_create2(const char *filename,
> int64_t total_size,
>          }
>      }
>
> -    /* And if we're supposed to preallocate metadata, do that now */
> +    /* And if we're supposed to preallocate data, do that now */
>      if (prealloc) {
>          BDRVQcowState *
Hu Tao Nov. 15, 2013, 1:29 a.m. UTC | #4
On Wed, Nov 13, 2013 at 07:03:03AM +0100, Peter Lieven wrote:
> What is your use case for this seris? QCOW2 creation or converting
> anything to QCOW2? For the later case you could use "qemu-img convert -S 0
> ..."
> starting in 1.8.

The former. Seems "qemu-img convert -S 0" do the same thing but at
converting time, maybe we can share some code. But let me dig the
code first.

> 
> Peter
> 
> Hu Tao wrote:
> > This adds a preallocation=full mode to qcow2 image creation, which
> > creates a non-sparse image file.
> >
> > Signed-off-by: Hu Tao <hutao@cn.fujitsu.com>
> > ---
> >  block/qcow2.c | 28 ++++++++++++++++++++++------
> >  1 file changed, 22 insertions(+), 6 deletions(-)
> >
> > diff --git a/block/qcow2.c b/block/qcow2.c
> > index 359030f..d3ca6cf 100644
> > --- a/block/qcow2.c
> > +++ b/block/qcow2.c
> > @@ -1385,7 +1385,13 @@ static int
> > qcow2_change_backing_file(BlockDriverState *bs,
> >      return qcow2_update_header(bs);
> >  }
> >
> > -static int preallocate(BlockDriverState *bs)
> > +enum prealloc_mode {
> > +    PREALLOC_OFF = 0,
> > +    PREALLOC_METADATA,
> > +    PREALLOC_FULL,
> > +};
> > +
> > +static int preallocate(BlockDriverState *bs, enum prealloc_mode mode)
> >  {
> >      uint64_t nb_sectors;
> >      uint64_t offset;
> > @@ -1394,9 +1400,12 @@ static int preallocate(BlockDriverState *bs)
> >      int ret;
> >      QCowL2Meta *meta;
> >
> > +    assert(mode != PREALLOC_OFF);
> > +
> >      nb_sectors = bdrv_getlength(bs) >> 9;
> >      offset = 0;
> >
> > +    /* First allocate metadata in _really_ big chunks */
> >      while (nb_sectors) {
> >          num = MIN(nb_sectors, INT_MAX >> 9);
> >          ret = qcow2_alloc_cluster_offset(bs, offset, 0, num, &num,
> > @@ -1424,6 +1433,11 @@ static int preallocate(BlockDriverState *bs)
> >          offset += num << 9;
> >      }
> >
> > +    /* Then write zeros to the cluster data, if requested */
> > +    if (mode == PREALLOC_FULL) {
> > +        bdrv_zero_init(bs->file, offset, bdrv_getlength(bs));
> > +    }
> > +
> >      /*
> >       * It is expected that the image file is large enough to actually
> > contain
> >       * all of the allocated clusters (otherwise we get failing reads
> > after
> > @@ -1572,11 +1586,11 @@ static int qcow2_create2(const char *filename,
> > int64_t total_size,
> >          }
> >      }
> >
> > -    /* And if we're supposed to preallocate metadata, do that now */
> > +    /* And if we're supposed to preallocate data, do that now */
> >      if (prealloc) {
> >          BDRVQcowState *
>
Hu Tao Nov. 15, 2013, 8:44 a.m. UTC | #5
On Fri, Nov 15, 2013 at 09:29:43AM +0800, Hu Tao wrote:
> On Wed, Nov 13, 2013 at 07:03:03AM +0100, Peter Lieven wrote:
> > What is your use case for this seris? QCOW2 creation or converting
> > anything to QCOW2? For the later case you could use "qemu-img convert -S 0
> > ..."
> > starting in 1.8.
> 
> The former. Seems "qemu-img convert -S 0" do the same thing but at
> converting time, maybe we can share some code. But let me dig the
> code first.

The purpose is to using posix_fallocate() to preallocate space, other
than writing zeros to do it. Because the latter is pretty slow. 

> 
> > 
> > Peter
> > 
> > Hu Tao wrote:
> > > This adds a preallocation=full mode to qcow2 image creation, which
> > > creates a non-sparse image file.
> > >
> > > Signed-off-by: Hu Tao <hutao@cn.fujitsu.com>
> > > ---
> > >  block/qcow2.c | 28 ++++++++++++++++++++++------
> > >  1 file changed, 22 insertions(+), 6 deletions(-)
> > >
> > > diff --git a/block/qcow2.c b/block/qcow2.c
> > > index 359030f..d3ca6cf 100644
> > > --- a/block/qcow2.c
> > > +++ b/block/qcow2.c
> > > @@ -1385,7 +1385,13 @@ static int
> > > qcow2_change_backing_file(BlockDriverState *bs,
> > >      return qcow2_update_header(bs);
> > >  }
> > >
> > > -static int preallocate(BlockDriverState *bs)
> > > +enum prealloc_mode {
> > > +    PREALLOC_OFF = 0,
> > > +    PREALLOC_METADATA,
> > > +    PREALLOC_FULL,
> > > +};
> > > +
> > > +static int preallocate(BlockDriverState *bs, enum prealloc_mode mode)
> > >  {
> > >      uint64_t nb_sectors;
> > >      uint64_t offset;
> > > @@ -1394,9 +1400,12 @@ static int preallocate(BlockDriverState *bs)
> > >      int ret;
> > >      QCowL2Meta *meta;
> > >
> > > +    assert(mode != PREALLOC_OFF);
> > > +
> > >      nb_sectors = bdrv_getlength(bs) >> 9;
> > >      offset = 0;
> > >
> > > +    /* First allocate metadata in _really_ big chunks */
> > >      while (nb_sectors) {
> > >          num = MIN(nb_sectors, INT_MAX >> 9);
> > >          ret = qcow2_alloc_cluster_offset(bs, offset, 0, num, &num,
> > > @@ -1424,6 +1433,11 @@ static int preallocate(BlockDriverState *bs)
> > >          offset += num << 9;
> > >      }
> > >
> > > +    /* Then write zeros to the cluster data, if requested */
> > > +    if (mode == PREALLOC_FULL) {
> > > +        bdrv_zero_init(bs->file, offset, bdrv_getlength(bs));
> > > +    }
> > > +
> > >      /*
> > >       * It is expected that the image file is large enough to actually
> > > contain
> > >       * all of the allocated clusters (otherwise we get failing reads
> > > after
> > > @@ -1572,11 +1586,11 @@ static int qcow2_create2(const char *filename,
> > > int64_t total_size,
> > >          }
> > >      }
> > >
> > > -    /* And if we're supposed to preallocate metadata, do that now */
> > > +    /* And if we're supposed to preallocate data, do that now */
> > >      if (prealloc) {
> > >          BDRVQcowState *
> >
diff mbox

Patch

diff --git a/block/qcow2.c b/block/qcow2.c
index 359030f..d3ca6cf 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -1385,7 +1385,13 @@  static int qcow2_change_backing_file(BlockDriverState *bs,
     return qcow2_update_header(bs);
 }
 
-static int preallocate(BlockDriverState *bs)
+enum prealloc_mode {
+    PREALLOC_OFF = 0,
+    PREALLOC_METADATA,
+    PREALLOC_FULL,
+};
+
+static int preallocate(BlockDriverState *bs, enum prealloc_mode mode)
 {
     uint64_t nb_sectors;
     uint64_t offset;
@@ -1394,9 +1400,12 @@  static int preallocate(BlockDriverState *bs)
     int ret;
     QCowL2Meta *meta;
 
+    assert(mode != PREALLOC_OFF);
+
     nb_sectors = bdrv_getlength(bs) >> 9;
     offset = 0;
 
+    /* First allocate metadata in _really_ big chunks */
     while (nb_sectors) {
         num = MIN(nb_sectors, INT_MAX >> 9);
         ret = qcow2_alloc_cluster_offset(bs, offset, 0, num, &num,
@@ -1424,6 +1433,11 @@  static int preallocate(BlockDriverState *bs)
         offset += num << 9;
     }
 
+    /* Then write zeros to the cluster data, if requested */
+    if (mode == PREALLOC_FULL) {
+        bdrv_zero_init(bs->file, offset, bdrv_getlength(bs));
+    }
+
     /*
      * It is expected that the image file is large enough to actually contain
      * all of the allocated clusters (otherwise we get failing reads after
@@ -1572,11 +1586,11 @@  static int qcow2_create2(const char *filename, int64_t total_size,
         }
     }
 
-    /* And if we're supposed to preallocate metadata, do that now */
+    /* And if we're supposed to preallocate data, do that now */
     if (prealloc) {
         BDRVQcowState *s = bs->opaque;
         qemu_co_mutex_lock(&s->lock);
-        ret = preallocate(bs);
+        ret = preallocate(bs, prealloc);
         qemu_co_mutex_unlock(&s->lock);
         if (ret < 0) {
             error_setg_errno(errp, -ret, "Could not preallocate metadata");
@@ -1629,9 +1643,11 @@  static int qcow2_create(const char *filename, QEMUOptionParameter *options,
             }
         } else if (!strcmp(options->name, BLOCK_OPT_PREALLOC)) {
             if (!options->value.s || !strcmp(options->value.s, "off")) {
-                prealloc = 0;
+                prealloc = PREALLOC_OFF;
             } else if (!strcmp(options->value.s, "metadata")) {
-                prealloc = 1;
+                prealloc = PREALLOC_METADATA;
+            } else if (!strcmp(options->value.s, "full")) {
+                prealloc = PREALLOC_FULL;
             } else {
                 error_setg(errp, "Invalid preallocation mode: '%s'",
                            options->value.s);
@@ -2221,7 +2237,7 @@  static QEMUOptionParameter qcow2_create_options[] = {
     {
         .name = BLOCK_OPT_PREALLOC,
         .type = OPT_STRING,
-        .help = "Preallocation mode (allowed values: off, metadata)"
+        .help = "Preallocation mode (allowed values: off, metadata, full)"
     },
     {
         .name = BLOCK_OPT_LAZY_REFCOUNTS,