diff mbox

[1/4] block/qcow2: add compression_algorithm create option

Message ID 1498566850-7934-2-git-send-email-pl@kamp.de
State New
Headers show

Commit Message

Peter Lieven June 27, 2017, 12:34 p.m. UTC
this patch adds a new compression_algorithm option when creating qcow2 images.
The current default for the compresison algorithm is zlib and zlib will be
used when this option is omitted (like before).

If the option is specified e.g. with:

 qemu-img create -f qcow2 -o compression_algorithm=zlib image.qcow2 1G

then a new compression algorithm header extension is added and an incompatible
feature bit is set. This means that if the header is present it must be parsed
by Qemu on qcow2_open and it must be validated if the specified compression
algorithm is supported by the current build of Qemu.

This means if the compression_algorithm option is specified Qemu prior to this
commit will not be able to open the created image.

Signed-off-by: Peter Lieven <pl@kamp.de>
---
 block/qcow2.c             | 93 ++++++++++++++++++++++++++++++++++++++++++++---
 block/qcow2.h             | 20 +++++++---
 docs/interop/qcow2.txt    |  8 +++-
 include/block/block_int.h | 35 +++++++++---------
 qemu-img.texi             | 10 +++++
 5 files changed, 138 insertions(+), 28 deletions(-)

Comments

Eric Blake June 27, 2017, 12:49 p.m. UTC | #1
On 06/27/2017 07:34 AM, Peter Lieven wrote:
> this patch adds a new compression_algorithm option when creating qcow2 images.
> The current default for the compresison algorithm is zlib and zlib will be

s/compresison/compression/

> used when this option is omitted (like before).
> 
> If the option is specified e.g. with:
> 
>  qemu-img create -f qcow2 -o compression_algorithm=zlib image.qcow2 1G
> 
> then a new compression algorithm header extension is added and an incompatible
> feature bit is set. This means that if the header is present it must be parsed
> by Qemu on qcow2_open and it must be validated if the specified compression
> algorithm is supported by the current build of Qemu.
> 
> This means if the compression_algorithm option is specified Qemu prior to this
> commit will not be able to open the created image.
> 
> Signed-off-by: Peter Lieven <pl@kamp.de>
> ---
>  block/qcow2.c             | 93 ++++++++++++++++++++++++++++++++++++++++++++---
>  block/qcow2.h             | 20 +++++++---
>  docs/interop/qcow2.txt    |  8 +++-

Focusing on just the spec change first:

> +++ b/docs/interop/qcow2.txt
> @@ -85,7 +85,11 @@ in the description of a field.
>                                  be written to (unless for regaining
>                                  consistency).
>  
> -                    Bits 2-63:  Reserved (set to 0)
> +                    Bit 2:      Compress algorithm bit.  If this bit is set then
> +                                the compress algorithm extension must be parsed
> +                                and checked for compatiblity.

s/compatiblity/compatibility/

> +
> +                    Bits 3-63:  Reserved (set to 0)
>  
>           80 -  87:  compatible_features
>                      Bitmask of compatible features. An implementation can
> @@ -135,6 +139,8 @@ be stored. Each extension has a structure like the following:
>                          0xE2792ACA - Backing file format name
>                          0x6803f857 - Feature name table
>                          0x23852875 - Bitmaps extension
> +                        0xC0318300 - Compression Algorithm
> +                        0xC03183xx - Reserved for compression algorithm params

s/params/parameters/

You have now introduced 256 different reserved headers, without
documenting any of their formats.  You absolutely MUST include a
documentation of how the new 0xC0318300 header is laid out (see, for
example, our section on "Bitmaps extension"), along with text mentioning
that the new header MUST be present if incompatible-feature bit is set
and MUST be absent otherwise.  But I also think that with a bit of
proper design work, you only need ONE header for all possible algorithm
parameters, rather than burning an additional 255 unspecified
reservations.  That is, make sure your new header includes a common
prefix including a length field and the algorightm in use, and then the
length covers a variable-length suffix that can be parsed in a
per-algorithm-specific manner for whatever additional parameters are
needed for that algorithm.
Daniel P. Berrangé June 27, 2017, 1:20 p.m. UTC | #2
On Tue, Jun 27, 2017 at 02:34:07PM +0200, Peter Lieven wrote:
> this patch adds a new compression_algorithm option when creating qcow2 images.
> The current default for the compresison algorithm is zlib and zlib will be
> used when this option is omitted (like before).
> 
> If the option is specified e.g. with:
> 
>  qemu-img create -f qcow2 -o compression_algorithm=zlib image.qcow2 1G

