[PATCH 2/3] erofs-utils: fuse: add LZMA algorithm support

Gao Xiang xiang at kernel.org
Sat Oct 30 13:01:17 AEDT 2021


This patch adds LZMA compression algorithm support to erofsfuse
to test if LZMA fixed-sized output compression works as expected.

Cc: Lasse Collin <lasse.collin at tukaani.org>
Signed-off-by: Gao Xiang <xiang at kernel.org>
---
 include/erofs_fs.h |  5 +++-
 lib/data.c         |  7 ++---
 lib/decompress.c   | 66 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 74 insertions(+), 4 deletions(-)

diff --git a/include/erofs_fs.h b/include/erofs_fs.h
index 66a68e3b2065..86ad6f5fd86c 100644
--- a/include/erofs_fs.h
+++ b/include/erofs_fs.h
@@ -248,7 +248,8 @@ struct erofs_inode_chunk_index {
 
 /* available compression algorithm types (for h_algorithmtype) */
 enum {
-	Z_EROFS_COMPRESSION_LZ4	= 0,
+	Z_EROFS_COMPRESSION_LZ4		= 0,
+	Z_EROFS_COMPRESSION_LZMA	= 1,
 	Z_EROFS_COMPRESSION_MAX
 };
 #define Z_EROFS_ALL_COMPR_ALGS		(1 << (Z_EROFS_COMPRESSION_MAX - 1))
@@ -260,6 +261,8 @@ struct z_erofs_lz4_cfgs {
 	u8 reserved[10];
 } __packed;
 
+#define Z_EROFS_LZMA_MAX_DICT_SIZE	(8 * Z_EROFS_PCLUSTER_MAX_SIZE)
+
 /*
  * bit 0 : COMPACTED_2B indexes (0 - off; 1 - on)
  *  e.g. for 4k logical cluster size,      4B        if compacted 2B is off;
diff --git a/lib/data.c b/lib/data.c
index 641d8408b54f..82bf6ba85592 100644
--- a/lib/data.c
+++ b/lib/data.c
@@ -244,9 +244,10 @@ static int z_erofs_read_data(struct erofs_inode *inode, char *buffer,
 		if (ret < 0)
 			break;
 
-		algorithmformat = map.m_flags & EROFS_MAP_ZIPPED ?
-						Z_EROFS_COMPRESSION_LZ4 :
-						Z_EROFS_COMPRESSION_SHIFTED;
+		if (map.m_flags & EROFS_MAP_ZIPPED)
+			algorithmformat = inode->z_algorithmtype[0];
+		else
+			algorithmformat = Z_EROFS_COMPRESSION_SHIFTED;
 
 		ret = z_erofs_decompress(&(struct z_erofs_decompress_req) {
 					.in = raw,
diff --git a/lib/decompress.c b/lib/decompress.c
index 2ee1439d9bfa..f313e41d780b 100644
--- a/lib/decompress.c
+++ b/lib/decompress.c
@@ -7,6 +7,68 @@
 
 #include "erofs/decompress.h"
 #include "erofs/err.h"
+#include "erofs/print.h"
+
+#ifdef HAVE_LIBLZMA
+#include <lzma.h>
+
+static int z_erofs_decompress_lzma(struct z_erofs_decompress_req *rq)
+{
+	int ret = 0;
+	u8 *dest = (u8 *)rq->out;
+	u8 *src = (u8 *)rq->in;
+	u8 *buff = NULL;
+	unsigned int inputmargin = 0;
+	lzma_stream strm;
+	lzma_ret ret2;
+
+	while (!src[inputmargin & ~PAGE_MASK])
+		if (!(++inputmargin & ~PAGE_MASK))
+			break;
+
+	if (inputmargin >= rq->inputsize)
+		return -EFSCORRUPTED;
+
+	if (rq->decodedskip) {
+		buff = malloc(rq->decodedlength);
+		if (!buff)
+			return -ENOMEM;
+		dest = buff;
+	}
+
+	strm = (lzma_stream)LZMA_STREAM_INIT;
+	strm.next_in = src + inputmargin;
+	strm.avail_in = rq->inputsize - inputmargin;
+	strm.next_out = dest;
+	strm.avail_out = rq->decodedlength;
+
+	ret2 = lzma_microlzma_decoder(&strm, strm.avail_in, rq->decodedlength,
+				      !rq->partial_decoding,
+				      Z_EROFS_LZMA_MAX_DICT_SIZE);
+	if (ret2 != LZMA_OK) {
+		erofs_err("fail to initialize lzma decoder %u", ret2 | 0U);
+		ret = -EFAULT;
+		goto out;
+	}
+
+	ret2 = lzma_code(&strm, LZMA_FINISH);
+	if (ret2 != LZMA_STREAM_END) {
+		ret = -EFSCORRUPTED;
+		goto out_lzma_end;
+	}
+
+	if (rq->decodedskip)
+		memcpy(rq->out, dest + rq->decodedskip,
+		       rq->decodedlength - rq->decodedskip);
+
+out_lzma_end:
+	lzma_end(&strm);
+out:
+	if (buff)
+		free(buff);
+	return ret;
+}
+#endif
 
 #ifdef LZ4_ENABLED
 #include <lz4.h>
@@ -81,6 +143,10 @@ int z_erofs_decompress(struct z_erofs_decompress_req *rq)
 #ifdef LZ4_ENABLED
 	if (rq->alg == Z_EROFS_COMPRESSION_LZ4)
 		return z_erofs_decompress_lz4(rq);
+#endif
+#ifdef HAVE_LIBLZMA
+	if (rq->alg == Z_EROFS_COMPRESSION_LZMA)
+		return z_erofs_decompress_lzma(rq);
 #endif
 	return -EOPNOTSUPP;
 }
-- 
2.20.1



More information about the Linux-erofs mailing list