linux-erofs.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/8] erofs-utils: support big pcluster compression
@ 2021-04-11  3:48 Gao Xiang
  2021-04-11  3:48 ` [PATCH 1/8] erofs-utils: support adjust lz4 history window size Gao Xiang
                   ` (8 more replies)
  0 siblings, 9 replies; 10+ messages in thread
From: Gao Xiang @ 2021-04-11  3:48 UTC (permalink / raw)
  To: linux-erofs; +Cc: Gao Xiang

Hi folks,

This matches big pcluster kernel support in for-next. I've tested
together with ro_fsstress and aosp x86_64 cuttlefish boot without
any problem.

XXX: since LZMA hasn't been introduced yet, compression cfg
generation code is still a preliminary version, will refine it
with later formal LZMA support.

Thanks,
Gao Xiang

Gao Xiang (7):
  erofs-utils: introduce ondisk compression cfgs
  erofs-utils: add -C# for the maximum size of pclusters
  erofs-utils: add big physical cluster definition
  erofs-utils: fuse: support multiple block compression
  erofs-utils: mkfs: support multiple block compression
  erofs-utils: fuse: support compact indexes for bigpcluster
  erofs-utils: mkfs: support compact indexes for bigpcluster

Huang Jianan (1):
  erofs-utils: support adjust lz4 history window size

 include/erofs/compress.h |   2 +-
 include/erofs/config.h   |   2 +
 include/erofs/internal.h |   5 ++
 include/erofs_fs.h       |  39 ++++++++--
 lib/compress.c           | 160 ++++++++++++++++++++++++++++++---------
 lib/compressor_lz4.c     |   5 ++
 lib/compressor_lz4hc.c   |   2 +
 lib/config.c             |   1 +
 lib/data.c               |   4 +-
 lib/zmap.c               | 136 +++++++++++++++++++++++++++++----
 mkfs/main.c              |  21 ++++-
 11 files changed, 317 insertions(+), 60 deletions(-)

-- 
2.20.1


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/8] erofs-utils: support adjust lz4 history window size
  2021-04-11  3:48 [PATCH 0/8] erofs-utils: support big pcluster compression Gao Xiang
@ 2021-04-11  3:48 ` Gao Xiang
  2021-04-11  3:48 ` [PATCH 2/8] erofs-utils: introduce ondisk compression cfgs Gao Xiang
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Gao Xiang @ 2021-04-11  3:48 UTC (permalink / raw)
  To: linux-erofs; +Cc: Gao Xiang, Guo Weichao

From: Huang Jianan <huangjianan@oppo.com>

lz4 uses LZ4_DISTANCE_MAX to record history preservation. When
using rolling decompression, a block with a higher compression
ratio will cause a larger memory allocation (up to 64k). It may
cause a large resource burden in extreme cases on devices with
small memory and a large number of concurrent IOs. So appropriately
reducing this value can improve performance.

Decreasing this value will reduce the compression ratio (except
when input_size <LZ4_DISTANCE_MAX). But considering that erofs
currently only supports 4k output, reducing this value will not
significantly reduce the compression benefits.

The maximum value of LZ4_DISTANCE_MAX defined by lz4 is 64k, and
we can only reduce this value. For the old kernel, it just can't
reduce the memory allocation during rolling decompression without
affecting the decompression result.

Signed-off-by: Huang Jianan <huangjianan@oppo.com>
Signed-off-by: Guo Weichao <guoweichao@oppo.com>
Signed-off-by: Gao Xiang <xiang@kernel.org>
---
 include/erofs/internal.h | 1 +
 include/erofs_fs.h       | 3 ++-
 lib/compressor_lz4.c     | 5 +++++
 lib/compressor_lz4hc.c   | 2 ++
 mkfs/main.c              | 1 +
 5 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index ac5b270329e2..3849980d8eab 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -79,6 +79,7 @@ struct erofs_sb_info {
 	u64 inos;
 
 	u8 uuid[16];
+	u16 lz4_max_distance;
 };
 
 /* global sbi */
diff --git a/include/erofs_fs.h b/include/erofs_fs.h
index a69f179a51a5..ae2305c1eb79 100644
--- a/include/erofs_fs.h
+++ b/include/erofs_fs.h
@@ -41,7 +41,8 @@ struct erofs_super_block {
 	__u8 uuid[16];          /* 128-bit uuid for volume */
 	__u8 volume_name[16];   /* volume name */
 	__le32 feature_incompat;
-	__u8 reserved2[44];
+	__le16 lz4_max_distance;
+	__u8 reserved2[42];
 };
 
 /*
diff --git a/lib/compressor_lz4.c b/lib/compressor_lz4.c
index 8540a0d01cbb..292d0f27fe0e 100644
--- a/lib/compressor_lz4.c
+++ b/lib/compressor_lz4.c
@@ -10,6 +10,10 @@
 #include "erofs/internal.h"
 #include "compressor.h"
 
+#ifndef LZ4_DISTANCE_MAX	/* history window size */
+#define LZ4_DISTANCE_MAX 65535	/* set to maximum value by default */
+#endif
+
 static int lz4_compress_destsize(struct erofs_compress *c,
 				 int compression_level,
 				 void *src, unsigned int *srcsize,
@@ -32,6 +36,7 @@ static int compressor_lz4_exit(struct erofs_compress *c)
 static int compressor_lz4_init(struct erofs_compress *c)
 {
 	c->alg = &erofs_compressor_lz4;
+	sbi.lz4_max_distance = LZ4_DISTANCE_MAX;
 	return 0;
 }
 
diff --git a/lib/compressor_lz4hc.c b/lib/compressor_lz4hc.c
index 6680563986c3..052c6ba0cc41 100644
--- a/lib/compressor_lz4hc.c
+++ b/lib/compressor_lz4hc.c
@@ -44,6 +44,8 @@ static int compressor_lz4hc_init(struct erofs_compress *c)
 	c->private_data = LZ4_createStreamHC();
 	if (!c->private_data)
 		return -ENOMEM;
+
+	sbi.lz4_max_distance = LZ4_DISTANCE_MAX;
 	return 0;
 }
 