IMHO we should introduce a nested struct "compress" struct to hold the format
name, and any other format specific arguments, in a way that maps nicely to
any future QAPI representmatch of create options. eg

{ 'enum': 'BlockdevQcow2CompressFormat',
  'data': [ 'zlib', 'lzo' ] }

{ 'union': 'BlockdevQcow2Compress',
  'base': { 'format': 'BlockdevQcow2CompressFormat' },
  'discriminator': 'format',
  'data': { 'zlib': 'BlockdevQcow2CompressZLib',
            'lzo': 'BlockdevQcow2CompressLZO'} }

so it would map to

 qemu-img create -f qcow2 -o compress.format=zlib image.qcow2 1G

and let us have other compress.XXXX options specific to each format

Regards,
Daniel
Peter Lieven June 27, 2017, 1:27 p.m. UTC | #3
Am 27.06.2017 um 15:20 schrieb Daniel P. Berrange:
> On Tue, Jun 27, 2017 at 02:34:07PM +0200, Peter Lieven wrote:
>> this patch adds a new compression_algorithm option when creating qcow2 images.
>> The current default for the compresison algorithm is zlib and zlib will be
>> used when this option is omitted (like before).
>>
>> If the option is specified e.g. with:
>>
>>   qemu-img create -f qcow2 -o compression_algorithm=zlib image.qcow2 1G
> IMHO we should introduce a nested struct "compress" struct to hold the format
> name, and any other format specific arguments, in a way that maps nicely to
> any future QAPI representmatch of create options. eg
>
> { 'enum': 'BlockdevQcow2CompressFormat',
>    'data': [ 'zlib', 'lzo' ] }
>
> { 'union': 'BlockdevQcow2Compress',
>    'base': { 'format': 'BlockdevQcow2CompressFormat' },
>    'discriminator': 'format',
>    'data': { 'zlib': 'BlockdevQcow2CompressZLib',
>              'lzo': 'BlockdevQcow2CompressLZO'} }
>
> so it would map to
>
>   qemu-img create -f qcow2 -o compress.format=zlib image.qcow2 1G
>
> and let us have other compress.XXXX options specific to each format

Or would it be possible to start with just a compress.level (int) parameter.
In fact that would be sufficient for almost all formats (or better use algorithms?).
The windowBits can be default to -15 in the future. It seems the old choice of -12
was just not optimal. We just have to use it for backwards compatiblity if the compress
options are not specified.

Peter
Denis V. Lunev June 28, 2017, 2:50 p.m. UTC | #4
On 06/27/2017 04:27 PM, Peter Lieven wrote:
> Am 27.06.2017 um 15:20 schrieb Daniel P. Berrange:
>> On Tue, Jun 27, 2017 at 02:34:07PM +0200, Peter Lieven wrote:
>>> this patch adds a new compression_algorithm option when creating
>>> qcow2 images.
>>> The current default for the compresison algorithm is zlib and zlib
>>> will be
>>> used when this option is omitted (like before).
>>>
>>> If the option is specified e.g. with:
>>>
>>>   qemu-img create -f qcow2 -o compression_algorithm=zlib image.qcow2 1G
>> IMHO we should introduce a nested struct "compress" struct to hold
>> the format
>> name, and any other format specific arguments, in a way that maps
>> nicely to
>> any future QAPI representmatch of create options. eg
>>
>> { 'enum': 'BlockdevQcow2CompressFormat',
>>    'data': [ 'zlib', 'lzo' ] }
>>
>> { 'union': 'BlockdevQcow2Compress',
>>    'base': { 'format': 'BlockdevQcow2CompressFormat' },
>>    'discriminator': 'format',
>>    'data': { 'zlib': 'BlockdevQcow2CompressZLib',
>>              'lzo': 'BlockdevQcow2CompressLZO'} }
>>
>> so it would map to
>>
>>   qemu-img create -f qcow2 -o compress.format=zlib image.qcow2 1G
>>
>> and let us have other compress.XXXX options specific to each format
>
> Or would it be possible to start with just a compress.level (int)
> parameter.
> In fact that would be sufficient for almost all formats (or better use
> algorithms?).
> The windowBits can be default to -15 in the future. It seems the old
> choice of -12
> was just not optimal. We just have to use it for backwards
> compatiblity if the compress
> options are not specified.
>
> Peter
>
We can put generic parameters on top (in generic header) but
put algorithm-dependent container inside. This could be
viable for the future to avoid incompatible format changes.

