From: Gao Xiang <hsiang...@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 <hsiang...@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