diff --git a/mkfs/main.c b/mkfs/main.c
index d9c4c7fff5c1..4c9743d077a7 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -299,6 +299,7 @@ int erofs_mkfs_update_super_block(struct erofs_buffer_head *bh,
 		.feature_incompat = cpu_to_le32(sbi.feature_incompat),
 		.feature_compat = cpu_to_le32(sbi.feature_compat &
 					      ~EROFS_FEATURE_COMPAT_SB_CHKSUM),
+		.lz4_max_distance = cpu_to_le16(sbi.lz4_max_distance),
 	};
 	const unsigned int sb_blksize =
 		round_up(EROFS_SUPER_END, EROFS_BLKSIZ);
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/8] erofs-utils: introduce ondisk compression cfgs
  2021-04-11  3:48 [PATCH 0/8] erofs-utils: support big pcluster compression Gao Xiang
  2021-04-11  3:48 ` [PATCH 1/8] erofs-utils: support adjust lz4 history window size Gao Xiang
@ 2021-04-11  3:48 ` Gao Xiang
  2021-04-11  3:48 ` [PATCH 3/8] erofs-utils: add -C# for the maximum size of pclusters Gao Xiang
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Gao Xiang @ 2021-04-11  3:48 UTC (permalink / raw)
  To: linux-erofs; +Cc: Gao Xiang

Add support to generate ondisk compression cfgs, which can generate
lz4 compression cfgs now.

Signed-off-by: Gao Xiang <xiang@kernel.org>
---
 include/erofs/compress.h |  2 +-
 include/erofs/internal.h |  3 +++
 include/erofs_fs.h       | 17 +++++++++++++++--
 lib/compress.c           | 37 ++++++++++++++++++++++++++++++++++++-
 mkfs/main.c              |  8 ++++++--
 5 files changed, 61 insertions(+), 6 deletions(-)

diff --git a/include/erofs/compress.h b/include/erofs/compress.h
index 952f2870a180..d234e8b25a3b 100644
--- a/include/erofs/compress.h
+++ b/include/erofs/compress.h
@@ -18,7 +18,7 @@
 
 int erofs_write_compressed_file(struct erofs_inode *inode);
 
-int z_erofs_compress_init(void);
+int z_erofs_compress_init(struct erofs_buffer_head *bh);
 int z_erofs_compress_exit(void);
 
 const char *z_erofs_list_available_compressors(unsigned int i);
diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 3849980d8eab..6e481faa8c9f 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -79,6 +79,8 @@ struct erofs_sb_info {
 	u64 inos;
 
 	u8 uuid[16];
+
+	u16 available_compr_algs;
 	u16 lz4_max_distance;
 };
 
@@ -105,6 +107,7 @@ static inline void erofs_sb_clear_##name(void) \
 }
 
 EROFS_FEATURE_FUNCS(lz4_0padding, incompat, INCOMPAT_LZ4_0PADDING)
+EROFS_FEATURE_FUNCS(compr_cfgs, incompat, INCOMPAT_COMPR_CFGS)
 EROFS_FEATURE_FUNCS(sb_chksum, compat, COMPAT_SB_CHKSUM)
 
 #define EROFS_I_EA_INITED	(1 << 0)
diff --git a/include/erofs_fs.h b/include/erofs_fs.h
index ae2305c1eb79..a24deb095537 100644
--- a/include/erofs_fs.h
+++ b/include/erofs_fs.h
@@ -20,7 +20,10 @@
  * be incompatible with this kernel version.
  */
 #define EROFS_FEATURE_INCOMPAT_LZ4_0PADDING	0x00000001
-#define EROFS_ALL_FEATURE_INCOMPAT		EROFS_FEATURE_INCOMPAT_LZ4_0PADDING
+#define EROFS_FEATURE_INCOMPAT_COMPR_CFGS	0x00000002
+#define EROFS_ALL_FEATURE_INCOMPAT		\
+	(EROFS_FEATURE_INCOMPAT_LZ4_0PADDING | \
+	 EROFS_FEATURE_INCOMPAT_COMPR_CFGS)
 
 /* 128-byte erofs on-disk super block */
 struct erofs_super_block {
@@ -41,7 +44,11 @@ struct erofs_super_block {
 	__u8 uuid[16];          /* 128-bit uuid for volume */
 	__u8 volume_name[16];   /* volume name */
 	__le32 feature_incompat;
-	__le16 lz4_max_distance;
+	union {
+		/* bitmap for available compression algorithms */
+		__le16 available_compr_algs;
+		__le16 lz4_max_distance;
+	} u1;
 	__u8 reserved2[42];
 };
 
@@ -198,6 +205,12 @@ enum {
 	Z_EROFS_COMPRESSION_MAX
 };
 
+/* 14 bytes (+ length field = 16 bytes) */
+struct z_erofs_lz4_cfgs {
+	__le16 max_distance;
+	u8 reserved[12];
+} __packed;
+
 /*
  * 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/compress.c b/lib/compress.c
index 4b685cd27080..c991c13dfd1a 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -500,7 +500,37 @@ static int erofs_get_compress_algorithm_id(const char *name)
 	return -ENOTSUP;
 }
 
-int z_erofs_compress_init(void)
+int z_erofs_build_compr_cfgs(struct erofs_buffer_head *sb_bh)
+{
+	struct erofs_buffer_head *bh = sb_bh;
+	int ret = 0;
+
+	if (sbi.available_compr_algs & (1 << Z_EROFS_COMPRESSION_LZ4)) {
+		struct {
+			__le16 size;
+			struct z_erofs_lz4_cfgs lz4;
+		} __packed lz4alg = {
+			.size = cpu_to_le16(sizeof(struct z_erofs_lz4_cfgs)),
+			.lz4 = {
+				.max_distance =
+					cpu_to_le16(sbi.lz4_max_distance),
+			}
+		};
+
+		bh = erofs_battach(bh, META, sizeof(lz4alg));
+		if (IS_ERR(bh)) {
+			DBG_BUGON(1);
+			return PTR_ERR(bh);
+		}
+		erofs_mapbh(bh->block);
+		ret = dev_write(&lz4alg, erofs_btell(bh, false),
+				sizeof(lz4alg));
+		bh->op = &erofs_drop_directly_bhops;
+	}
+	return ret;
+}
+
+int z_erofs_compress_init(struct erofs_buffer_head *sb_bh)
 {
 	unsigned int algorithmtype[2];
 	/* initialize for primary compression algorithm */
@@ -536,6 +566,11 @@ int z_erofs_compress_init(void)
 	mapheader.h_algorithmtype = algorithmtype[1] << 4 |
 					  algorithmtype[0];
 	mapheader.h_clusterbits = LOG_BLOCK_SIZE - 12;
+
+	if (erofs_sb_has_compr_cfgs()) {
+		sbi.available_compr_algs |= 1 << ret;
+		return z_erofs_build_compr_cfgs(sb_bh);
+	}
 	return 0;
 }
 
diff --git a/mkfs/main.c b/mkfs/main.c
index 4c9743d077a7..c2a0214c84e2 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -299,7 +299,6 @@ int erofs_mkfs_update_super_block(struct erofs_buffer_head *bh,
 		.feature_incompat = cpu_to_le32(sbi.feature_incompat),
 		.feature_compat = cpu_to_le32(sbi.feature_compat &
 					      ~EROFS_FEATURE_COMPAT_SB_CHKSUM),
-		.lz4_max_distance = cpu_to_le16(sbi.lz4_max_distance),
 	};
 	const unsigned int sb_blksize =
 		round_up(EROFS_SUPER_END, EROFS_BLKSIZ);
@@ -310,6 +309,11 @@ int erofs_mkfs_update_super_block(struct erofs_buffer_head *bh,
 	sb.root_nid     = cpu_to_le16(root_nid);
 	memcpy(sb.uuid, sbi.uuid, sizeof(sb.uuid));
 
+	if (erofs_sb_has_compr_cfgs())
+		sb.u1.available_compr_algs = sbi.available_compr_algs;
+	else
+		sb.u1.lz4_max_distance = cpu_to_le16(sbi.lz4_max_distance);
+
 	buf = calloc(sb_blksize, 1);
 	if (!buf) {
 		erofs_err("Failed to allocate memory for sb: %s",
@@ -499,7 +503,7 @@ int main(int argc, char **argv)
 		goto exit;
 	}
 
-	err = z_erofs_compress_init();
+	err = z_erofs_compress_init(sb_bh);
 	if (err) {
 		erofs_err("Failed to initialize compressor: %s",
 			  erofs_strerror(err));
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/8] erofs-utils: add -C# for the maximum size of pclusters
  2021-04-11  3:48 [PATCH 0/8] erofs-utils: support big pcluster compression Gao Xiang
  2021-04-11  3:48 ` [PATCH 1/8] erofs-utils: support adjust lz4 history window size Gao Xiang
  2021-04-11  3:48 ` [PATCH 2/8] erofs-utils: introduce ondisk compression cfgs Gao Xiang
@ 2021-04-11  3:48 ` Gao Xiang
  2021-04-11  3:48 ` [PATCH 4/8] erofs-utils: add big physical cluster definition Gao Xiang
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Gao Xiang @ 2021-04-11  3:48 UTC (permalink / raw)
  To: linux-erofs; +Cc: Gao Xiang

Set up -C >= EROFS_BLKSIZ (more specifically, >= lclustersize)
to enable big pcluster feature.

Signed-off-by: Gao Xiang <xiang@kernel.org>
---
 include/erofs/config.h |  2 ++
 lib/config.c           |  1 +
 mkfs/main.c            | 14 +++++++++++++-
 3 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/include/erofs/config.h b/include/erofs/config.h
index 02ddf594ca60..5f5a05a8b796 100644
--- a/include/erofs/config.h
+++ b/include/erofs/config.h
@@ -53,6 +53,8 @@ struct erofs_configure {
 	int c_force_inodeversion;
 	/* < 0, xattr disabled and INT_MAX, always use inline xattrs */
 	int c_inline_xattr_tolerance;
+
+	u32 c_physical_clusterblks;
 	u64 c_unix_timestamp;
 #ifdef WITH_ANDROID
 	char *mount_point;
diff --git a/lib/config.c b/lib/config.c
index 3ecd48140cfd..352a77c8d639 100644
--- a/lib/config.c
+++ b/lib/config.c
@@ -24,6 +24,7 @@ void erofs_init_configure(void)
 	cfg.c_force_inodeversion = 0;
 	cfg.c_inline_xattr_tolerance = 2;
 	cfg.c_unix_timestamp = -1;
+	cfg.c_physical_clusterblks = 1;
 }
 
 void erofs_show_config(void)
diff --git a/mkfs/main.c b/mkfs/main.c
index c2a0214c84e2..fef94e26e86b 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -62,6 +62,7 @@ static void usage(void)
 	fputs("usage: [options] FILE DIRECTORY\n\n"
 	      "Generate erofs image from DIRECTORY to FILE, and [options] are:\n"
 	      " -zX[,Y]            X=compressor (Y=compression level, optional)\n"
+	      " -C#                specify the size of compress physical cluster in bytes\n"
 	      " -d#                set output message level to # (maximum 9)\n"
 	      " -x#                set xattr tolerance to # (< 0, disable xattrs; default 2)\n"
 	      " -EX[,...]          X=extended options\n"
@@ -152,7 +153,7 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
 	char *endptr;
 	int opt, i;
 
-	while((opt = getopt_long(argc, argv, "d:x:z:E:T:U:",
+	while((opt = getopt_long(argc, argv, "d:x:z:E:T:U:C:",
 				 long_options, NULL)) != -1) {
 		switch (opt) {
 		case 'z':
@@ -248,6 +249,17 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
 			cfg.fs_config_file = optarg;
 			break;
 #endif
+		case 'C':
+			i = strtoull(optarg, &endptr, 0);
+			if (*endptr != '\0' ||
+			    i < EROFS_BLKSIZ || i % EROFS_BLKSIZ) {
+				erofs_err("invalid physical clustersize %s",
+					  optarg);
+				return -EINVAL;
+			}
+			cfg.c_physical_clusterblks = i / EROFS_BLKSIZ;
+			break;
+
 		case 1:
 			usage();
 			exit(0);
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 4/8] erofs-utils: add big physical cluster definition
  2021-04-11  3:48 [PATCH 0/8] erofs-utils: support big pcluster compression Gao Xiang
                   ` (2 preceding siblings ...)
  2021-04-11  3:48 ` [PATCH 3/8] erofs-utils: add -C# for the maximum size of pclusters Gao Xiang
@ 2021-04-11  3:48 ` Gao Xiang
  2021-04-11  3:48 ` [PATCH 5/8] erofs-utils: fuse: support multiple block compression Gao Xiang
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Gao Xiang @ 2021-04-11  3:48 UTC (permalink / raw)
  To: linux-erofs; +Cc: Gao Xiang

This keeps in sync with the kernel definition.

Signed-off-by: Gao Xiang <xiang@kernel.org>
---
 include/erofs/internal.h |  1 +
 include/erofs_fs.h       | 25 ++++++++++++++++++++-----
 2 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 6e481faa8c9f..1339341a0792 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -108,6 +108,7 @@ static inline void erofs_sb_clear_##name(void) \
 
 EROFS_FEATURE_FUNCS(lz4_0padding, incompat, INCOMPAT_LZ4_0PADDING)
 EROFS_FEATURE_FUNCS(compr_cfgs, incompat, INCOMPAT_COMPR_CFGS)
+EROFS_FEATURE_FUNCS(big_pcluster, incompat, INCOMPAT_BIG_PCLUSTER)
 EROFS_FEATURE_FUNCS(sb_chksum, compat, COMPAT_SB_CHKSUM)
 
 #define EROFS_I_EA_INITED	(1 << 0)
diff --git a/include/erofs_fs.h b/include/erofs_fs.h
index a24deb095537..52da7abaac92 100644
--- a/include/erofs_fs.h
+++ b/include/erofs_fs.h
@@ -21,9 +21,11 @@
  */
 #define EROFS_FEATURE_INCOMPAT_LZ4_0PADDING	0x00000001
 #define EROFS_FEATURE_INCOMPAT_COMPR_CFGS	0x00000002
+#define EROFS_FEATURE_INCOMPAT_BIG_PCLUSTER	0x00000002
 #define EROFS_ALL_FEATURE_INCOMPAT		\
 	(EROFS_FEATURE_INCOMPAT_LZ4_0PADDING | \
-	 EROFS_FEATURE_INCOMPAT_COMPR_CFGS)
+	 EROFS_FEATURE_INCOMPAT_COMPR_CFGS | \
+	 EROFS_FEATURE_INCOMPAT_BIG_PCLUSTER)
 
 /* 128-byte erofs on-disk super block */
 struct erofs_super_block {
@@ -199,6 +201,9 @@ static inline unsigned int erofs_xattr_entry_size(struct erofs_xattr_entry *e)
 				 e->e_name_len + le16_to_cpu(e->e_value_size));
 }
 
+/* maximum supported size of a physical compression cluster */
+#define Z_EROFS_PCLUSTER_MAX_SIZE	(1024 * 1024)
+
 /* available compression algorithm types (for h_algorithmtype) */
 enum {
 	Z_EROFS_COMPRESSION_LZ4	= 0,
@@ -208,17 +213,20 @@ enum {
 /* 14 bytes (+ length field = 16 bytes) */
 struct z_erofs_lz4_cfgs {
 	__le16 max_distance;
-	u8 reserved[12];
+	__le16 max_pclusterblks;
+	u8 reserved[10];
 } __packed;
 
 /*
  * bit 0 : COMPACTED_2B indexes (0 - off; 1 - on)
  *  e.g. for 4k logical cluster size,      4B        if compacted 2B is off;
  *                                  (4B) + 2B + (4B) if compacted 2B is on.
+ * bit 1 : HEAD1 big pcluster (0 - off; 1 - on)
+ * bit 2 : HEAD2 big pcluster (0 - off; 1 - on)
  */
-#define Z_EROFS_ADVISE_COMPACTED_2B_BIT         0
-
-#define Z_EROFS_ADVISE_COMPACTED_2B     (1 << Z_EROFS_ADVISE_COMPACTED_2B_BIT)
+#define Z_EROFS_ADVISE_COMPACTED_2B		0x0001
+#define Z_EROFS_ADVISE_BIG_PCLUSTER_1		0x0002
+#define Z_EROFS_ADVISE_BIG_PCLUSTER_2		0x0004
 
 struct z_erofs_map_header {
 	__le32	h_reserved1;
@@ -275,6 +283,13 @@ enum {
 #define Z_EROFS_VLE_DI_CLUSTER_TYPE_BITS        2
 #define Z_EROFS_VLE_DI_CLUSTER_TYPE_BIT         0
 
+/*
+ * D0_CBLKCNT will be marked _only_ at the 1st non-head lcluster to store the
+ * compressed block count of a compressed extent (in logical clusters, aka.
+ * block count of a pcluster).
+ */
+#define Z_EROFS_VLE_DI_D0_CBLKCNT		(1 << 11)
+
 struct z_erofs_vle_decompressed_index {
 	__le16 di_advise;
 	/* where to decompress in the head cluster */
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 5/8] erofs-utils: fuse: support multiple block compression
  2021-04-11  3:48 [PATCH 0/8] erofs-utils: support big pcluster compression Gao Xiang
                   ` (3 preceding siblings ...)
  2021-04-11  3:48 ` [PATCH 4/8] erofs-utils: add big physical cluster definition Gao Xiang
@ 2021-04-11  3:48 ` Gao Xiang
  2021-04-11  3:48 ` [PATCH 6/8] erofs-utils: mkfs: " Gao Xiang
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Gao Xiang @ 2021-04-11  3:48 UTC (permalink / raw)
  To: linux-erofs; +Cc: Gao Xiang

Add multiple block compression runtime support for erofsfuse.

Signed-off-by: Gao Xiang <xiang@kernel.org>
---
 lib/data.c |  4 +--
 lib/zmap.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 68 insertions(+), 8 deletions(-)

diff --git a/lib/data.c b/lib/data.c
index 56de16b3c840..31d81f3c8a2a 100644
--- a/lib/data.c
+++ b/lib/data.c
@@ -130,7 +130,7 @@ static int z_erofs_read_data(struct erofs_inode *inode, char *buffer,
 	};
 	bool partial;
 	unsigned int algorithmformat;
-	char raw[EROFS_BLKSIZ];
+	char raw[Z_EROFS_PCLUSTER_MAX_SIZE];
 
 	end = offset + size;
 	while (end > offset) {
@@ -167,7 +167,7 @@ static int z_erofs_read_data(struct erofs_inode *inode, char *buffer,
 			continue;
 		}
 
-		ret = dev_read(raw, map.m_pa, EROFS_BLKSIZ);
+		ret = dev_read(raw, map.m_pa, map.m_plen);
 		if (ret < 0)
 			return -EIO;
 
diff --git a/lib/zmap.c b/lib/zmap.c
index ee63de74cab2..096fd35cdeb3 100644
--- a/lib/zmap.c
+++ b/lib/zmap.c
@@ -14,7 +14,8 @@
 
 int z_erofs_fill_inode(struct erofs_inode *vi)
 {
-	if (vi->datalayout == EROFS_INODE_FLAT_COMPRESSION_LEGACY) {
+	if (!erofs_sb_has_big_pcluster() &&
+	    vi->datalayout == EROFS_INODE_FLAT_COMPRESSION_LEGACY) {
 		vi->z_advise = 0;
 		vi->z_algorithmtype[0] = 0;
 		vi->z_algorithmtype[1] = 0;
@@ -37,7 +38,8 @@ static int z_erofs_fill_inode_lazy(struct erofs_inode *vi)
 	if (vi->flags & EROFS_I_Z_INITED)
 		return 0;
 
-	DBG_BUGON(vi->datalayout == EROFS_INODE_FLAT_COMPRESSION_LEGACY);
+	DBG_BUGON(!erofs_sb_has_big_pcluster() &&
+		  vi->datalayout == EROFS_INODE_FLAT_COMPRESSION_LEGACY);
 	pos = round_up(iloc(vi->nid) + vi->inode_isize + vi->xattr_isize, 8);
 
 	ret = dev_read(buf, pos, sizeof(buf));
@@ -81,7 +83,7 @@ struct z_erofs_maprecorder {
 	u8  type;
 	u16 clusterofs;
 	u16 delta[2];
-	erofs_blk_t pblk;
+	erofs_blk_t pblk, compressedlcs;
 };
 
 static int z_erofs_reload_indexes(struct z_erofs_maprecorder *m,
@@ -130,6 +132,15 @@ static int legacy_load_cluster_from_disk(struct z_erofs_maprecorder *m,
 	case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
 		m->clusterofs = 1 << vi->z_logical_clusterbits;
 		m->delta[0] = le16_to_cpu(di->di_u.delta[0]);
+		if (m->delta[0] & Z_EROFS_VLE_DI_D0_CBLKCNT) {
+			if (!(vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1)) {
+				DBG_BUGON(1);
+				return -EFSCORRUPTED;
+			}
+			m->compressedlcs = m->delta[0] &
+				~Z_EROFS_VLE_DI_D0_CBLKCNT;
+			m->delta[0] = 1;
+		}
 		m->delta[1] = le16_to_cpu(di->di_u.delta[1]);
 		break;
 	case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
@@ -333,6 +344,51 @@ static int z_erofs_extent_lookback(struct z_erofs_maprecorder *m,
 	return 0;
 }
 
+static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m,
+					    unsigned int initial_lcn)
+{
+	struct erofs_inode *const vi = m->inode;
+	struct erofs_map_blocks *const map = m->map;
+	const unsigned int lclusterbits = vi->z_logical_clusterbits;
+	unsigned long lcn;
+	int err;
+
+	DBG_BUGON(m->type != Z_EROFS_VLE_CLUSTER_TYPE_PLAIN &&
+		  m->type != Z_EROFS_VLE_CLUSTER_TYPE_HEAD);
+	if (!((map->m_flags & EROFS_MAP_ZIPPED) &&
+	      (vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1))) {
+		map->m_plen = 1 << lclusterbits;
+		return 0;
+	}
+
+	lcn = m->lcn + 1;
+	if (lcn == initial_lcn && !m->compressedlcs)
+		m->compressedlcs = 2;
+
+	if (m->compressedlcs)
+		goto out;
+
+	err = z_erofs_load_cluster_from_disk(m, lcn);
+	if (err)
+		return err;
+
+	switch (m->type) {
+	case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
+		DBG_BUGON(m->delta[0] != 1);
+		if (m->compressedlcs) {
+			break;
+		}
+	default:
+		erofs_err("cannot found CBLKCNT @ lcn %lu of nid %llu",
+			  lcn, (unsigned long long)vi->nid);
+		DBG_BUGON(1);
+		return -EFSCORRUPTED;
+	}
+out:
+	map->m_plen = m->compressedlcs << lclusterbits;
+	return 0;
+}
+
 int z_erofs_map_blocks_iter(struct erofs_inode *vi,
 			    struct erofs_map_blocks *map)
 {
@@ -343,6 +399,7 @@ int z_erofs_map_blocks_iter(struct erofs_inode *vi,
 	};
 	int err = 0;
 	unsigned int lclusterbits, endoff;
+	unsigned long initial_lcn;
 	unsigned long long ofs, end;
 
 	/* when trying to read beyond EOF, leave it unmapped */
@@ -359,10 +416,10 @@ int z_erofs_map_blocks_iter(struct erofs_inode *vi,
 
 	lclusterbits = vi->z_logical_clusterbits;
 	ofs = map->m_la;
-	m.lcn = ofs >> lclusterbits;
+	initial_lcn = ofs >> lclusterbits;
 	endoff = ofs & ((1 << lclusterbits) - 1);
 
-	err = z_erofs_load_cluster_from_disk(&m, m.lcn);
+	err = z_erofs_load_cluster_from_disk(&m, initial_lcn);
 	if (err)
 		goto out;
 
@@ -401,8 +458,11 @@ int z_erofs_map_blocks_iter(struct erofs_inode *vi,
 	}
 
 	map->m_llen = end - map->m_la;
-	map->m_plen = 1 << lclusterbits;
 	map->m_pa = blknr_to_addr(m.pblk);
+
+	err = z_erofs_get_extent_compressedlen(&m, initial_lcn);
+	if (err)
+		goto out;
 	map->m_flags |= EROFS_MAP_MAPPED;
 
 out:
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 6/8] erofs-utils: mkfs: support multiple block compression
  2021-04-11  3:48 [PATCH 0/8] erofs-utils: support big pcluster compression Gao Xiang
                   ` (4 preceding siblings ...)
  2021-04-11  3:48 ` [PATCH 5/8] erofs-utils: fuse: support multiple block compression Gao Xiang
@ 2021-04-11  3:48 ` Gao Xiang
  2021-04-11  3:48 ` [PATCH 7/8] erofs-utils: fuse: support compact indexes for bigpcluster Gao Xiang
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Gao Xiang @ 2021-04-11  3:48 UTC (permalink / raw)
  To: linux-erofs; +Cc: Gao Xiang

Store compressed block count to the compressed index so that EROFS
can compress from variable-sized input to variable-sized compressed
blocks and make the in-place decompression possible as well.

Signed-off-by: Gao Xiang <xiang@kernel.org>
---
 lib/compress.c | 77 ++++++++++++++++++++++++++++++++++----------------
 1 file changed, 53 insertions(+), 24 deletions(-)

diff --git a/lib/compress.c b/lib/compress.c
index c991c13dfd1a..c8b627db5bec 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -29,8 +29,8 @@ struct z_erofs_vle_compress_ctx {
 
 	u8 queue[EROFS_CONFIG_COMPR_MAX_SZ * 2];
 	unsigned int head, tail;
-
-	erofs_blk_t blkaddr;	/* pointing to the next blkaddr */
+	unsigned int compressedblks;
+	erofs_blk_t blkaddr;		/* pointing to the next blkaddr */
 	u16 clusterofs;
 };
 
@@ -89,7 +89,13 @@ static void vle_write_indexes(struct z_erofs_vle_compress_ctx *ctx,
 	}
 
 	do {
-		if (d0) {
+		/* XXX: big pcluster feature should be per-inode */
+		if (d0 == 1 && cfg.c_physical_clusterblks > 1) {
+			type = Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD;
+			di.di_u.delta[0] = cpu_to_le16(ctx->compressedblks |
+					Z_EROFS_VLE_DI_D0_CBLKCNT);
+			di.di_u.delta[1] = cpu_to_le16(d1);
+		} else if (d0) {
 			type = Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD;
 
 			di.di_u.delta[0] = cpu_to_le16(d0);
@@ -115,9 +121,8 @@ static void vle_write_indexes(struct z_erofs_vle_compress_ctx *ctx,
 	ctx->clusterofs = clusterofs + count;
 }
 
-static int write_uncompressed_block(struct z_erofs_vle_compress_ctx *ctx,
-				    unsigned int *len,
-				    char *dst)
+static int write_uncompressed_extent(struct z_erofs_vle_compress_ctx *ctx,
+				     unsigned int *len, char *dst)
 {
 	int ret;
 	unsigned int count;
@@ -148,17 +153,19 @@ static int vle_compress_one(struct erofs_inode *inode,
 			    struct z_erofs_vle_compress_ctx *ctx,
 			    bool final)
 {
+	const unsigned int pclusterblks = cfg.c_physical_clusterblks;
+	const unsigned int pclustersize = pclusterblks * EROFS_BLKSIZ;
 	struct erofs_compress *const h = &compresshandle;
 	unsigned int len = ctx->tail - ctx->head;
 	unsigned int count;
 	int ret;
-	static char dstbuf[EROFS_BLKSIZ * 2];
+	static char dstbuf[EROFS_CONFIG_COMPR_MAX_SZ + EROFS_BLKSIZ];
 	char *const dst = dstbuf + EROFS_BLKSIZ;
 
 	while (len) {
 		bool raw;
 
-		if (len <= EROFS_BLKSIZ) {
+		if (len <= pclustersize) {
 			if (final)
 				goto nocompression;
 			break;
@@ -167,7 +174,7 @@ static int vle_compress_one(struct erofs_inode *inode,
 		count = len;
 		ret = erofs_compress_destsize(h, compressionlevel,
 					      ctx->queue + ctx->head,
-					      &count, dst, EROFS_BLKSIZ);
+					      &count, dst, pclustersize);
 		if (ret <= 0) {
 			if (ret != -EAGAIN) {
 				erofs_err("failed to compress %s: %s",
@@ -175,32 +182,36 @@ static int vle_compress_one(struct erofs_inode *inode,
 					  erofs_strerror(ret));
 			}
 nocompression:
-			ret = write_uncompressed_block(ctx, &len, dst);
+			ret = write_uncompressed_extent(ctx, &len, dst);
 			if (ret < 0)
 				return ret;
 			count = ret;
+			ctx->compressedblks = 1;
 			raw = true;
 		} else {
-			/* write compressed data */
-			erofs_dbg("Writing %u compressed data to block %u",
-				  count, ctx->blkaddr);
+			const unsigned int used = ret & (EROFS_BLKSIZ - 1);
+			const unsigned int margin =
+				erofs_sb_has_lz4_0padding() && used ?
+					EROFS_BLKSIZ - used : 0;
 
-			if (erofs_sb_has_lz4_0padding())
-				ret = blk_write(dst - (EROFS_BLKSIZ - ret),
-						ctx->blkaddr, 1);
-			else
-				ret = blk_write(dst, ctx->blkaddr, 1);
+			ctx->compressedblks = DIV_ROUND_UP(ret, EROFS_BLKSIZ);
 
+			/* write compressed data */
+			erofs_dbg("Writing %u compressed data to %u of %u blocks",
+				  count, ctx->blkaddr, ctx->compressedblks);
+
+			ret = blk_write(dst - margin, ctx->blkaddr,
+					ctx->compressedblks);
 			if (ret)
 				return ret;
 			raw = false;
 		}
 
 		ctx->head += count;
-		/* write compression indexes for this blkaddr */
+		/* write compression indexes for this pcluster */
 		vle_write_indexes(ctx, count, raw);
 
-		++ctx->blkaddr;
+		ctx->blkaddr += ctx->compressedblks;
 		len -= count;
 
 		if (!final && ctx->head >= EROFS_CONFIG_COMPR_MAX_SZ) {
@@ -345,8 +356,6 @@ int z_erofs_convert_to_compacted_format(struct erofs_inode *inode,
 
 	out = in = inode->compressmeta;
 
-	/* write out compacted header */
-	memcpy(out, &mapheader, sizeof(mapheader));
 	out += sizeof(mapheader);
 	in += Z_EROFS_LEGACY_MAP_HEADER_SIZE;
 
@@ -415,6 +424,8 @@ int erofs_write_compressed_file(struct erofs_inode *inode)
 	}
 
 	memset(compressmeta, 0, Z_EROFS_LEGACY_MAP_HEADER_SIZE);
+	/* write out compressed header */
+	memcpy(compressmeta, &mapheader, sizeof(mapheader));
 
 	blkaddr = erofs_mapbh(bh->block);	/* start_blkaddr */
 	ctx.blkaddr = blkaddr;
@@ -474,7 +485,8 @@ int erofs_write_compressed_file(struct erofs_inode *inode)
 	inode->u.i_blocks = compressed_blocks;
 
 	legacymetasize = ctx.metacur - compressmeta;
-	if (cfg.c_legacy_compress) {
+	/* XXX: temporarily use legacy index instead for mbpcluster */
+	if (cfg.c_legacy_compress || cfg.c_physical_clusterblks > 1) {
 		inode->extent_isize = legacymetasize;
 		inode->datalayout = EROFS_INODE_FLAT_COMPRESSION_LEGACY;
 	} else {
@@ -514,6 +526,7 @@ int z_erofs_build_compr_cfgs(struct erofs_buffer_head *sb_bh)
 			.lz4 = {
 				.max_distance =
 					cpu_to_le16(sbi.lz4_max_distance),
+				.max_pclusterblks = cfg.c_physical_clusterblks,
 			}
 		};
 
@@ -562,7 +575,23 @@ int z_erofs_compress_init(struct erofs_buffer_head *sb_bh)
 
 	algorithmtype[0] = ret;	/* primary algorithm (head 0) */
 	algorithmtype[1] = 0;	/* secondary algorithm (head 1) */
-	mapheader.h_advise |= Z_EROFS_ADVISE_COMPACTED_2B;
+	mapheader.h_advise = 0;
+	if (!cfg.c_legacy_compress)
+		mapheader.h_advise |= Z_EROFS_ADVISE_COMPACTED_2B;
+	/*
+	 * if big pcluster is enabled, an extra CBLKCNT lcluster index needs
+	 * to be loaded in order to get those compressed block counts.
+	 */
+	if (cfg.c_physical_clusterblks > 1) {
+		if (cfg.c_physical_clusterblks >
+		    Z_EROFS_PCLUSTER_MAX_SIZE / EROFS_BLKSIZ) {
+			erofs_err("unsupported clusterblks %u (too large)",
+				  cfg.c_physical_clusterblks);
+			return -EINVAL;
+		}
+		erofs_sb_set_big_pcluster();
+		mapheader.h_advise |= Z_EROFS_ADVISE_BIG_PCLUSTER_1;
+	}
 	mapheader.h_algorithmtype = algorithmtype[1] << 4 |
 					  algorithmtype[0];
 	mapheader.h_clusterbits = LOG_BLOCK_SIZE - 12;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 7/8] erofs-utils: fuse: support compact indexes for bigpcluster
  2021-04-11  3:48 [PATCH 0/8] erofs-utils: support big pcluster compression Gao Xiang
                   ` (5 preceding siblings ...)
  2021-04-11  3:48 ` [PATCH 6/8] erofs-utils: mkfs: " Gao Xiang
@ 2021-04-11  3:48 ` Gao Xiang
  2021-04-11  3:48 ` [PATCH 8/8] erofs-utils: mkfs: " Gao Xiang
  2021-04-15  3:27 ` [PATCH v1.1 1/8] erofs-utils: support adjust lz4 history window size Gao Xiang
  8 siblings, 0 replies; 10+ messages in thread