Den
Denis V. Lunev June 28, 2017, 2:54 p.m. UTC | #5
On 06/27/2017 03:34 PM, Peter Lieven wrote:
> this patch adds a new compression_algorithm option when creating qcow2 images.
> The current default for the compresison algorithm is zlib and zlib will be
> used when this option is omitted (like before).
>
> If the option is specified e.g. with:
>
>  qemu-img create -f qcow2 -o compression_algorithm=zlib image.qcow2 1G
>
> then a new compression algorithm header extension is added and an incompatible
> feature bit is set. This means that if the header is present it must be parsed
> by Qemu on qcow2_open and it must be validated if the specified compression
> algorithm is supported by the current build of Qemu.
>
> This means if the compression_algorithm option is specified Qemu prior to this
> commit will not be able to open the created image.
>
> Signed-off-by: Peter Lieven <pl@kamp.de>

as general, it is weird to have formatting changes, spec changes and
real code changes in one patch.

[skipped]

> diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt
> index 80cdfd0..1f165d6 100644
> --- a/docs/interop/qcow2.txt
> +++ b/docs/interop/qcow2.txt
> @@ -85,7 +85,11 @@ in the description of a field.
>                                  be written to (unless for regaining
>                                  consistency).
>  
> -                    Bits 2-63:  Reserved (set to 0)
> +                    Bit 2:      Compress algorithm bit.  If this bit is set then
> +                                the compress algorithm extension must be parsed
> +                                and checked for compatiblity.
Eric is correct here. We should add note that compressed algorithm extension
must present when the bit is sent and must be absent in the other case.

> +
> +                    Bits 3-63:  Reserved (set to 0)
>  
>           80 -  87:  compatible_features
>                      Bitmask of compatible features. An implementation can
> @@ -135,6 +139,8 @@ be stored. Each extension has a structure like the following:
>                          0xE2792ACA - Backing file format name
>                          0x6803f857 - Feature name table
>                          0x23852875 - Bitmaps extension
> +                        0xC0318300 - Compression Algorithm
> +                        0xC03183xx - Reserved for compression algorithm params
>                          other      - Unknown header extension, can be safely
>                                       ignored

I think that there is no need to reserve 255 magics once we will
add opaque container to the extension.

