@@ -24,6 +24,9 @@
#include "qemu/osdep.h"
#include <zlib.h>
+#ifdef CONFIG_LZO
+#include <lzo/lzo1x.h>
+#endif
#include "qapi/error.h"
#include "qemu-common.h"
@@ -1521,30 +1524,49 @@ again:
}
static int decompress_buffer(uint8_t *out_buf, int out_buf_size,
- const uint8_t *buf, int buf_size)
+ const uint8_t *buf, int buf_size,
+ uint32_t compression_algorithm_id)
{
z_stream strm1, *strm = &strm1;
- int ret, out_len;
-
- memset(strm, 0, sizeof(*strm));
-
- strm->next_in = (uint8_t *)buf;
- strm->avail_in = buf_size;
- strm->next_out = out_buf;
- strm->avail_out = out_buf_size;
-
- ret = inflateInit2(strm, -12);
- if (ret != Z_OK)
- return -1;
- ret = inflate(strm, Z_FINISH);
- out_len = strm->next_out - out_buf;
- if ((ret != Z_STREAM_END && ret != Z_BUF_ERROR) ||
- out_len != out_buf_size) {
+ int ret = 0, out_len;
+
+ switch (compression_algorithm_id) {
+ case QCOW2_COMPRESSION_ZLIB:
+ memset(strm, 0, sizeof(*strm));
+
+ strm->next_in = (uint8_t *)buf;
+ strm->avail_in = buf_size;
+ strm->next_out = out_buf;
+ strm->avail_out = out_buf_size;
+
+ ret = inflateInit2(strm, -12);
+ if (ret != Z_OK) {
+ return -1;
+ }
+ ret = inflate(strm, Z_FINISH);
+ out_len = strm->next_out - out_buf;
+ ret = -(ret != Z_STREAM_END);
inflateEnd(strm);
- return -1;
+ break;
+#ifdef CONFIG_LZO
+ case QCOW2_COMPRESSION_LZO:
+ out_len = out_buf_size;
+ ret = lzo1x_decompress_safe(buf, buf_size, out_buf,
+ (lzo_uint *) &out_len, NULL);
+ if (ret == LZO_E_INPUT_NOT_CONSUMED) {
+ /* We always read up to the next sector boundary. Thus
+ * buf_size may be larger than the original compressed size. */
+ ret = 0;
+ }
+ break;
+#endif
+ default:
+ abort(); /* should never reach this point */
}
- inflateEnd(strm);
- return 0;
+ if (out_len != out_buf_size) {
+ ret = -1;
+ }
+ return ret;
}
int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
@@ -1565,7 +1587,8 @@ int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
return ret;
}
if (decompress_buffer(s->cluster_cache, s->cluster_size,
- s->cluster_data + sector_offset, csize) < 0) {
+ s->cluster_data + sector_offset, csize,
+ s->compression_algorithm_id) < 0) {
return -EIO;
}
s->cluster_cache_offset = coffset;
@@ -26,6 +26,9 @@
#include "sysemu/block-backend.h"
#include "qemu/module.h"
#include <zlib.h>
+#ifdef CONFIG_LZO
+#include <lzo/lzo1x.h>
+#endif
#include "block/qcow2.h"
#include "qemu/error-report.h"
#include "qapi/qmp/qerror.h"
@@ -84,6 +87,10 @@ static uint32_t is_compression_algorithm_supported(char *algorithm)
/* no algorithm means the old default of zlib compression
* with 12 window bits */
return QCOW2_COMPRESSION_ZLIB;
+#ifdef CONFIG_LZO
+ } else if (!strcmp(algorithm, "lzo")) {
+ return QCOW2_COMPRESSION_LZO;
+#endif
}
return 0;
}
@@ -2715,8 +2722,8 @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
QEMUIOVector hd_qiov;
struct iovec iov;
z_stream strm;
- int ret, out_len;
- uint8_t *buf, *out_buf, *local_buf = NULL;
+ int ret, out_len = 0;
+ uint8_t *buf, *out_buf = NULL, *local_buf = NULL, *work_buf = NULL;
uint64_t cluster_offset;
if (bytes == 0) {
@@ -2741,34 +2748,50 @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
buf = qiov->iov[0].iov_base;
}
- out_buf = g_malloc(s->cluster_size);
+ switch (s->compression_algorithm_id) {
+ case QCOW2_COMPRESSION_ZLIB:
+ 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) {
- ret = -EINVAL;
- goto fail;
- }
+ /* 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) {
+ 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;
+ 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;
- 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);
+ ret = ret != Z_STREAM_END;
+ break;
+#ifdef CONFIG_LZO
+ case QCOW2_COMPRESSION_LZO:
+ out_buf = g_malloc(s->cluster_size + s->cluster_size / 64 + 16 + 3);
+ work_buf = g_malloc(LZO1X_1_MEM_COMPRESS);
+ ret = lzo1x_1_compress(buf, s->cluster_size, out_buf,
+ (lzo_uint *) &out_len, work_buf);
+ break;
+#endif
+ default:
+ abort(); /* should never reach this point */
+ }
- if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
+ if (ret || out_len >= s->cluster_size) {
/* could not compress: write normal cluster */
ret = qcow2_co_pwritev(bs, offset, bytes, qiov, 0);
if (ret < 0) {
@@ -2809,6 +2832,7 @@ success:
fail:
qemu_vfree(local_buf);
g_free(out_buf);
+ g_free(work_buf);
return ret;
}
@@ -172,6 +172,7 @@ typedef struct Qcow2UnknownHeaderExtension {
enum {
QCOW2_COMPRESSION_ZLIB = 0xC0318301,
+ QCOW2_COMPRESSION_LZO = 0xC0318302,
};
enum {
@@ -1890,7 +1890,7 @@ if test "$lzo" != "no" ; then
int main(void) { lzo_version(); return 0; }
EOF
if compile_prog "" "-llzo2" ; then
- libs_softmmu="$libs_softmmu -llzo2"
+ LIBS="$LIBS -llzo2"
lzo="yes"
else
if test "$lzo" = "yes"; then
@@ -627,6 +627,7 @@ The following options are available if support for the respective libraries
has been enabled at compile time:
zlib Uses standard zlib compression (default)
+ lzo Uses LZO1X compression
The compression algorithm can only be defined at image create time and cannot
be changed later.
Signed-off-by: Peter Lieven <pl@kamp.de> --- block/qcow2-cluster.c | 65 +++++++++++++++++++++++++++++++--------------- block/qcow2.c | 72 ++++++++++++++++++++++++++++++++++----------------- block/qcow2.h | 1 + configure | 2 +- qemu-img.texi | 1 + 5 files changed, 95 insertions(+), 46 deletions(-)