* [Qemu-devel] [PATCH v3 1/4] block: adding lzfse decompressing support as a module.
2018-11-05 15:08 [Qemu-devel] [PATCH v3 0/4] Adding LZFSE compression support for DMG block driver Julio Faracco
@ 2018-11-05 15:08 ` Julio Faracco
2018-11-05 15:08 ` [Qemu-devel] [PATCH v3 2/4] configure: adding support to lzfse library Julio Faracco
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Julio Faracco @ 2018-11-05 15:08 UTC (permalink / raw)
To: qemu-devel; +Cc: Kevin Wolf, Max Reitz, Stefan Hajnoczi, qemu-block
QEMU dmg support includes zlib and bzip2, but it does not contains lzfse
support. This commit adds the source file to extend compression support
for new DMGs.
Signed-off-by: Julio Faracco <jcfaracco@gmail.com>
---
block/dmg-lzfse.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 49 insertions(+)
create mode 100644 block/dmg-lzfse.c
diff --git a/block/dmg-lzfse.c b/block/dmg-lzfse.c
new file mode 100644
index 0000000000..19d25bc646
--- /dev/null
+++ b/block/dmg-lzfse.c
@@ -0,0 +1,49 @@
+/*
+ * DMG lzfse uncompression
+ *
+ * Copyright (c) 2018 Julio Cesar Faracco
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "dmg.h"
+#include <lzfse.h>
+
+static int dmg_uncompress_lzfse_do(char *next_in, unsigned int avail_in,
+ char *next_out, unsigned int avail_out)
+{
+ size_t out_size = lzfse_decode_buffer((uint8_t *) next_out, avail_out,
+ (uint8_t *) next_in, avail_in,
+ NULL);
+
+ /* We need to decode the single chunk only. */
+ /* So, out_size == avail_out is not an error here. */
+ if (out_size > 0) {
+ return out_size;
+ }
+ return -1;
+}
+
+__attribute__((constructor))
+static void dmg_lzfse_init(void)
+{
+ assert(!dmg_uncompress_lzfse);
+ dmg_uncompress_lzfse = dmg_uncompress_lzfse_do;
+}
--
2.17.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [Qemu-devel] [PATCH v3 2/4] configure: adding support to lzfse library.
2018-11-05 15:08 [Qemu-devel] [PATCH v3 0/4] Adding LZFSE compression support for DMG block driver Julio Faracco
2018-11-05 15:08 ` [Qemu-devel] [PATCH v3 1/4] block: adding lzfse decompressing support as a module Julio Faracco
@ 2018-11-05 15:08 ` Julio Faracco
2018-11-05 15:08 ` [Qemu-devel] [PATCH v3 3/4] dmg: including dmg-lzfse module inside dmg block driver Julio Faracco
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Julio Faracco @ 2018-11-05 15:08 UTC (permalink / raw)
To: qemu-devel; +Cc: Kevin Wolf, Max Reitz, Stefan Hajnoczi, qemu-block
This commit includes the support to lzfse opensource library. With this
library dmg block driver can decompress images with this type of
compression inside.
Signed-off-by: Julio Faracco <jcfaracco@gmail.com>
---
block/Makefile.objs | 2 ++
configure | 31 +++++++++++++++++++++++++++++++
2 files changed, 33 insertions(+)
diff --git a/block/Makefile.objs b/block/Makefile.objs
index c8337bf186..f4ddbb9c7b 100644
--- a/block/Makefile.objs
+++ b/block/Makefile.objs
@@ -47,6 +47,8 @@ ssh.o-cflags := $(LIBSSH2_CFLAGS)
ssh.o-libs := $(LIBSSH2_LIBS)
block-obj-$(if $(CONFIG_BZIP2),m,n) += dmg-bz2.o
dmg-bz2.o-libs := $(BZIP2_LIBS)
+block-obj-$(if $(CONFIG_LZFSE),m,n) += dmg-lzfse.o
+dmg-lzfse.o-libs := $(LZFSE_LIBS)
qcow.o-libs := -lz
linux-aio.o-libs := -laio
parallels.o-cflags := $(LIBXML2_CFLAGS)
diff --git a/configure b/configure
index 46ae1e8c76..56b26f0579 100755
--- a/configure
+++ b/configure
@@ -434,6 +434,7 @@ capstone=""
lzo=""
snappy=""
bzip2=""
+lzfse=""
guest_agent=""
guest_agent_with_vss="no"
guest_agent_ntddscsi="no"
@@ -1301,6 +1302,10 @@ for opt do
;;
--enable-bzip2) bzip2="yes"
;;
+ --enable-lzfse) lzfse="yes"
+ ;;
+ --disable-lzfse) lzfse="no"
+ ;;
--enable-guest-agent) guest_agent="yes"
;;
--disable-guest-agent) guest_agent="no"
@@ -1700,6 +1705,8 @@ disabled with --disable-FEATURE, default is enabled if available:
snappy support of snappy compression library
bzip2 support of bzip2 compression library
(for reading bzip2-compressed dmg images)
+ lzfse support of lzfse compression library
+ (for reading lzfse-compressed dmg images)
seccomp seccomp support
coroutine-pool coroutine freelist (better performance)
glusterfs GlusterFS backend
@@ -2209,6 +2216,24 @@ EOF
fi
fi
+##########################################
+# lzfse check
+
+if test "$lzfse" != "no" ; then
+ cat > $TMPC << EOF
+#include <lzfse.h>
+int main(void) { lzfse_decode_scratch_size(); return 0; }
+EOF
+ if compile_prog "" "-llzfse" ; then
+ lzfse="yes"
+ else
+ if test "$lzfse" = "yes"; then
+ feature_not_found "lzfse" "Install lzfse devel"
+ fi
+ lzfse="no"
+ fi
+fi
+
##########################################
# libseccomp check
@@ -6036,6 +6061,7 @@ echo "Live block migration $live_block_migration"
echo "lzo support $lzo"
echo "snappy support $snappy"
echo "bzip2 support $bzip2"
+echo "lzfse support $lzfse"
echo "NUMA host support $numa"
echo "libxml2 $libxml2"
echo "tcmalloc support $tcmalloc"
@@ -6549,6 +6575,11 @@ if test "$bzip2" = "yes" ; then
echo "BZIP2_LIBS=-lbz2" >> $config_host_mak
fi
+if test "$lzfse" = "yes" ; then
+ echo "CONFIG_LZFSE=y" >> $config_host_mak
+ echo "LZFSE_LIBS=-llzfse" >> $config_host_mak
+fi
+
if test "$libiscsi" = "yes" ; then
echo "CONFIG_LIBISCSI=m" >> $config_host_mak
echo "LIBISCSI_CFLAGS=$libiscsi_cflags" >> $config_host_mak
--
2.17.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [Qemu-devel] [PATCH v3 3/4] dmg: including dmg-lzfse module inside dmg block driver.
2018-11-05 15:08 [Qemu-devel] [PATCH v3 0/4] Adding LZFSE compression support for DMG block driver Julio Faracco
2018-11-05 15:08 ` [Qemu-devel] [PATCH v3 1/4] block: adding lzfse decompressing support as a module Julio Faracco
2018-11-05 15:08 ` [Qemu-devel] [PATCH v3 2/4] configure: adding support to lzfse library Julio Faracco
@ 2018-11-05 15:08 ` Julio Faracco
2018-11-05 15:08 ` [Qemu-devel] [PATCH v3 4/4] dmg: exchanging hardcoded dmg UDIF block types to enum Julio Faracco
2018-11-06 16:46 ` [Qemu-devel] [PATCH v3 0/4] Adding LZFSE compression support for DMG block driver Kevin Wolf
4 siblings, 0 replies; 6+ messages in thread
From: Julio Faracco @ 2018-11-05 15:08 UTC (permalink / raw)
To: qemu-devel; +Cc: Kevin Wolf, Max Reitz, Stefan Hajnoczi, qemu-block
This commit includes the support to new module dmg-lzfse into dmg block
driver. It includes the support for block type ULFO (0x80000007).
Signed-off-by: Julio Faracco <jcfaracco@gmail.com>
---
block/dmg.c | 28 ++++++++++++++++++++++++++++
block/dmg.h | 3 +++
2 files changed, 31 insertions(+)
diff --git a/block/dmg.c b/block/dmg.c
index c9b3c519c4..615f818c5a 100644
--- a/block/dmg.c
+++ b/block/dmg.c
@@ -33,6 +33,9 @@
int (*dmg_uncompress_bz2)(char *next_in, unsigned int avail_in,
char *next_out, unsigned int avail_out);
+int (*dmg_uncompress_lzfse)(char *next_in, unsigned int avail_in,
+ char *next_out, unsigned int avail_out);
+
enum {
/* Limit chunk sizes to prevent unreasonable amounts of memory being used
* or truncating when converting to 32-bit types
@@ -107,6 +110,7 @@ static void update_max_chunk_size(BDRVDMGState *s, uint32_t chunk,
switch (s->types[chunk]) {
case 0x80000005: /* zlib compressed */
case 0x80000006: /* bzip2 compressed */
+ case 0x80000007: /* lzfse compressed */
compressed_size = s->lengths[chunk];
uncompressed_sectors = s->sectorcounts[chunk];
break;
@@ -188,6 +192,8 @@ static bool dmg_is_known_block_type(uint32_t entry_type)
return true;
case 0x80000006: /* bzip2 */
return !!dmg_uncompress_bz2;
+ case 0x80000007: /* lzfse */
+ return !!dmg_uncompress_lzfse;
default:
return false;
}
@@ -431,6 +437,7 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
}
block_module_load_one("dmg-bz2");
+ block_module_load_one("dmg-lzfse");
s->n_chunks = 0;
s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL;
@@ -629,6 +636,27 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
return ret;
}
break;
+ case 0x80000007:
+ if (!dmg_uncompress_lzfse) {
+ break;
+ }
+ /* we need to buffer, because only the chunk as whole can be
+ * inflated. */
+ ret = bdrv_pread(bs->file, s->offsets[chunk],
+ s->compressed_chunk, s->lengths[chunk]);
+ if (ret != s->lengths[chunk]) {
+ return -1;
+ }
+
+ ret = dmg_uncompress_lzfse((char *)s->compressed_chunk,
+ (unsigned int) s->lengths[chunk],
+ (char *)s->uncompressed_chunk,
+ (unsigned int)
+ (512 * s->sectorcounts[chunk]));
+ if (ret < 0) {
+ return ret;
+ }
+ break;
case 1: /* copy */
ret = bdrv_pread(bs->file, s->offsets[chunk],
s->uncompressed_chunk, s->lengths[chunk]);
diff --git a/block/dmg.h b/block/dmg.h
index 2ecf239ba5..f28929998f 100644
--- a/block/dmg.h
+++ b/block/dmg.h
@@ -55,4 +55,7 @@ typedef struct BDRVDMGState {
extern int (*dmg_uncompress_bz2)(char *next_in, unsigned int avail_in,
char *next_out, unsigned int avail_out);
+extern int (*dmg_uncompress_lzfse)(char *next_in, unsigned int avail_in,
+ char *next_out, unsigned int avail_out);
+
#endif
--
2.17.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [Qemu-devel] [PATCH v3 4/4] dmg: exchanging hardcoded dmg UDIF block types to enum.
2018-11-05 15:08 [Qemu-devel] [PATCH v3 0/4] Adding LZFSE compression support for DMG block driver Julio Faracco
` (2 preceding siblings ...)
2018-11-05 15:08 ` [Qemu-devel] [PATCH v3 3/4] dmg: including dmg-lzfse module inside dmg block driver Julio Faracco
@ 2018-11-05 15:08 ` Julio Faracco
2018-11-06 16:46 ` [Qemu-devel] [PATCH v3 0/4] Adding LZFSE compression support for DMG block driver Kevin Wolf
4 siblings, 0 replies; 6+ messages in thread
From: Julio Faracco @ 2018-11-05 15:08 UTC (permalink / raw)
To: qemu-devel; +Cc: Kevin Wolf, Max Reitz, Stefan Hajnoczi, qemu-block
This change is better to understand what kind of block type is being
handled by the code. Using a syntax similar to the DMG documentation is
easier than tracking all hex values assigned to a block type.
Signed-off-by: Julio Faracco <jcfaracco@gmail.com>
---
block/dmg.c | 43 ++++++++++++++++++++++++++++---------------
1 file changed, 28 insertions(+), 15 deletions(-)
diff --git a/block/dmg.c b/block/dmg.c
index 615f818c5a..6d055594df 100644
--- a/block/dmg.c
+++ b/block/dmg.c
@@ -44,6 +44,19 @@ enum {
DMG_SECTORCOUNTS_MAX = DMG_LENGTHS_MAX / 512,
};
+enum {
+ /* DMG Block Type */
+ UDZE = 0, /* Zeroes */
+ UDRW, /* RAW type */
+ UDIG, /* Ignore */
+ UDCO = 0x80000004,
+ UDZO,
+ UDBZ,
+ ULFO,
+ UDCM = 0x7ffffffe, /* Comments */
+ UDLE /* Last Entry */
+};
+
static int dmg_probe(const uint8_t *buf, int buf_size, const char *filename)
{
int len;
@@ -108,16 +121,16 @@ static void update_max_chunk_size(BDRVDMGState *s, uint32_t chunk,
uint32_t uncompressed_sectors = 0;
switch (s->types[chunk]) {
- case 0x80000005: /* zlib compressed */
- case 0x80000006: /* bzip2 compressed */
- case 0x80000007: /* lzfse compressed */
+ case UDZO: /* zlib compressed */
+ case UDBZ: /* bzip2 compressed */
+ case ULFO: /* lzfse compressed */
compressed_size = s->lengths[chunk];
uncompressed_sectors = s->sectorcounts[chunk];
break;
- case 1: /* copy */
+ case UDRW: /* copy */
uncompressed_sectors = DIV_ROUND_UP(s->lengths[chunk], 512);
break;
- case 2: /* zero */
+ case UDIG: /* zero */
/* as the all-zeroes block may be large, it is treated specially: the
* sector is not copied from a large buffer, a simple memset is used
* instead. Therefore uncompressed_sectors does not need to be set. */
@@ -186,13 +199,13 @@ typedef struct DmgHeaderState {
static bool dmg_is_known_block_type(uint32_t entry_type)
{
switch (entry_type) {
- case 0x00000001: /* uncompressed */
- case 0x00000002: /* zeroes */
- case 0x80000005: /* zlib */
+ case UDRW: /* uncompressed */
+ case UDIG: /* zeroes */
+ case UDZO: /* zlib */
return true;
- case 0x80000006: /* bzip2 */
+ case UDBZ: /* bzip2 */
return !!dmg_uncompress_bz2;
- case 0x80000007: /* lzfse */
+ case ULFO: /* lzfse */
return !!dmg_uncompress_lzfse;
default:
return false;
@@ -592,7 +605,7 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
s->current_chunk = s->n_chunks;
switch (s->types[chunk]) { /* block entry type */
- case 0x80000005: { /* zlib compressed */
+ case UDZO: { /* zlib compressed */
/* we need to buffer, because only the chunk as whole can be
* inflated. */
ret = bdrv_pread(bs->file, s->offsets[chunk],
@@ -615,7 +628,7 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
return -1;
}
break; }
- case 0x80000006: /* bzip2 compressed */
+ case UDBZ: /* bzip2 compressed */
if (!dmg_uncompress_bz2) {
break;
}
@@ -636,7 +649,7 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
return ret;
}
break;
- case 0x80000007:
+ case ULFO:
if (!dmg_uncompress_lzfse) {
break;
}
@@ -657,14 +670,14 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
return ret;
}
break;
- case 1: /* copy */
+ case UDRW: /* copy */
ret = bdrv_pread(bs->file, s->offsets[chunk],
s->uncompressed_chunk, s->lengths[chunk]);
if (ret != s->lengths[chunk]) {
return -1;
}
break;
- case 2: /* zero */
+ case UDIG: /* zero */
/* see dmg_read, it is treated specially. No buffer needs to be
* pre-filled, the zeroes can be set directly. */
break;
--
2.17.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [Qemu-devel] [PATCH v3 0/4] Adding LZFSE compression support for DMG block driver.
2018-11-05 15:08 [Qemu-devel] [PATCH v3 0/4] Adding LZFSE compression support for DMG block driver Julio Faracco
` (3 preceding siblings ...)
2018-11-05 15:08 ` [Qemu-devel] [PATCH v3 4/4] dmg: exchanging hardcoded dmg UDIF block types to enum Julio Faracco
@ 2018-11-06 16:46 ` Kevin Wolf
4 siblings, 0 replies; 6+ messages in thread
From: Kevin Wolf @ 2018-11-06 16:46 UTC (permalink / raw)
To: Julio Faracco; +Cc: qemu-devel, Max Reitz, Stefan Hajnoczi, qemu-block
Am 05.11.2018 um 16:08 hat Julio Faracco geschrieben:
> Since Mac OS X El Capitain (v10.11), Apple uses LZFSE compression to
> generate compressed DMGs as an alternative to BZIP2. Possible, Apple
> want to keep this algorithm as default in long term. Some years ago,
> Apple opened the LZFSE algorithm to opensource and the main source (or
> the most active repo), can be found at: https://github.com/lzfse/lzfse
>
> v1-v2: Fixing some error handlings from dmg-lzfse.c
> v2-v3: Master rebasing suggestion from Stefan.
Thanks, applied to the block-next branch (for 3.2).
Stefan, if you have some more comments, we can still modify/dequeue the
patches, but this seems to address all of my review comments for v1.
Kevin
^ permalink raw reply [flat|nested] 6+ messages in thread