From: Gao Xiang @ 2021-04-11  3:48 UTC (permalink / raw)
  To: linux-erofs; +Cc: Gao Xiang

Add big pcluster compact indexes runtime support for erofsfuse,
which keeps in sync with kernel side.

Signed-off-by: Gao Xiang <xiang@kernel.org>
---
 lib/zmap.c | 64 +++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 54 insertions(+), 10 deletions(-)

diff --git a/lib/zmap.c b/lib/zmap.c
index 096fd35cdeb3..e2a54b937b7c 100644
--- a/lib/zmap.c
+++ b/lib/zmap.c
@@ -58,6 +58,14 @@ static int z_erofs_fill_inode_lazy(struct erofs_inode *vi)
 	}
 
 	vi->z_logical_clusterbits = LOG_BLOCK_SIZE + (h->h_clusterbits & 7);
+	if (vi->datalayout == EROFS_INODE_FLAT_COMPRESSION &&
+	    !(vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1) ^
+	    !(vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_2)) {
+		erofs_err(
+"big pcluster head1/2 of compact indexes should be consistent for nid %llu",
+			  vi->nid * 1ULL);
+		return -EFSCORRUPTED;
+	}
 	vi->z_physical_clusterbits[0] = vi->z_logical_clusterbits +
 					((h->h_clusterbits >> 3) & 3);
 
