qcow2: refactor data compression

Make a separate function for compression to be parallelized later.
 - use .avail_out field instead of .next_out to calculate size of
   compressed data. It looks more natural and it allows to keep dest to
   be void pointer
 - set avail_out to be at least one byte less than input, to be sure
   avoid inefficient compression earlier

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
Vladimir Sementsov-Ogievskiy 2018-06-20 17:48:36 +03:00 committed by Kevin Wolf
parent 88481329c0
commit 2714f13d69

View file

@ -23,11 +23,14 @@
*/
#include "qemu/osdep.h"
#define ZLIB_CONST
#include <zlib.h>
#include "block/block_int.h"
#include "block/qdict.h"
#include "sysemu/block-backend.h"
#include "qemu/module.h"
#include <zlib.h>
#include "qcow2.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
@ -3650,6 +3653,48 @@ fail:
return ret;
}
/*
* qcow2_compress()
*
* @dest - destination buffer, at least of @size-1 bytes
* @src - source buffer, @size bytes
*
* Returns: compressed size on success
* -1 if compression is inefficient
* -2 on any other error
*/
static ssize_t qcow2_compress(void *dest, const void *src, size_t size)
{
ssize_t ret;
z_stream strm;
/* best compression, small window, no zlib header */
memset(&strm, 0, sizeof(strm));
ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
-12, 9, Z_DEFAULT_STRATEGY);
if (ret != 0) {
return -2;
}
/* strm.next_in is not const in old zlib versions, such as those used on
* OpenBSD/NetBSD, so cast the const away */
strm.avail_in = size;
strm.next_in = (void *) src;
strm.avail_out = size - 1;
strm.next_out = dest;
ret = deflate(&strm, Z_FINISH);
if (ret == Z_STREAM_END) {
ret = size - 1 - strm.avail_out;
} else {
ret = (ret == Z_OK ? -1 : -2);
}
deflateEnd(&strm);
return ret;
}
/* XXX: put compressed sectors first, then all the cluster aligned
tables to avoid losing bytes in alignment */
static coroutine_fn int
@ -3659,8 +3704,8 @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
BDRVQcow2State *s = bs->opaque;
QEMUIOVector hd_qiov;
struct iovec iov;
z_stream strm;
int ret, out_len;
int ret;
size_t out_len;
uint8_t *buf, *out_buf;
int64_t cluster_offset;
@ -3694,32 +3739,11 @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
out_buf = g_malloc(s->cluster_size);
/* best compression, small window, no zlib header */
memset(&strm, 0, sizeof(strm));
ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION,
Z_DEFLATED, -12,
9, Z_DEFAULT_STRATEGY);
if (ret != 0) {
out_len = qcow2_compress(out_buf, buf, s->cluster_size);
if (out_len == -2) {
ret = -EINVAL;
goto fail;
}
strm.avail_in = s->cluster_size;
strm.next_in = (uint8_t *)buf;
strm.avail_out = s->cluster_size;
strm.next_out = out_buf;
ret = deflate(&strm, Z_FINISH);
if (ret != Z_STREAM_END && ret != Z_OK) {
deflateEnd(&strm);
ret = -EINVAL;
goto fail;
}
out_len = strm.next_out - out_buf;
deflateEnd(&strm);
if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
} else if (out_len == -1) {
/* could not compress: write normal cluster */
ret = qcow2_co_pwritev(bs, offset, bytes, qiov, 0);
if (ret < 0) {