>  
> diff --git a/include/block/block_int.h b/include/block/block_int.h
> index 15fa602..03a4b8f 100644
> --- a/include/block/block_int.h
> +++ b/include/block/block_int.h
> @@ -40,23 +40,24 @@
>  #define BLOCK_FLAG_ENCRYPT          1
>  #define BLOCK_FLAG_LAZY_REFCOUNTS   8
>  
> -#define BLOCK_OPT_SIZE              "size"
> -#define BLOCK_OPT_ENCRYPT           "encryption"
> -#define BLOCK_OPT_COMPAT6           "compat6"
> -#define BLOCK_OPT_HWVERSION         "hwversion"
> -#define BLOCK_OPT_BACKING_FILE      "backing_file"
> -#define BLOCK_OPT_BACKING_FMT       "backing_fmt"
> -#define BLOCK_OPT_CLUSTER_SIZE      "cluster_size"
> -#define BLOCK_OPT_TABLE_SIZE        "table_size"
> -#define BLOCK_OPT_PREALLOC          "preallocation"
> -#define BLOCK_OPT_SUBFMT            "subformat"
> -#define BLOCK_OPT_COMPAT_LEVEL      "compat"
> -#define BLOCK_OPT_LAZY_REFCOUNTS    "lazy_refcounts"
> -#define BLOCK_OPT_ADAPTER_TYPE      "adapter_type"
> -#define BLOCK_OPT_REDUNDANCY        "redundancy"
> -#define BLOCK_OPT_NOCOW             "nocow"
> -#define BLOCK_OPT_OBJECT_SIZE       "object_size"
> -#define BLOCK_OPT_REFCOUNT_BITS     "refcount_bits"
> +#define BLOCK_OPT_SIZE                  "size"
> +#define BLOCK_OPT_ENCRYPT               "encryption"
> +#define BLOCK_OPT_COMPAT6               "compat6"
> +#define BLOCK_OPT_HWVERSION             "hwversion"
> +#define BLOCK_OPT_BACKING_FILE          "backing_file"
> +#define BLOCK_OPT_BACKING_FMT           "backing_fmt"
> +#define BLOCK_OPT_CLUSTER_SIZE          "cluster_size"
> +#define BLOCK_OPT_TABLE_SIZE            "table_size"
> +#define BLOCK_OPT_PREALLOC              "preallocation"
> +#define BLOCK_OPT_SUBFMT                "subformat"
> +#define BLOCK_OPT_COMPAT_LEVEL          "compat"
> +#define BLOCK_OPT_LAZY_REFCOUNTS        "lazy_refcounts"
> +#define BLOCK_OPT_ADAPTER_TYPE          "adapter_type"
> +#define BLOCK_OPT_REDUNDANCY            "redundancy"
> +#define BLOCK_OPT_NOCOW                 "nocow"
> +#define BLOCK_OPT_OBJECT_SIZE           "object_size"
> +#define BLOCK_OPT_REFCOUNT_BITS         "refcount_bits"
> +#define BLOCK_OPT_COMPRESSION_ALGORITHM "compression_algorithm"
>  
>  #define BLOCK_PROBE_BUF_SIZE        512
>  
> diff --git a/qemu-img.texi b/qemu-img.texi
> index 5b925ec..c0d1bec 100644
> --- a/qemu-img.texi
> +++ b/qemu-img.texi
> @@ -621,6 +621,16 @@ file which is COW and has data blocks already, it couldn't be changed to NOCOW
>  by setting @code{nocow=on}. One can issue @code{lsattr filename} to check if
>  the NOCOW flag is set or not (Capital 'C' is NOCOW flag).
>  
> +@item compression_algorithm
> +Defines which compression algorithm is should be used for compressed clusters.
> +The following options are available if support for the respective libraries
> +has been enabled at compile time:
> +
> +   zlib            Uses standard zlib compression (default)
> +
> +The compression algorithm can only be defined at image create time and cannot
> +be changed later.
> +
>  @end table
>  
>  @item Other
diff mbox

Patch

diff --git a/block/qcow2.c b/block/qcow2.c
index 2f94f03..893b145 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -60,9 +60,11 @@  typedef struct {
     uint32_t len;
 } QEMU_PACKED QCowExtension;
 
-#define  QCOW2_EXT_MAGIC_END 0
-#define  QCOW2_EXT_MAGIC_BACKING_FORMAT 0xE2792ACA
-#define  QCOW2_EXT_MAGIC_FEATURE_TABLE 0x6803f857
+#define QCOW2_EXT_MAGIC_END                   0
+#define QCOW2_EXT_MAGIC_BACKING_FORMAT        0xE2792ACA
+#define QCOW2_EXT_MAGIC_FEATURE_TABLE         0x6803f857
+#define QCOW2_EXT_MAGIC_COMPRESSION_ALGORITHM 0xc0318300
+/* 0xc03183xx reserved for further use of compression algorithm parameters */
 
 static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename)
 {
@@ -76,6 +78,15 @@  static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename)
         return 0;
 }
 
