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);
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;
struct erofs_mkfs_dfops;
struct erofs_sb_info {
+ struct erofs_sb_lz4_info lz4;
struct erofs_device_info *devs;
char *devname;
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 */
.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,
}
{
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;
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])
* 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.
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;
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;
}
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;
}
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;
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);
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;
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) {