Commit 2714f13d authored by Vladimir Sementsov-Ogievskiy's avatar Vladimir Sementsov-Ogievskiy Committed by Kevin Wolf
Browse files

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: default avatarVladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Signed-off-by: default avatarKevin Wolf <kwolf@redhat.com>
parent 88481329
Loading
Loading
Loading
Loading
+51 −27
Original line number Diff line number Diff line
@@ -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) {