[PATCH] erofs-utils: disallow new algorithms on incremental builds

Gao Xiang xiang at kernel.org
Tue Aug 6 10:08:59 AEST 2024


From: Gao Xiang <hsiangkao at linux.alibaba.com>

On-disk compression configurations are not rewritten on incremental
builds, therefore there is no way to add new algorithms in this mode.

Clean builds should be used instead.

Signed-off-by: Gao Xiang <hsiangkao at linux.alibaba.com>
---
 dump/main.c              |  2 +-
 include/erofs/internal.h | 12 +++++++++---
 lib/compress.c           | 33 ++++++++++++++++++++++++++-------
 lib/compressor_lz4.c     |  3 ++-
 lib/compressor_lz4hc.c   |  3 ++-
 lib/decompress.c         | 34 +++++++++++++++++++++++++++++-----
 lib/super.c              |  2 +-
 7 files changed, 70 insertions(+), 19 deletions(-)

diff --git a/dump/main.c b/dump/main.c
index 06ca4d3..372162e 100644
--- a/dump/main.c
+++ b/dump/main.c
@@ -651,7 +651,7 @@ static void erofsdump_show_superblock(void)
 			g_sbi.available_compr_algs);
 	} else {
 		fprintf(stdout, "Filesystem lz4_max_distance:                  %u\n",
-			g_sbi.lz4_max_distance | 0U);
+			g_sbi.lz4.max_distance | 0U);
 	}
 	fprintf(stdout, "Filesystem sb_size:                           %u\n",
 			g_sbi.sb_size | 0U);
diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 708e51e..2edc1b4 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -66,6 +66,13 @@ struct erofs_device_info {
 	u32 mapped_blkaddr;
 };
 