@@ -177,6 +185,7 @@ static int unpack_compacted_index(struct z_erofs_maprecorder *m,
 	unsigned int vcnt, base, lo, encodebits, nblk;
 	int i;
 	u8 *in, type;
+	bool big_pcluster;
 
 	if (1 << amortizedshift == 4)
 		vcnt = 2;
@@ -185,6 +194,7 @@ static int unpack_compacted_index(struct z_erofs_maprecorder *m,
 	else
 		return -EOPNOTSUPP;
 
+	big_pcluster = vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1;
 	encodebits = ((vcnt << amortizedshift) - sizeof(__le32)) * 8 / vcnt;
 	base = round_down(eofs, vcnt << amortizedshift);
 	in = m->kaddr + base;
@@ -196,7 +206,15 @@ static int unpack_compacted_index(struct z_erofs_maprecorder *m,
 	m->type = type;
 	if (type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) {
 		m->clusterofs = 1 << lclusterbits;
-		if (i + 1 != (int)vcnt) {
+		if (lo & Z_EROFS_VLE_DI_D0_CBLKCNT) {
+			if (!big_pcluster) {
+				DBG_BUGON(1);
+				return -EFSCORRUPTED;
+			}
+			m->compressedlcs = lo & ~Z_EROFS_VLE_DI_D0_CBLKCNT;
+			m->delta[0] = 1;
+			return 0;
+		} else if (i + 1 != (int)vcnt) {
 			m->delta[0] = lo;
 			return 0;
 		}
@@ -209,22 +227,48 @@ static int unpack_compacted_index(struct z_erofs_maprecorder *m,
 					  in, encodebits * (i - 1), &type);
 		if (type != Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD)
 			lo = 0;
+		else if (lo & Z_EROFS_VLE_DI_D0_CBLKCNT)
+			lo = 1;
 		m->delta[0] = lo + 1;
 		return 0;
 	}
 	m->clusterofs = lo;
 	m->delta[0] = 0;
 	/* figout out blkaddr (pblk) for HEAD lclusters */
-	nblk = 1;
-	while (i > 0) {
-		--i;
-		lo = decode_compactedbits(lclusterbits, lomask,
-					  in, encodebits * i, &type);
-		if (type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD)
-			i -= lo;
-
-		if (i >= 0)
+	if (!big_pcluster) {
+		nblk = 1;
+		while (i > 0) {
+			--i;
+			lo = decode_compactedbits(lclusterbits, lomask,
+						  in, encodebits * i, &type);
+			if (type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD)
+				i -= lo;
+
+			if (i >= 0)
+				++nblk;
+		}
+	} else {
+		nblk = 0;
+		while (i > 0) {
+			--i;
+			lo = decode_compactedbits(lclusterbits, lomask,
+						  in, encodebits * i, &type);
+			if (type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) {
+				if (lo & Z_EROFS_VLE_DI_D0_CBLKCNT) {
+					--i;
+					nblk += lo & ~Z_EROFS_VLE_DI_D0_CBLKCNT;
+					continue;
+				}
+				if (lo == 1) {
+					DBG_BUGON(1);
+					/* --i; ++nblk;	continue; */
+					return -EFSCORRUPTED;
+				}
+				i -= lo - 2;
+				continue;
+			}
 			++nblk;
+		}
 	}
 	in += (vcnt << amortizedshift) - sizeof(__le32);
 	m->pblk = le32_to_cpu(*(__le32 *)in) + nblk;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 8/8] erofs-utils: mkfs: support compact indexes for bigpcluster
  2021-04-11  3:48 [PATCH 0/8] erofs-utils: support big pcluster compression Gao Xiang
                   ` (6 preceding siblings ...)
  2021-04-11  3:48 ` [PATCH 7/8] erofs-utils: fuse: support compact indexes for bigpcluster Gao Xiang
@ 2021-04-11  3:48 ` Gao Xiang
  2021-04-15  3:27 ` [PATCH v1.1 1/8] erofs-utils: support adjust lz4 history window size Gao Xiang
  8 siblings, 0 replies; 10+ messages in thread
From: Gao Xiang @ 2021-04-11  3:48 UTC (permalink / raw)
  To: linux-erofs; +Cc: Gao Xiang

This adds support to generate big pcluster compact indexes.

Different from non big pcluster, blkaddr recorded in each pack is
the 1st pcluster blkaddr with a valid CBLKCNT since we don't know
compressed block count of each pcluster when reading HEAD lcluster.

For more details, also see related kernel commits.

Signed-off-by: Gao Xiang <xiang@kernel.org>
---
 lib/compress.c | 52 ++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 40 insertions(+), 12 deletions(-)

diff --git a/lib/compress.c b/lib/compress.c
index c8b627db5bec..654286d3f33e 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -267,9 +267,10 @@ static void *write_compacted_indexes(u8 *out,
 				     erofs_blk_t *blkaddr_ret,
 				     unsigned int destsize,
 				     unsigned int logical_clusterbits,
-				     bool final)
+				     bool final, bool *dummy_head)
 {
-	unsigned int vcnt, encodebits, pos, i;
+	unsigned int vcnt, encodebits, pos, i, cblks;
+	bool update_blkaddr;
 	erofs_blk_t blkaddr;
 
 	if (destsize == 4) {
@@ -281,6 +282,7 @@ static void *write_compacted_indexes(u8 *out,
 	}
 	encodebits = (vcnt * destsize * 8 - 32) / vcnt;
 	blkaddr = *blkaddr_ret;
+	update_blkaddr = erofs_sb_has_big_pcluster();
 
 	pos = 0;
 	for (i = 0; i < vcnt; ++i) {
@@ -288,13 +290,26 @@ static void *write_compacted_indexes(u8 *out,
 		u8 ch, rem;
 
 		if (cv[i].clustertype == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) {
-			if (i + 1 == vcnt)
+			if (cv[i].u.delta[0] & Z_EROFS_VLE_DI_D0_CBLKCNT) {
+				cblks = cv[i].u.delta[0] & ~Z_EROFS_VLE_DI_D0_CBLKCNT;
+				offset = cv[i].u.delta[0];
+				blkaddr += cblks;
+				*dummy_head = false;
+			} else if (i + 1 == vcnt) {
 				offset = cv[i].u.delta[1];
-			else
+			} else {
 				offset = cv[i].u.delta[0];
+			}
 		} else {
 			offset = cv[i].clusterofs;
-			++blkaddr;
+			if (*dummy_head) {
+				++blkaddr;
+				if (update_blkaddr)
+					*blkaddr_ret = blkaddr;
+			}
+			*dummy_head = true;
+			update_blkaddr = false;
+
 			if (cv[i].u.blkaddr != blkaddr) {
 				if (i + 1 != vcnt)
 					DBG_BUGON(!final);
@@ -330,6 +345,7 @@ int z_erofs_convert_to_compacted_format(struct erofs_inode *inode,
 	/* # of 8-byte units so that it can be aligned with 32 bytes */
 	unsigned int compacted_4b_initial, compacted_4b_end;
 	unsigned int compacted_2b;
+	bool dummy_head;
 
 	if (logical_clusterbits < LOG_BLOCK_SIZE || LOG_BLOCK_SIZE < 12)
 		return -EINVAL;
@@ -359,11 +375,19 @@ int z_erofs_convert_to_compacted_format(struct erofs_inode *inode,
 	out += sizeof(mapheader);
 	in += Z_EROFS_LEGACY_MAP_HEADER_SIZE;
 
+	dummy_head = false;
+	/* prior to bigpcluster, blkaddr was bumped up once coming into HEAD */
+	if (!erofs_sb_has_big_pcluster()) {
+		--blkaddr;
+		dummy_head = true;
+	}
+
 	/* generate compacted_4b_initial */
 	while (compacted_4b_initial) {
 		in = parse_legacy_indexes(cv, 2, in);
 		out = write_compacted_indexes(out, cv, &blkaddr,
-					      4, logical_clusterbits, false);
+					      4, logical_clusterbits, false,
+					      &dummy_head);
 		compacted_4b_initial -= 2;
 	}
 	DBG_BUGON(compacted_4b_initial);
@@ -372,7 +396,8 @@ int z_erofs_convert_to_compacted_format(struct erofs_inode *inode,
 	while (compacted_2b) {
 		in = parse_legacy_indexes(cv, 16, in);
 		out = write_compacted_indexes(out, cv, &blkaddr,
-					      2, logical_clusterbits, false);
+					      2, logical_clusterbits, false,
+					      &dummy_head);
 		compacted_2b -= 16;
 	}
 	DBG_BUGON(compacted_2b);
@@ -381,7 +406,8 @@ int z_erofs_convert_to_compacted_format(struct erofs_inode *inode,
 	while (compacted_4b_end > 1) {
 		in = parse_legacy_indexes(cv, 2, in);
 		out = write_compacted_indexes(out, cv, &blkaddr,
-					      4, logical_clusterbits, false);
+					      4, logical_clusterbits, false,
+					      &dummy_head);
 		compacted_4b_end -= 2;
 	}
 
@@ -390,7 +416,8 @@ int z_erofs_convert_to_compacted_format(struct erofs_inode *inode,
 		memset(cv, 0, sizeof(cv));
 		in = parse_legacy_indexes(cv, 1, in);
 		out = write_compacted_indexes(out, cv, &blkaddr,
-					      4, logical_clusterbits, true);
+					      4, logical_clusterbits, true,
+					      &dummy_head);
 	}
 	inode->extent_isize = out - (u8 *)inode->compressmeta;
 	inode->datalayout = EROFS_INODE_FLAT_COMPRESSION;
@@ -485,12 +512,11 @@ int erofs_write_compressed_file(struct erofs_inode *inode)
 	inode->u.i_blocks = compressed_blocks;
 
 	legacymetasize = ctx.metacur - compressmeta;
-	/* XXX: temporarily use legacy index instead for mbpcluster */
-	if (cfg.c_legacy_compress || cfg.c_physical_clusterblks > 1) {
+	if (cfg.c_legacy_compress) {
 		inode->extent_isize = legacymetasize;
 		inode->datalayout = EROFS_INODE_FLAT_COMPRESSION_LEGACY;
 	} else {
-		ret = z_erofs_convert_to_compacted_format(inode, blkaddr - 1,
+		ret = z_erofs_convert_to_compacted_format(inode, blkaddr,
 							  legacymetasize, 12);
 		DBG_BUGON(ret);
 	}
@@ -591,6 +617,8 @@ int z_erofs_compress_init(struct erofs_buffer_head *sb_bh)
 		}
 		erofs_sb_set_big_pcluster();
 		mapheader.h_advise |= Z_EROFS_ADVISE_BIG_PCLUSTER_1;
+		if (!cfg.c_legacy_compress)
+			mapheader.h_advise |= Z_EROFS_ADVISE_BIG_PCLUSTER_2;
 	}
 	mapheader.h_algorithmtype = algorithmtype[1] << 4 |
 					  algorithmtype[0];
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v1.1 1/8] erofs-utils: support adjust lz4 history window size
  2021-04-11  3:48 [PATCH 0/8] erofs-utils: support big pcluster compression Gao Xiang
                   ` (7 preceding siblings ...)
  2021-04-11  3:48 ` [PATCH 8/8] erofs-utils: mkfs: " Gao Xiang
@ 2021-04-15  3:27 ` Gao Xiang
  8 siblings, 0 replies; 10+ messages in thread
From: Gao Xiang @ 2021-04-15  3:27 UTC (permalink / raw)
  To: linux-erofs; +Cc: Gao Xiang, Guo Weichao

From: Huang Jianan <huangjianan@oppo.com>

lz4 uses LZ4_DISTANCE_MAX to record history preservation. When
using rolling decompression, a block with a higher compression
ratio will cause a larger memory allocation (up to 64k). It may
cause a large resource burden in extreme cases on devices with
small memory and a large number of concurrent IOs. So appropriately
reducing this value can improve performance.

Decreasing this value will reduce the compression ratio (except
when input_size <LZ4_DISTANCE_MAX). But considering that erofs
currently only supports 4k output, reducing this value will not
significantly reduce the compression benefits.

The maximum value of LZ4_DISTANCE_MAX defined by lz4 is 64k, and
we can only reduce this value. For the old kernel, it just can't
reduce the memory allocation during rolling decompression without
affecting the decompression result.

Signed-off-by: Huang Jianan <huangjianan@oppo.com>
Signed-off-by: Guo Weichao <guoweichao@oppo.com>
Signed-off-by: Gao Xiang <xiang@kernel.org>
---
changes since v1:
 - fix missing LZ4_DISTANCE_MAX definition for lz4hc reported
   by travis CI.

 include/erofs/internal.h | 1 +
 include/erofs_fs.h       | 3 ++-
 lib/compressor_lz4.c     | 5 +++++
 lib/compressor_lz4hc.c   | 6 ++++++
 mkfs/main.c              | 1 +
 5 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index ac5b270329e2..3849980d8eab 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -79,6 +79,7 @@ struct erofs_sb_info {
 	u64 inos;
 
 	u8 uuid[16];
+	u16 lz4_max_distance;
 };
 
 /* global sbi */
diff --git a/include/erofs_fs.h b/include/erofs_fs.h
index a69f179a51a5..ae2305c1eb79 100644
--- a/include/erofs_fs.h
+++ b/include/erofs_fs.h
@@ -41,7 +41,8 @@ struct erofs_super_block {
 	__u8 uuid[16];          /* 128-bit uuid for volume */
 	__u8 volume_name[16];   /* volume name */
 	__le32 feature_incompat;
-	__u8 reserved2[44];
+	__le16 lz4_max_distance;
+	__u8 reserved2[42];
 };
 
 /*
diff --git a/lib/compressor_lz4.c b/lib/compressor_lz4.c
index 8540a0d01cbb..292d0f27fe0e 100644
--- a/lib/compressor_lz4.c
+++ b/lib/compressor_lz4.c
@@ -10,6 +10,10 @@
 #include "erofs/internal.h"
 #include "compressor.h"
 
+#ifndef LZ4_DISTANCE_MAX	/* history window size */
+#define LZ4_DISTANCE_MAX 65535	/* set to maximum value by default */
+#endif
+
 static int lz4_compress_destsize(struct erofs_compress *c,
 				 int compression_level,
 				 void *src, unsigned int *srcsize,
@@ -32,6 +36,7 @@ static int compressor_lz4_exit(struct erofs_compress *c)
 static int compressor_lz4_init(struct erofs_compress *c)
 {
 	c->alg = &erofs_compressor_lz4;
+	sbi.lz4_max_distance = LZ4_DISTANCE_MAX;
 	return 0;
 }
 
diff --git a/lib/compressor_lz4hc.c b/lib/compressor_lz4hc.c
index 6680563986c3..14c3a71b0a80 100644
--- a/lib/compressor_lz4hc.c
+++ b/lib/compressor_lz4hc.c
@@ -11,6 +11,10 @@
 #include "erofs/internal.h"
 #include "compressor.h"
 
+#ifndef LZ4_DISTANCE_MAX	/* history window size */
+#define LZ4_DISTANCE_MAX 65535	/* set to maximum value by default */
+#endif
+
 static int lz4hc_compress_destsize(struct erofs_compress *c,
 				   int compression_level,
 				   void *src,
@@ -44,6 +48,8 @@ static int compressor_lz4hc_init(struct erofs_compress *c)
 	c->private_data = LZ4_createStreamHC();
 	if (!c->private_data)
 		return -ENOMEM;
+
+	sbi.lz4_max_distance = LZ4_DISTANCE_MAX;
 	return 0;
 }
 
diff --git a/mkfs/main.c b/mkfs/main.c
index 6bc179db8dc3..8a9611f0f3d0 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -322,6 +322,7 @@ int erofs_mkfs_update_super_block(struct erofs_buffer_head *bh,
 		.feature_incompat = cpu_to_le32(sbi.feature_incompat),
 		.feature_compat = cpu_to_le32(sbi.feature_compat &
 					      ~EROFS_FEATURE_COMPAT_SB_CHKSUM),
+		.lz4_max_distance = cpu_to_le16(sbi.lz4_max_distance),
 	};
 	const unsigned int sb_blksize =
 		round_up(EROFS_SUPER_END, EROFS_BLKSIZ);
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2021-04-15  3:27 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-11  3:48 [PATCH 0/8] erofs-utils: support big pcluster compression Gao Xiang
2021-04-11  3:48 ` [PATCH 1/8] erofs-utils: support adjust lz4 history window size Gao Xiang
2021-04-11  3:48 ` [PATCH 2/8] erofs-utils: introduce ondisk compression cfgs Gao Xiang
2021-04-11  3:48 ` [PATCH 3/8] erofs-utils: add -C# for the maximum size of pclusters Gao Xiang
2021-04-11  3:48 ` [PATCH 4/8] erofs-utils: add big physical cluster definition Gao Xiang
2021-04-11  3:48 ` [PATCH 5/8] erofs-utils: fuse: support multiple block compression Gao Xiang
2021-04-11  3:48 ` [PATCH 6/8] erofs-utils: mkfs: " Gao Xiang
2021-04-11  3:48 ` [PATCH 7/8] erofs-utils: fuse: support compact indexes for bigpcluster Gao Xiang
2021-04-11  3:48 ` [PATCH 8/8] erofs-utils: mkfs: " Gao Xiang
2021-04-15  3:27 ` [PATCH v1.1 1/8] erofs-utils: support adjust lz4 history window size Gao Xiang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).