+static uint32_t is_compression_algorithm_supported(char *algorithm)
+{
+    if (!algorithm[0] || !strcmp(algorithm, "zlib")) {
+        /* no algorithm means the old default of zlib compression
+         * with 12 window bits */
+        return QCOW2_COMPRESSION_ZLIB;
+    }
+    return 0;
+}
 
 /* 
  * read qcow2 extension and fill bs
@@ -148,6 +159,34 @@  static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
 #endif
             break;
 
+        case QCOW2_EXT_MAGIC_COMPRESSION_ALGORITHM:
+            if (ext.len >= sizeof(s->compression_algorithm)) {
+                error_setg(errp, "ERROR: ext_compression_algorithm: len=%"
+                           PRIu32 " too large (>=%zu)", ext.len,
+                           sizeof(s->compression_algorithm));
+                return 2;
+            }
+            ret = bdrv_pread(bs->file, offset, s->compression_algorithm,
+                             ext.len);
+            if (ret < 0) {
+                error_setg_errno(errp, -ret, "ERROR: ext_compression_algorithm:"
+                                 " Could not read algorithm name");
+                return 3;
+            }
+            s->compression_algorithm[ext.len] = '\0';
+            s->compression_algorithm_id =
+                is_compression_algorithm_supported(s->compression_algorithm);
+            if (!s->compression_algorithm_id) {
+                error_setg(errp, "ERROR: compression algorithm '%s' is "
+                           " unsupported", s->compression_algorithm);
+                return 4;
+            }
+#ifdef DEBUG_EXT
+            printf("Qcow2: Got compression algorithm %s\n",
+                   s->compression_algorithm);
+#endif
+            break;
+
         case QCOW2_EXT_MAGIC_FEATURE_TABLE:
             if (p_feature_table != NULL) {
                 void* feature_table = g_malloc0(ext.len + 2 * sizeof(Qcow2Feature));
@@ -1104,6 +1143,7 @@  static int qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
 
     s->cluster_cache_offset = -1;
     s->flags = flags;
+    s->compression_algorithm_id = QCOW2_COMPRESSION_ZLIB;
 
     ret = qcow2_refcount_init(bs);
     if (ret != 0) {
@@ -1981,6 +2021,21 @@  int qcow2_update_header(BlockDriverState *bs)
         buflen -= ret;
     }
 
+    /* Compression Algorithm header extension */
+    if (s->compression_algorithm[0]) {
+        ret = header_ext_add(buf, QCOW2_EXT_MAGIC_COMPRESSION_ALGORITHM,
+                             s->compression_algorithm,
+                             strlen(s->compression_algorithm),
+                             buflen);
+        if (ret < 0) {
+            goto fail;
+        }
+        buf += ret;
+        buflen -= ret;
+        header->incompatible_features |=
+            cpu_to_be64(QCOW2_INCOMPAT_COMPRESSION);
+    }
+
     /* Feature table */
     if (s->qcow_version >= 3) {
         Qcow2Feature features[] = {
@@ -1995,6 +2050,11 @@  int qcow2_update_header(BlockDriverState *bs)
                 .name = "corrupt bit",
             },
             {
+                .type = QCOW2_FEAT_TYPE_INCOMPATIBLE,
+                .bit  = QCOW2_INCOMPAT_COMPRESSION_BITNR,
+                .name = "compression algorithm",
+            },
+            {
                 .type = QCOW2_FEAT_TYPE_COMPATIBLE,
                 .bit  = QCOW2_COMPAT_LAZY_REFCOUNTS_BITNR,
                 .name = "lazy refcounts",
@@ -2144,7 +2204,7 @@  static int qcow2_create2(const char *filename, int64_t total_size,
                          const char *backing_file, const char *backing_format,
                          int flags, size_t cluster_size, PreallocMode prealloc,
                          QemuOpts *opts, int version, int refcount_order,
-                         Error **errp)
+                         char *compression_algorithm, Error **errp)
 {
     int cluster_bits;
     QDict *options;
@@ -2332,6 +2392,12 @@  static int qcow2_create2(const char *filename, int64_t total_size,
         abort();
     }
 
+    if (compression_algorithm[0]) {
+        BDRVQcow2State *s = blk_bs(blk)->opaque;
+        memcpy(s->compression_algorithm, compression_algorithm,
+               strlen(compression_algorithm));
+    }
+
     /* Create a full header (including things like feature table) */
     ret = qcow2_update_header(blk_bs(blk));
     if (ret < 0) {
@@ -2395,6 +2461,7 @@  static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
     char *backing_file = NULL;
     char *backing_fmt = NULL;
     char *buf = NULL;
+    char *compression_algorithm = NULL;
     uint64_t size = 0;
     int flags = 0;
     size_t cluster_size = DEFAULT_CLUSTER_SIZE;
@@ -2475,15 +2542,25 @@  static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
 
     refcount_order = ctz32(refcount_bits);
 
+    compression_algorithm = qemu_opt_get_del(opts,
+                                             BLOCK_OPT_COMPRESSION_ALGORITHM);
+    if (!is_compression_algorithm_supported(compression_algorithm)) {
+        error_setg(errp, "Compression algorithm '%s' is not supported",
+                   compression_algorithm);
+        ret = -EINVAL;
+        goto finish;
+    }
+
     ret = qcow2_create2(filename, size, backing_file, backing_fmt, flags,
                         cluster_size, prealloc, opts, version, refcount_order,
-                        &local_err);
+                        compression_algorithm, &local_err);
     error_propagate(errp, local_err);
 
 finish:
     g_free(backing_file);
     g_free(backing_fmt);
     g_free(buf);
+    g_free(compression_algorithm);
     return ret;
 }
 
@@ -3458,6 +3535,12 @@  static QemuOptsList qcow2_create_opts = {
             .help = "Width of a reference count entry in bits",
             .def_value_str = "16"
         },
+        {
+            .name = BLOCK_OPT_COMPRESSION_ALGORITHM,
+            .type = QEMU_OPT_STRING,
+            .help = "Compression algorithm used for compressed clusters",
+            .def_value_str = ""
+        },
         { /* end of list */ }
     }
 };