+/* all filesystem-wide lz4 configurations */
+struct erofs_sb_lz4_info {
+	u16 max_distance;
+	/* maximum possible blocks for pclusters in the filesystem */
+	u16 max_pclusterblks;
+};
+
 struct erofs_xattr_prefix_item {
 	struct erofs_xattr_long_prefix *prefix;
 	u8 infix_len;
@@ -75,6 +82,7 @@ struct erofs_xattr_prefix_item {
 
 struct erofs_mkfs_dfops;
 struct erofs_sb_info {
+	struct erofs_sb_lz4_info lz4;
 	struct erofs_device_info *devs;
 	char *devname;
 
@@ -102,10 +110,8 @@ struct erofs_sb_info {
 	u8 uuid[16];
 	char volume_name[16];
 
-	u16 available_compr_algs;
-	u16 lz4_max_distance;
-
 	u32 checksum;
+	u16 available_compr_algs;
 	u16 extra_devices;
 	union {
 		u16 devt_slotoff;		/* used for mkfs */
diff --git a/lib/compress.c b/lib/compress.c
index 794f714..cea96f4 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -1591,7 +1591,7 @@ static int z_erofs_build_compr_cfgs(struct erofs_sb_info *sbi,
 			.size = cpu_to_le16(sizeof(struct z_erofs_lz4_cfgs)),
 			.lz4 = {
 				.max_distance =
-					cpu_to_le16(sbi->lz4_max_distance),
+					cpu_to_le16(sbi->lz4.max_distance),
 				.max_pclusterblks =
 					cfg.c_mkfs_pclustersize_max >> sbi->blkszbits,
 			}
@@ -1686,6 +1686,7 @@ int z_erofs_compress_init(struct erofs_sb_info *sbi, struct erofs_buffer_head *s
 {
 	int i, ret, id;
 	u32 max_dict_size[Z_EROFS_COMPRESSION_MAX] = {};
+	u32 available_compr_algs = 0;
 
 	for (i = 0; cfg.c_compr_opts[i].alg; ++i) {
 		struct erofs_compress *c = &erofs_ccfg[i].handle;
@@ -1699,7 +1700,7 @@ int z_erofs_compress_init(struct erofs_sb_info *sbi, struct erofs_buffer_head *s
 		id = z_erofs_get_compress_algorithm_id(c);
 		erofs_ccfg[i].algorithmtype = id;
 		erofs_ccfg[i].enable = true;
-		sbi->available_compr_algs |= 1 << erofs_ccfg[i].algorithmtype;
+		available_compr_algs |= 1 << erofs_ccfg[i].algorithmtype;
 		if (erofs_ccfg[i].algorithmtype != Z_EROFS_COMPRESSION_LZ4)
 			erofs_sb_set_compr_cfgs(sbi);
 		if (c->dict_size > max_dict_size[id])
@@ -1710,14 +1711,32 @@ int z_erofs_compress_init(struct erofs_sb_info *sbi, struct erofs_buffer_head *s
 	 * if primary algorithm is empty (e.g. compression off),
 	 * clear 0PADDING feature for old kernel compatibility.
 	 */
-	if (!cfg.c_compr_opts[0].alg ||
-	    (cfg.c_legacy_compress &&
-	     !strncmp(cfg.c_compr_opts[0].alg, "lz4", 3)))
+	if (!available_compr_algs ||
+	    (cfg.c_legacy_compress && available_compr_algs == 1))
 		erofs_sb_clear_lz4_0padding(sbi);
 
-	if (!cfg.c_compr_opts[0].alg)
+	if (!available_compr_algs)
 		return 0;
 
+	if (!sb_bh) {
+		u32 dalg = available_compr_algs & (~sbi->available_compr_algs);
+
+		if (dalg) {
+			erofs_err("unavailable algorithms 0x%x on incremental builds",
+				  dalg);
+			return -EOPNOTSUPP;
+		}
+		if (available_compr_algs & (1 << Z_EROFS_COMPRESSION_LZ4) &&
+		    sbi->lz4.max_pclusterblks << sbi->blkszbits <
+			cfg.c_mkfs_pclustersize_max) {
+			erofs_err("pclustersize %u is too large on incremental builds",
+				  cfg.c_mkfs_pclustersize_max);
+			return -EOPNOTSUPP;
+		}
+	} else {
+		sbi->available_compr_algs = available_compr_algs;
+	}
+
 	/*
 	 * if big pcluster is enabled, an extra CBLKCNT lcluster index needs
 	 * to be loaded in order to get those compressed block counts.
@@ -1736,7 +1755,7 @@ int z_erofs_compress_init(struct erofs_sb_info *sbi, struct erofs_buffer_head *s
 		return -EINVAL;
 	}
 
-	if (erofs_sb_has_compr_cfgs(sbi)) {
+	if (sb_bh && erofs_sb_has_compr_cfgs(sbi)) {
 		ret = z_erofs_build_compr_cfgs(sbi, sb_bh, max_dict_size);
 		if (ret)
 			return ret;
diff --git a/lib/compressor_lz4.c b/lib/compressor_lz4.c
index 5ecfd3e..f3d88b0 100644
--- a/lib/compressor_lz4.c
+++ b/lib/compressor_lz4.c
@@ -32,7 +32,8 @@ static int compressor_lz4_exit(struct erofs_compress *c)
 
 static int compressor_lz4_init(struct erofs_compress *c)
 {
-	c->sbi->lz4_max_distance = LZ4_DISTANCE_MAX;
+	c->sbi->lz4.max_distance = max_t(u16, c->sbi->lz4.max_distance,
+					 LZ4_DISTANCE_MAX);
 	return 0;
 }
 
diff --git a/lib/compressor_lz4hc.c b/lib/compressor_lz4hc.c
index f354b84..1e1ccc7 100644
--- a/lib/compressor_lz4hc.c
+++ b/lib/compressor_lz4hc.c
@@ -43,7 +43,8 @@ static int compressor_lz4hc_init(struct erofs_compress *c)
 	if (!c->private_data)
 		return -ENOMEM;
 
-	c->sbi->lz4_max_distance = LZ4_DISTANCE_MAX;
+	c->sbi->lz4.max_distance = max_t(u16, c->sbi->lz4.max_distance,
+					 LZ4_DISTANCE_MAX);
 	return 0;
 }
 
diff --git a/lib/decompress.c b/lib/decompress.c
index 1e22f9f..1b44a18 100644
--- a/lib/decompress.c
+++ b/lib/decompress.c
@@ -545,6 +545,30 @@ int z_erofs_decompress(struct z_erofs_decompress_req *rq)
 	return -EOPNOTSUPP;
 }
 
+static int z_erofs_load_lz4_config(struct erofs_sb_info *sbi,
+			    struct erofs_super_block *dsb, void *data, int size)
+{
+	struct z_erofs_lz4_cfgs *lz4 = data;
+	u16 distance;
+
+	if (lz4) {
+		if (size < sizeof(struct z_erofs_lz4_cfgs)) {
+			erofs_err("invalid lz4 cfgs, size=%u", size);
+			return -EINVAL;
+		}
+		distance = le16_to_cpu(lz4->max_distance);
+
+		sbi->lz4.max_pclusterblks = le16_to_cpu(lz4->max_pclusterblks);
+		if (!sbi->lz4.max_pclusterblks)
+			sbi->lz4.max_pclusterblks = 1;	/* reserved case */
+	} else {
+		distance = le16_to_cpu(dsb->u1.lz4_max_distance);
+		sbi->lz4.max_pclusterblks = 1;
+	}
+	sbi->lz4.max_distance = distance;
+	return 0;
+}
+
 int z_erofs_parse_cfgs(struct erofs_sb_info *sbi, struct erofs_super_block *dsb)
 {
 	unsigned int algs, alg;
@@ -553,8 +577,7 @@ int z_erofs_parse_cfgs(struct erofs_sb_info *sbi, struct erofs_super_block *dsb)
 
 	if (!erofs_sb_has_compr_cfgs(sbi)) {
 		sbi->available_compr_algs = 1 << Z_EROFS_COMPRESSION_LZ4;
-		sbi->lz4_max_distance = le16_to_cpu(dsb->u1.lz4_max_distance);
-		return 0;
+		return z_erofs_load_lz4_config(sbi, dsb, NULL, 0);
 	}
 
 	sbi->available_compr_algs = le16_to_cpu(dsb->u1.available_compr_algs);
@@ -578,10 +601,11 @@ int z_erofs_parse_cfgs(struct erofs_sb_info *sbi, struct erofs_super_block *dsb)
 			break;
 		}
 
-		if (alg == Z_EROFS_COMPRESSION_DEFLATE)
+		ret = 0;
+		if (alg == Z_EROFS_COMPRESSION_LZ4)
+			ret = z_erofs_load_lz4_config(sbi, dsb, data, size);
+		else if (alg == Z_EROFS_COMPRESSION_DEFLATE)
 			ret = z_erofs_load_deflate_config(sbi, dsb, data, size);
-		else
-			ret = 0;
 		free(data);
 		if (ret)
 			break;
diff --git a/lib/super.c b/lib/super.c
index 45233c4..32e10cd 100644
--- a/lib/super.c
+++ b/lib/super.c
@@ -188,7 +188,7 @@ int erofs_writesb(struct erofs_sb_info *sbi, struct erofs_buffer_head *sb_bh,
 	if (erofs_sb_has_compr_cfgs(sbi))
 		sb.u1.available_compr_algs = cpu_to_le16(sbi->available_compr_algs);
 	else
-		sb.u1.lz4_max_distance = cpu_to_le16(sbi->lz4_max_distance);
+		sb.u1.lz4_max_distance = cpu_to_le16(sbi->lz4.max_distance);
 
 	buf = calloc(sb_blksize, 1);
 	if (!buf) {
-- 
2.30.2



More information about the Linux-erofs mailing list