Message ID | 20190704130949.14017-4-dplotnikov@virtuozzo.com |
---|---|
State | New |
Headers | show |
Series | add zstd cluster compression | expand |
Denis Plotnikov <dplotnikov@virtuozzo.com> writes: > zstd significantly reduces cluster compression time. > It provides better compression performance maintaining > the same level of compression ratio in comparison with > zlib, which, by the moment, has been the only compression > method available. > > The performance test results: > Test compresses and decompresses qemu qcow2 image with just > installed rhel-7.6 guest. > Image cluster size: 64K. Image on disk size: 2.2G > > The test was conducted with brd disk to reduce the influence > of disk subsystem to the test results. > The results is given in seconds. > > compress cmd: > time ./qemu-img convert -O qcow2 -c -o compression_type=[zlib|zstd] > src.img [zlib|zstd]_compressed.img > decompress cmd > time ./qemu-img convert -O qcow2 > [zlib|zstd]_compressed.img uncompressed.img > > compression decompression > zlib zstd zlib zstd > ------------------------------------------------------------ > real 65.5 16.3 (-75 %) 1.9 1.6 (-16 %) > user 65.0 15.8 5.3 2.5 > sys 3.3 0.2 2.0 2.0 > > Both ZLIB and ZSTD gave the same compression ratio: 1.57 > compressed image size in both cases: 1.4G > > Signed-off-by: Denis Plotnikov <dplotnikov@virtuozzo.com> [...] > diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt > index 7cf068f814..4344e858cb 100644 > --- a/docs/interop/qcow2.txt > +++ b/docs/interop/qcow2.txt > @@ -538,6 +538,9 @@ Compressed Clusters Descriptor (x = 62 - (cluster_bits - 8)): > Another compressed cluster may map to the tail of the final > sector used by this compressed cluster. > > + The layout of the compressed data depends on the compression > + type used for the image (see compressed cluster layout). > + > If a cluster is unallocated, read requests shall read the data from the backing > file (except if bit 0 in the Standard Cluster Descriptor is set). If there is > no backing file or the backing file is smaller than the image, they shall read > @@ -790,3 +793,19 @@ In the image file the 'enabled' state is reflected by the 'auto' flag. If this > flag is set, the software must consider the bitmap as 'enabled' and start > tracking virtual disk changes to this bitmap from the first write to the > virtual disk. If this flag is not set then the bitmap is disabled. > + > +=== Compressed cluster layout === > + > +The compressed cluster data may have a different layout depending on the > +compression type used for the image, and store specific data for the particular > +compression type. > + > +Compressed data layout for the available compression types: > +(x = data_space_length - 1) > + > + zlib: > + Byte 0 - x: the compressed data content > + all the space provided used for compressed data > + zstd: > + Byte 0 - 3: the length of compressed data > + 4 - x: the compressed data content Adding <http://zlib.net/> and <http://github.com/facebook/zstd> here as well wouldn't hurt, would it? > diff --git a/qapi/block-core.json b/qapi/block-core.json > index 835dd3c37f..2021e03a84 100644 > --- a/qapi/block-core.json > +++ b/qapi/block-core.json > @@ -4215,11 +4215,12 @@ > # Compression type used in qcow2 image file > # > # @zlib: zlib compression, see <http://zlib.net/> > +# @zstd: zstd compression, see <http://github.com/facebook/zstd> > # > # Since: 4.1 > ## > { 'enum': 'Qcow2CompressionType', > - 'data': [ 'zlib' ] } > + 'data': [ 'zlib', { 'name': 'zstd', 'if': 'defined(CONFIG_ZSTD)' } ] } > > ## > # @BlockdevCreateOptionsQcow2: QAPI schema Acked-by: Markus Armbruster <armbru@redhat.com>
On Jul 9 2019, at 9:18 am, Markus Armbruster <armbru@redhat.com> wrote: Denis Plotnikov <dplotnikov@virtuozzo.com> writes: zstd significantly reduces cluster compression time. It provides better compression performance maintaining the same level of compression ratio in comparison with zlib, which, by the moment, has been the only compression method available. The performance test results: Test compresses and decompresses qemu qcow2 image with just installed rhel-7.6 guest. Image cluster size: 64K. Image on disk size: 2.2G The test was conducted with brd disk to reduce the influence of disk subsystem to the test results. The results is given in seconds. compress cmd: time ./qemu-img convert -O qcow2 -c -o compression_type=[zlib|zstd] src.img [zlib|zstd]_compressed.img decompress cmd time ./qemu-img convert -O qcow2 [zlib|zstd]_compressed.img uncompressed.img compression decompression zlib zstd zlib zstd ------------------------------------------------------------ real 65.5 16.3 (-75 %) 1.9 1.6 (-16 %) user 65.0 15.8 5.3 2.5 sys 3.3 0.2 2.0 2.0 Both ZLIB and ZSTD gave the same compression ratio: 1.57 compressed image size in both cases: 1.4G Signed-off-by: Denis Plotnikov <dplotnikov@virtuozzo.com> [...] diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt index 7cf068f814..4344e858cb 100644 --- a/docs/interop/qcow2.txt +++ b/docs/interop/qcow2.txt @@ -538,6 +538,9 @@ Compressed Clusters Descriptor (x = 62 - (cluster_bits - 8)): Another compressed cluster may map to the tail of the final sector used by this compressed cluster. + The layout of the compressed data depends on the compression + type used for the image (see compressed cluster layout). + If a cluster is unallocated, read requests shall read the data from the backing file (except if bit 0 in the Standard Cluster Descriptor is set). If there is no backing file or the backing file is smaller than the image, they shall read @@ -790,3 +793,19 @@ In the image file the 'enabled' state is reflected by the 'auto' flag. If this flag is set, the software must consider the bitmap as 'enabled' and start tracking virtual disk changes to this bitmap from the first write to the virtual disk. If this flag is not set then the bitmap is disabled. + +=== Compressed cluster layout === + +The compressed cluster data may have a different layout depending on the +compression type used for the image, and store specific data for the particular +compression type. + +Compressed data layout for the available compression types: +(x = data_space_length - 1) + + zlib: + Byte 0 - x: the compressed data content + all the space provided used for compressed data + zstd: + Byte 0 - 3: the length of compressed data + 4 - x: the compressed data content Adding <http://zlib.net/> and <http://github.com/facebook/zstd> here as well wouldn't hurt, would it? ok diff --git a/qapi/block-core.json b/qapi/block-core.json index 835dd3c37f..2021e03a84 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -4215,11 +4215,12 @@ # Compression type used in qcow2 image file # # @zlib: zlib compression, see <http://zlib.net/> +# @zstd: zstd compression, see <http://github.com/facebook/zstd> # # Since: 4.1 ## { 'enum': 'Qcow2CompressionType', - 'data': [ 'zlib' ] } + 'data': [ 'zlib', { 'name': 'zstd', 'if': 'defined(CONFIG_ZSTD)' } ] } ## # @BlockdevCreateOptionsQcow2: QAPI schema Acked-by: Markus Armbruster <armbru@redhat.com>
On 7/4/19 8:09 AM, Denis Plotnikov wrote: > zstd significantly reduces cluster compression time. > It provides better compression performance maintaining > the same level of compression ratio in comparison with > zlib, which, by the moment, has been the only compression s/by/at/ > method available. > > The performance test results: > Test compresses and decompresses qemu qcow2 image with just > installed rhel-7.6 guest. > Image cluster size: 64K. Image on disk size: 2.2G > > The test was conducted with brd disk to reduce the influence > of disk subsystem to the test results. > The results is given in seconds. > > compress cmd: > time ./qemu-img convert -O qcow2 -c -o compression_type=[zlib|zstd] > src.img [zlib|zstd]_compressed.img > decompress cmd > time ./qemu-img convert -O qcow2 > [zlib|zstd]_compressed.img uncompressed.img > > compression decompression > zlib zstd zlib zstd > ------------------------------------------------------------ > real 65.5 16.3 (-75 %) 1.9 1.6 (-16 %) > user 65.0 15.8 5.3 2.5 > sys 3.3 0.2 2.0 2.0 > > Both ZLIB and ZSTD gave the same compression ratio: 1.57 > compressed image size in both cases: 1.4G > Nice numbers. > +++ b/docs/interop/qcow2.txt > @@ -538,6 +538,9 @@ Compressed Clusters Descriptor (x = 62 - (cluster_bits - 8)): > Another compressed cluster may map to the tail of the final > sector used by this compressed cluster. > > + The layout of the compressed data depends on the compression > + type used for the image (see compressed cluster layout). > + > If a cluster is unallocated, read requests shall read the data from the backing > file (except if bit 0 in the Standard Cluster Descriptor is set). If there is > no backing file or the backing file is smaller than the image, they shall read > @@ -790,3 +793,19 @@ In the image file the 'enabled' state is reflected by the 'auto' flag. If this > flag is set, the software must consider the bitmap as 'enabled' and start > tracking virtual disk changes to this bitmap from the first write to the > virtual disk. If this flag is not set then the bitmap is disabled. > + > +=== Compressed cluster layout === > + > +The compressed cluster data may have a different layout depending on the > +compression type used for the image, and store specific data for the particular > +compression type. > + > +Compressed data layout for the available compression types: > +(x = data_space_length - 1) > + > + zlib: > + Byte 0 - x: the compressed data content > + all the space provided used for compressed data > + zstd: > + Byte 0 - 3: the length of compressed data > + 4 - x: the compressed data content Missing a change to the header description at bytes 104-107 calling out '1' as meaning zstd (it only calls out '0' or absent as meaning zlib).
On 04.07.19 15:09, Denis Plotnikov wrote: > zstd significantly reduces cluster compression time. > It provides better compression performance maintaining > the same level of compression ratio in comparison with > zlib, which, by the moment, has been the only compression > method available. > > The performance test results: > Test compresses and decompresses qemu qcow2 image with just > installed rhel-7.6 guest. > Image cluster size: 64K. Image on disk size: 2.2G > > The test was conducted with brd disk to reduce the influence > of disk subsystem to the test results. > The results is given in seconds. > > compress cmd: > time ./qemu-img convert -O qcow2 -c -o compression_type=[zlib|zstd] > src.img [zlib|zstd]_compressed.img > decompress cmd > time ./qemu-img convert -O qcow2 > [zlib|zstd]_compressed.img uncompressed.img > > compression decompression > zlib zstd zlib zstd > ------------------------------------------------------------ > real 65.5 16.3 (-75 %) 1.9 1.6 (-16 %) > user 65.0 15.8 5.3 2.5 > sys 3.3 0.2 2.0 2.0 > > Both ZLIB and ZSTD gave the same compression ratio: 1.57 > compressed image size in both cases: 1.4G > > Signed-off-by: Denis Plotnikov <dplotnikov@virtuozzo.com> > --- > block/qcow2.c | 99 ++++++++++++++++++++++++++++++++++++++++++ > configure | 32 ++++++++++++++ > docs/interop/qcow2.txt | 19 ++++++++ > qapi/block-core.json | 3 +- > 4 files changed, 152 insertions(+), 1 deletion(-) > > diff --git a/block/qcow2.c b/block/qcow2.c > index a107f76e98..252eba636f 100644 > --- a/block/qcow2.c > +++ b/block/qcow2.c [...] > @@ -4092,6 +4103,84 @@ static ssize_t qcow2_zlib_decompress(void *dest, size_t dest_size, > return ret; > } > > +#ifdef CONFIG_ZSTD > +/* > + * qcow2_zstd_compress() > + * > + * Compress @src_size bytes of data using zstd compression method > + * > + * @dest - destination buffer, @dest_size bytes > + * @src - source buffer, @src_size bytes > + * > + * Returns: compressed size on success > + * a negative error code on fail > + */ > + > +static ssize_t qcow2_zstd_compress(void *dest, size_t dest_size, > + const void *src, size_t src_size) > +{ > + ssize_t ret; > + uint32_t *c_size = dest; > + /* steal some bytes to store compressed chunk size */ > + char *d_buf = ((char *) dest) + sizeof(*c_size); > + > + if (dest_size < sizeof(*c_size)) { > + return -ENOMEM; > + } > + > + dest_size -= sizeof(*c_size); > + > + ret = ZSTD_compress(d_buf, dest_size, src, src_size, 5); > + > + if (ZSTD_isError(ret)) { > + if (ret == ZSTD_error_dstSize_tooSmall) { s/ret/ZSTD_getErrorCode(ret)/ > + return -ENOMEM; > + } else { > + return -EIO; > + } > + } > + > + /* store the compressed chunk size in the very beginning of the buffer */ > + *c_size = ret; I think this should be stored in big endian. > + > + return ret + sizeof(ret); s/sizeof(ret)/sizeof(*c_size)/ > +} > + > +/* > + * qcow2_zstd_decompress() > + * > + * Decompress some data (not more than @src_size bytes) to produce exactly > + * @dest_size bytes using zstd compression method > + * > + * @dest - destination buffer, @dest_size bytes > + * @src - source buffer, @src_size bytes > + * > + * Returns: 0 on success > + * -EIO on fail > + */ > + > +static ssize_t qcow2_zstd_decompress(void *dest, size_t dest_size, > + const void *src, size_t src_size) > +{ > + ssize_t ret; > + /* > + * zstd decompress wants to know the exact lenght of the data *length > + * for that purpose, on the compression the length is stored in > + * the very beginning of the compressed buffer > + */ > + const uint32_t *s_size = src; > + const char *s_buf = ((char *) src) + sizeof(*s_size); If you want to be strict, s/(char *)/(const char *)/. > + > + ret = ZSTD_decompress(dest, dest_size, s_buf, *s_size); > + > + if (ZSTD_isError(ret)) { > + return -EIO; > + } > + > + return 0; > +} > +#endif > + > #define MAX_COMPRESS_THREADS 4 > > typedef ssize_t (*Qcow2CompressFunc)(void *dest, size_t dest_size, [...] > diff --git a/configure b/configure > index 1c563a7027..57a80e38e7 100755 > --- a/configure > +++ b/configure [...] > @@ -2374,6 +2380,29 @@ EOF > fi > fi > > +######################################### > +# zstd check > + > +if test "$zstd" != "no" ; then > + if $pkg_config --exists libzstd; then > + zstd_cflags=$($pkg_config --cflags libzstd) > + zstd_libs=$($pkg_config --libs libzstd) > + QEMU_CFLAGS="$zstd_cflags $QEMU_CFLAGS" > + LIBS="$zstd_libs $LIBS" > + else > + cat > $TMPC << EOF > +#include <zstd.h> > +int main(void) { ZSTD_versionNumber(); return 0; } > +EOF > + if compile_prog "" "-lzstd" ; then > + LIBS="$LIBS -lzstd" > + else > + error_exit "zstd check failed" \ > + "Make sure to have the zstd libs and headers installed." (1) When the user doesn’t specify anything and doesn’t have zstd installed, this will throw an error. That shouldn’t be, it should just set zstd to "no", unless zstd was explicitly "yes". (2) All other places use feature_not_found. I think this should, too. > + fi > + fi You must set zstd to "yes" if it was found. (So it is used when available, even if the user did not explicitly pass --enable-zstd.) > +fi > + > ########################################## > # libseccomp check > > @@ -7253,6 +7282,9 @@ fi > if test "$sheepdog" = "yes" ; then > echo "CONFIG_SHEEPDOG=y" >> $config_host_mak > fi > +if test "$zstd" = "yes" ; then > + echo "CONFIG_ZSTD=y" >> $config_host_mak > +fi > > if test "$tcg_interpreter" = "yes"; then > QEMU_INCLUDES="-iquote \$(SRC_PATH)/tcg/tci $QEMU_INCLUDES" The status should be printed in the list of what features are enabled. Max
diff --git a/block/qcow2.c b/block/qcow2.c index a107f76e98..252eba636f 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -27,6 +27,11 @@ #define ZLIB_CONST #include <zlib.h> +#ifdef CONFIG_ZSTD +#include <zstd.h> +#include <zstd_errors.h> +#endif + #include "block/block_int.h" #include "block/qdict.h" #include "sysemu/block-backend.h" @@ -1206,6 +1211,9 @@ static int check_compression_type(BDRVQcow2State *s, Error **errp) { switch (s->compression_type) { case QCOW2_COMPRESSION_TYPE_ZLIB: +#ifdef CONFIG_ZSTD + case QCOW2_COMPRESSION_TYPE_ZSTD: +#endif break; default: @@ -3200,6 +3208,9 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) switch(qcow2_opts->compression_type) { case QCOW2_COMPRESSION_TYPE_ZLIB: +#ifdef CONFIG_ZSTD + case QCOW2_COMPRESSION_TYPE_ZSTD: +#endif break; default: @@ -4092,6 +4103,84 @@ static ssize_t qcow2_zlib_decompress(void *dest, size_t dest_size, return ret; } +#ifdef CONFIG_ZSTD +/* + * qcow2_zstd_compress() + * + * Compress @src_size bytes of data using zstd compression method + * + * @dest - destination buffer, @dest_size bytes + * @src - source buffer, @src_size bytes + * + * Returns: compressed size on success + * a negative error code on fail + */ + +static ssize_t qcow2_zstd_compress(void *dest, size_t dest_size, + const void *src, size_t src_size) +{ + ssize_t ret; + uint32_t *c_size = dest; + /* steal some bytes to store compressed chunk size */ + char *d_buf = ((char *) dest) + sizeof(*c_size); + + if (dest_size < sizeof(*c_size)) { + return -ENOMEM; + } + + dest_size -= sizeof(*c_size); + + ret = ZSTD_compress(d_buf, dest_size, src, src_size, 5); + + if (ZSTD_isError(ret)) { + if (ret == ZSTD_error_dstSize_tooSmall) { + return -ENOMEM; + } else { + return -EIO; + } + } + + /* store the compressed chunk size in the very beginning of the buffer */ + *c_size = ret; + + return ret + sizeof(ret); +} + +/* + * qcow2_zstd_decompress() + * + * Decompress some data (not more than @src_size bytes) to produce exactly + * @dest_size bytes using zstd compression method + * + * @dest - destination buffer, @dest_size bytes + * @src - source buffer, @src_size bytes + * + * Returns: 0 on success + * -EIO on fail + */ + +static ssize_t qcow2_zstd_decompress(void *dest, size_t dest_size, + const void *src, size_t src_size) +{ + ssize_t ret; + /* + * zstd decompress wants to know the exact lenght of the data + * for that purpose, on the compression the length is stored in + * the very beginning of the compressed buffer + */ + const uint32_t *s_size = src; + const char *s_buf = ((char *) src) + sizeof(*s_size); + + ret = ZSTD_decompress(dest, dest_size, s_buf, *s_size); + + if (ZSTD_isError(ret)) { + return -EIO; + } + + return 0; +} +#endif + #define MAX_COMPRESS_THREADS 4 typedef ssize_t (*Qcow2CompressFunc)(void *dest, size_t dest_size, @@ -4180,6 +4269,11 @@ qcow2_co_compress(BlockDriverState *bs, void *dest, size_t dest_size, fn = qcow2_zlib_compress; break; +#ifdef CONFIG_ZSTD + case QCOW2_COMPRESSION_TYPE_ZSTD: + fn = qcow2_zstd_compress; + break; +#endif default: return -ENOTSUP; } @@ -4212,6 +4306,11 @@ qcow2_co_decompress(BlockDriverState *bs, void *dest, size_t dest_size, fn = qcow2_zlib_decompress; break; +#ifdef CONFIG_ZSTD + case QCOW2_COMPRESSION_TYPE_ZSTD: + fn = qcow2_zstd_decompress; + break; +#endif default: return -ENOTSUP; } diff --git a/configure b/configure index 1c563a7027..57a80e38e7 100755 --- a/configure +++ b/configure @@ -433,6 +433,7 @@ opengl_dmabuf="no" cpuid_h="no" avx2_opt="" zlib="yes" +zstd="" capstone="" lzo="" snappy="" @@ -1333,6 +1334,10 @@ for opt do ;; --disable-lzfse) lzfse="no" ;; + --enable-zstd) zstd="yes" + ;; + --disable-zstd) zstd="no" + ;; --enable-guest-agent) guest_agent="yes" ;; --disable-guest-agent) guest_agent="no" @@ -1788,6 +1793,7 @@ disabled with --disable-FEATURE, default is enabled if available: (for reading bzip2-compressed dmg images) lzfse support of lzfse compression library (for reading lzfse-compressed dmg images) + zstd support of zstd compression library seccomp seccomp support coroutine-pool coroutine freelist (better performance) glusterfs GlusterFS backend @@ -2374,6 +2380,29 @@ EOF fi fi +######################################### +# zstd check + +if test "$zstd" != "no" ; then + if $pkg_config --exists libzstd; then + zstd_cflags=$($pkg_config --cflags libzstd) + zstd_libs=$($pkg_config --libs libzstd) + QEMU_CFLAGS="$zstd_cflags $QEMU_CFLAGS" + LIBS="$zstd_libs $LIBS" + else + cat > $TMPC << EOF +#include <zstd.h> +int main(void) { ZSTD_versionNumber(); return 0; } +EOF + if compile_prog "" "-lzstd" ; then + LIBS="$LIBS -lzstd" + else + error_exit "zstd check failed" \ + "Make sure to have the zstd libs and headers installed." + fi + fi +fi + ########################################## # libseccomp check @@ -7253,6 +7282,9 @@ fi if test "$sheepdog" = "yes" ; then echo "CONFIG_SHEEPDOG=y" >> $config_host_mak fi +if test "$zstd" = "yes" ; then + echo "CONFIG_ZSTD=y" >> $config_host_mak +fi if test "$tcg_interpreter" = "yes"; then QEMU_INCLUDES="-iquote \$(SRC_PATH)/tcg/tci $QEMU_INCLUDES" diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt index 7cf068f814..4344e858cb 100644 --- a/docs/interop/qcow2.txt +++ b/docs/interop/qcow2.txt @@ -538,6 +538,9 @@ Compressed Clusters Descriptor (x = 62 - (cluster_bits - 8)): Another compressed cluster may map to the tail of the final sector used by this compressed cluster. + The layout of the compressed data depends on the compression + type used for the image (see compressed cluster layout). + If a cluster is unallocated, read requests shall read the data from the backing file (except if bit 0 in the Standard Cluster Descriptor is set). If there is no backing file or the backing file is smaller than the image, they shall read @@ -790,3 +793,19 @@ In the image file the 'enabled' state is reflected by the 'auto' flag. If this flag is set, the software must consider the bitmap as 'enabled' and start tracking virtual disk changes to this bitmap from the first write to the virtual disk. If this flag is not set then the bitmap is disabled. + +=== Compressed cluster layout === + +The compressed cluster data may have a different layout depending on the +compression type used for the image, and store specific data for the particular +compression type. + +Compressed data layout for the available compression types: +(x = data_space_length - 1) + + zlib: + Byte 0 - x: the compressed data content + all the space provided used for compressed data + zstd: + Byte 0 - 3: the length of compressed data + 4 - x: the compressed data content diff --git a/qapi/block-core.json b/qapi/block-core.json index 835dd3c37f..2021e03a84 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -4215,11 +4215,12 @@ # Compression type used in qcow2 image file # # @zlib: zlib compression, see <http://zlib.net/> +# @zstd: zstd compression, see <http://github.com/facebook/zstd> # # Since: 4.1 ## { 'enum': 'Qcow2CompressionType', - 'data': [ 'zlib' ] } + 'data': [ 'zlib', { 'name': 'zstd', 'if': 'defined(CONFIG_ZSTD)' } ] } ## # @BlockdevCreateOptionsQcow2:
zstd significantly reduces cluster compression time. It provides better compression performance maintaining the same level of compression ratio in comparison with zlib, which, by the moment, has been the only compression method available. The performance test results: Test compresses and decompresses qemu qcow2 image with just installed rhel-7.6 guest. Image cluster size: 64K. Image on disk size: 2.2G The test was conducted with brd disk to reduce the influence of disk subsystem to the test results. The results is given in seconds. compress cmd: time ./qemu-img convert -O qcow2 -c -o compression_type=[zlib|zstd] src.img [zlib|zstd]_compressed.img decompress cmd time ./qemu-img convert -O qcow2 [zlib|zstd]_compressed.img uncompressed.img compression decompression zlib zstd zlib zstd ------------------------------------------------------------ real 65.5 16.3 (-75 %) 1.9 1.6 (-16 %) user 65.0 15.8 5.3 2.5 sys 3.3 0.2 2.0 2.0 Both ZLIB and ZSTD gave the same compression ratio: 1.57 compressed image size in both cases: 1.4G Signed-off-by: Denis Plotnikov <dplotnikov@virtuozzo.com> --- block/qcow2.c | 99 ++++++++++++++++++++++++++++++++++++++++++ configure | 32 ++++++++++++++ docs/interop/qcow2.txt | 19 ++++++++ qapi/block-core.json | 3 +- 4 files changed, 152 insertions(+), 1 deletion(-)