diff --git a/block/qcow2.h b/block/qcow2.h
index 87b15eb..1c9ba06 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -171,6 +171,10 @@  typedef struct Qcow2UnknownHeaderExtension {
 } Qcow2UnknownHeaderExtension;
 
 enum {
+    QCOW2_COMPRESSION_ZLIB          = 0xC0318301,
+};
+
+enum {
     QCOW2_FEAT_TYPE_INCOMPATIBLE    = 0,
     QCOW2_FEAT_TYPE_COMPATIBLE      = 1,
     QCOW2_FEAT_TYPE_AUTOCLEAR       = 2,
@@ -178,13 +182,16 @@  enum {
 
 /* Incompatible feature bits */
 enum {
-    QCOW2_INCOMPAT_DIRTY_BITNR   = 0,
-    QCOW2_INCOMPAT_CORRUPT_BITNR = 1,
-    QCOW2_INCOMPAT_DIRTY         = 1 << QCOW2_INCOMPAT_DIRTY_BITNR,
-    QCOW2_INCOMPAT_CORRUPT       = 1 << QCOW2_INCOMPAT_CORRUPT_BITNR,
+    QCOW2_INCOMPAT_DIRTY_BITNR        = 0,
+    QCOW2_INCOMPAT_CORRUPT_BITNR      = 1,
+    QCOW2_INCOMPAT_COMPRESSION_BITNR  = 2,
+    QCOW2_INCOMPAT_DIRTY              = 1 << QCOW2_INCOMPAT_DIRTY_BITNR,
+    QCOW2_INCOMPAT_CORRUPT            = 1 << QCOW2_INCOMPAT_CORRUPT_BITNR,
+    QCOW2_INCOMPAT_COMPRESSION        = 1 << QCOW2_INCOMPAT_COMPRESSION_BITNR,
 
     QCOW2_INCOMPAT_MASK          = QCOW2_INCOMPAT_DIRTY
-                                 | QCOW2_INCOMPAT_CORRUPT,
+                                 | QCOW2_INCOMPAT_CORRUPT
+                                 | QCOW2_INCOMPAT_COMPRESSION,
 };
 
 /* Compatible feature bits */
@@ -294,6 +301,9 @@  typedef struct BDRVQcow2State {
      * override) */
     char *image_backing_file;
     char *image_backing_format;
+
+    char compression_algorithm[16];
+    uint32_t compression_algorithm_id;
 } BDRVQcow2State;
 
 typedef struct Qcow2COWRegion {
diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt
index 80cdfd0..1f165d6 100644
--- a/docs/interop/qcow2.txt
+++ b/docs/interop/qcow2.txt
@@ -85,7 +85,11 @@  in the description of a field.
                                 be written to (unless for regaining
                                 consistency).
 
-                    Bits 2-63:  Reserved (set to 0)
+                    Bit 2:      Compress algorithm bit.  If this bit is set then
+                                the compress algorithm extension must be parsed
+                                and checked for compatiblity.
+
+                    Bits 3-63:  Reserved (set to 0)
 
          80 -  87:  compatible_features
                     Bitmask of compatible features. An implementation can
@@ -135,6 +139,8 @@  be stored. Each extension has a structure like the following:
                         0xE2792ACA - Backing file format name
                         0x6803f857 - Feature name table
                         0x23852875 - Bitmaps extension
+                        0xC0318300 - Compression Algorithm
+                        0xC03183xx - Reserved for compression algorithm params
                         other      - Unknown header extension, can be safely
                                      ignored
 
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 15fa602..03a4b8f 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -40,23 +40,24 @@ 
 #define BLOCK_FLAG_ENCRYPT          1
 #define BLOCK_FLAG_LAZY_REFCOUNTS   8
 
-#define BLOCK_OPT_SIZE              "size"
-#define BLOCK_OPT_ENCRYPT           "encryption"
-#define BLOCK_OPT_COMPAT6           "compat6"
-#define BLOCK_OPT_HWVERSION         "hwversion"
-#define BLOCK_OPT_BACKING_FILE      "backing_file"
-#define BLOCK_OPT_BACKING_FMT       "backing_fmt"
-#define BLOCK_OPT_CLUSTER_SIZE      "cluster_size"
-#define BLOCK_OPT_TABLE_SIZE        "table_size"
-#define BLOCK_OPT_PREALLOC          "preallocation"
-#define BLOCK_OPT_SUBFMT            "subformat"
-#define BLOCK_OPT_COMPAT_LEVEL      "compat"
-#define BLOCK_OPT_LAZY_REFCOUNTS    "lazy_refcounts"
-#define BLOCK_OPT_ADAPTER_TYPE      "adapter_type"
-#define BLOCK_OPT_REDUNDANCY        "redundancy"
-#define BLOCK_OPT_NOCOW             "nocow"
-#define BLOCK_OPT_OBJECT_SIZE       "object_size"
-#define BLOCK_OPT_REFCOUNT_BITS     "refcount_bits"
+#define BLOCK_OPT_SIZE                  "size"
+#define BLOCK_OPT_ENCRYPT               "encryption"
+#define BLOCK_OPT_COMPAT6               "compat6"
+#define BLOCK_OPT_HWVERSION             "hwversion"
+#define BLOCK_OPT_BACKING_FILE          "backing_file"
+#define BLOCK_OPT_BACKING_FMT           "backing_fmt"
+#define BLOCK_OPT_CLUSTER_SIZE          "cluster_size"
+#define BLOCK_OPT_TABLE_SIZE            "table_size"
+#define BLOCK_OPT_PREALLOC              "preallocation"
+#define BLOCK_OPT_SUBFMT                "subformat"
+#define BLOCK_OPT_COMPAT_LEVEL          "compat"
+#define BLOCK_OPT_LAZY_REFCOUNTS        "lazy_refcounts"
+#define BLOCK_OPT_ADAPTER_TYPE          "adapter_type"
+#define BLOCK_OPT_REDUNDANCY            "redundancy"
+#define BLOCK_OPT_NOCOW                 "nocow"
+#define BLOCK_OPT_OBJECT_SIZE           "object_size"
+#define BLOCK_OPT_REFCOUNT_BITS         "refcount_bits"
+#define BLOCK_OPT_COMPRESSION_ALGORITHM "compression_algorithm"
 
 #define BLOCK_PROBE_BUF_SIZE        512
 
diff --git a/qemu-img.texi b/qemu-img.texi
index 5b925ec..c0d1bec 100644
--- a/qemu-img.texi
+++ b/qemu-img.texi
@@ -621,6 +621,16 @@  file which is COW and has data blocks already, it couldn't be changed to NOCOW
 by setting @code{nocow=on}. One can issue @code{lsattr filename} to check if
 the NOCOW flag is set or not (Capital 'C' is NOCOW flag).
 
+@item compression_algorithm
+Defines which compression algorithm is should be used for compressed clusters.
+The following options are available if support for the respective libraries
+has been enabled at compile time:
+
+   zlib            Uses standard zlib compression (default)
+
+The compression algorithm can only be defined at image create time and cannot
+be changed later.
+
 @end table
 
 @item Other