diff --git a/Documentation/ABI/testing/sysfs-fs-erofs b/Documentation/ABI/testing/sysfs-fs-erofs index b9243c7f28d7..e4cf6fc6a106 100644 --- a/Documentation/ABI/testing/sysfs-fs-erofs +++ b/Documentation/ABI/testing/sysfs-fs-erofs @@ -3,9 +3,9 @@ Date: November 2021 Contact: "Huang Jianan" Description: Shows all enabled kernel features. Supported features: - zero_padding, compr_cfgs, big_pcluster, chunked_file, - device_table, compr_head2, sb_chksum, ztailpacking, - dedupe, fragments, 48bit, metabox. + compr_cfgs, big_pcluster, chunked_file, device_table, + compr_head2, sb_chksum, ztailpacking, dedupe, fragments, + 48bit, metabox. What: /sys/fs/erofs//sync_decompress Date: November 2021 diff --git a/fs/erofs/decompressor.c b/fs/erofs/decompressor.c index e9d799a03a91..3c54e95964c9 100644 --- a/fs/erofs/decompressor.c +++ b/fs/erofs/decompressor.c @@ -34,7 +34,10 @@ static int z_erofs_load_lz4_config(struct super_block *sb, } } else { distance = le16_to_cpu(dsb->u1.lz4_max_distance); + if (!distance && !erofs_sb_has_lz4_0padding(sbi)) + return 0; sbi->lz4.max_pclusterblks = 1; + sbi->available_compr_algs = 1 << Z_EROFS_COMPRESSION_LZ4; } sbi->lz4.max_distance_pages = distance ? @@ -198,7 +201,6 @@ const char *z_erofs_fixup_insize(struct z_erofs_decompress_req *rq, static const char *__z_erofs_lz4_decompress(struct z_erofs_decompress_req *rq, u8 *dst) { - bool zeropadded = erofs_sb_has_zero_padding(EROFS_SB(rq->sb)); bool may_inplace = false; unsigned int inputmargin; u8 *out, *headpage, *src; @@ -206,18 +208,15 @@ static const char *__z_erofs_lz4_decompress(struct z_erofs_decompress_req *rq, int ret, maptype; headpage = kmap_local_page(*rq->in); - /* LZ4 decompression inplace is only safe if zero_padding is enabled */ - if (zeropadded) { - reason = z_erofs_fixup_insize(rq, headpage + rq->pageofs_in, - min_t(unsigned int, rq->inputsize, - rq->sb->s_blocksize - rq->pageofs_in)); - if (reason) { - kunmap_local(headpage); - return reason; - } - may_inplace = !((rq->pageofs_in + rq->inputsize) & - (rq->sb->s_blocksize - 1)); + reason = z_erofs_fixup_insize(rq, headpage + rq->pageofs_in, + min_t(unsigned int, rq->inputsize, + rq->sb->s_blocksize - rq->pageofs_in)); + if (reason) { + kunmap_local(headpage); + return reason; } + may_inplace = !((rq->pageofs_in + rq->inputsize) & + (rq->sb->s_blocksize - 1)); inputmargin = rq->pageofs_in; src = z_erofs_lz4_handle_overlap(rq, headpage, dst, &inputmargin, @@ -226,8 +225,7 @@ static const char *__z_erofs_lz4_decompress(struct z_erofs_decompress_req *rq, return ERR_CAST(src); out = dst + rq->pageofs_out; - /* legacy format could compress extra data in a pcluster. */ - if (rq->partial_decoding || !zeropadded) + if (rq->partial_decoding) ret = LZ4_decompress_safe_partial(src + inputmargin, out, rq->inputsize, rq->outputsize, rq->outputsize); else @@ -454,10 +452,8 @@ int z_erofs_parse_cfgs(struct super_block *sb, struct erofs_super_block *dsb) erofs_off_t offset; int size, ret = 0; - if (!erofs_sb_has_compr_cfgs(sbi)) { - sbi->available_compr_algs = 1 << Z_EROFS_COMPRESSION_LZ4; + if (!erofs_sb_has_compr_cfgs(sbi)) return z_erofs_load_lz4_config(sb, dsb, NULL, 0); - } algs = le16_to_cpu(dsb->u1.available_compr_algs); sbi->available_compr_algs = algs; diff --git a/fs/erofs/erofs_fs.h b/fs/erofs/erofs_fs.h index b30a74d307c5..b80c6bb33a58 100644 --- a/fs/erofs/erofs_fs.h +++ b/fs/erofs/erofs_fs.h @@ -23,7 +23,7 @@ * Any bits that aren't in EROFS_ALL_FEATURE_INCOMPAT should * be incompatible with this kernel version. */ -#define EROFS_FEATURE_INCOMPAT_ZERO_PADDING 0x00000001 +#define EROFS_FEATURE_INCOMPAT_LZ4_0PADDING 0x00000001 #define EROFS_FEATURE_INCOMPAT_COMPR_CFGS 0x00000002 #define EROFS_FEATURE_INCOMPAT_BIG_PCLUSTER 0x00000002 #define EROFS_FEATURE_INCOMPAT_CHUNKED_FILE 0x00000004 diff --git a/fs/erofs/inode.c b/fs/erofs/inode.c index 294f66376825..4f86169c23f1 100644 --- a/fs/erofs/inode.c +++ b/fs/erofs/inode.c @@ -183,11 +183,17 @@ static int erofs_read_inode(struct inode *inode) goto err_out; } - if (erofs_inode_is_data_compressed(vi->datalayout)) - inode->i_blocks = le32_to_cpu(copied.i_u.blocks_lo) << - (sb->s_blocksize_bits - 9); - else + if (!erofs_inode_is_data_compressed(vi->datalayout)) { inode->i_blocks = round_up(inode->i_size, sb->s_blocksize) >> 9; + } else if (!IS_ENABLED(CONFIG_EROFS_FS_ZIP) || !sbi->available_compr_algs) { + erofs_err(sb, "compressed inode (nid %llu) is invalid in a plain filesystem", + vi->nid); + err = -EFSCORRUPTED; + goto err_out; + } else { + inode->i_blocks = le32_to_cpu(copied.i_u.blocks_lo) << + (sb->s_blocksize_bits - 9); + } if (vi->datalayout == EROFS_INODE_CHUNK_BASED) { /* fill chunked inode summary info */ diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h index 3001bfec4e04..6a4802f3fdd8 100644 --- a/fs/erofs/internal.h +++ b/fs/erofs/internal.h @@ -114,7 +114,6 @@ struct erofs_sb_info { unsigned int sync_decompress; /* strategy for sync decompression */ unsigned int shrinker_run_no; - u16 available_compr_algs; /* pseudo inode to manage cached pages */ struct inode *managed_cache; @@ -154,6 +153,7 @@ struct erofs_sb_info { char *volume_name; u32 feature_compat; u32 feature_incompat; + u16 available_compr_algs; /* sysfs support */ struct kobject s_kobj; /* /sys/fs/erofs/ */ @@ -221,7 +221,7 @@ static inline bool erofs_sb_has_##name(struct erofs_sb_info *sbi) \ return sbi->feature_##compat & EROFS_FEATURE_##feature; \ } -EROFS_FEATURE_FUNCS(zero_padding, incompat, INCOMPAT_ZERO_PADDING) +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(chunked_file, incompat, INCOMPAT_CHUNKED_FILE) @@ -530,7 +530,6 @@ void z_erofs_put_gbuf(void *ptr); int z_erofs_gbuf_growsize(unsigned int nrpages); int __init z_erofs_gbuf_init(void); void z_erofs_gbuf_exit(void); -int z_erofs_parse_cfgs(struct super_block *sb, struct erofs_super_block *dsb); #else static inline void erofs_shrinker_register(struct super_block *sb) {} static inline void erofs_shrinker_unregister(struct super_block *sb) {} @@ -540,6 +539,7 @@ static inline int z_erofs_init_subsystem(void) { return 0; } static inline void z_erofs_exit_subsystem(void) {} static inline int z_erofs_init_super(struct super_block *sb) { return 0; } #endif /* !CONFIG_EROFS_FS_ZIP */ +int z_erofs_parse_cfgs(struct super_block *sb, struct erofs_super_block *dsb); #ifdef CONFIG_EROFS_FS_BACKED_BY_FILE struct bio *erofs_fileio_bio_alloc(struct erofs_map_dev *mdev); diff --git a/fs/erofs/super.c b/fs/erofs/super.c index b9ffb3d42bf4..e52c2b528f86 100644 --- a/fs/erofs/super.c +++ b/fs/erofs/super.c @@ -122,18 +122,6 @@ void *erofs_read_metadata(struct super_block *sb, struct erofs_buf *buf, return buffer; } -#ifndef CONFIG_EROFS_FS_ZIP -static int z_erofs_parse_cfgs(struct super_block *sb, - struct erofs_super_block *dsb) -{ - if (!dsb->u1.available_compr_algs) - return 0; - - erofs_err(sb, "compression disabled, unable to mount compressed EROFS"); - return -EOPNOTSUPP; -} -#endif - static int erofs_init_device(struct erofs_buf *buf, struct super_block *sb, struct erofs_device_info *dif, erofs_off_t *pos) { @@ -363,10 +351,16 @@ static int erofs_read_superblock(struct super_block *sb) } } - /* parse on-disk compression configurations */ - ret = z_erofs_parse_cfgs(sb, dsb); - if (ret < 0) + if (IS_ENABLED(CONFIG_EROFS_FS_ZIP)) { + ret = z_erofs_parse_cfgs(sb, dsb); + if (ret < 0) + goto out; + } else if (dsb->u1.available_compr_algs || + erofs_sb_has_lz4_0padding(sbi)) { + erofs_err(sb, "compression disabled, unable to mount compressed EROFS"); + ret = -EOPNOTSUPP; goto out; + } ret = erofs_scan_devices(sb, dsb); diff --git a/fs/erofs/sysfs.c b/fs/erofs/sysfs.c index 86b22b9f0c19..3a9a5fa000ae 100644 --- a/fs/erofs/sysfs.c +++ b/fs/erofs/sysfs.c @@ -86,7 +86,6 @@ static struct attribute *erofs_attrs[] = { ATTRIBUTE_GROUPS(erofs); /* Features this copy of erofs supports */ -EROFS_ATTR_FEATURE(zero_padding); EROFS_ATTR_FEATURE(compr_cfgs); EROFS_ATTR_FEATURE(big_pcluster); EROFS_ATTR_FEATURE(chunked_file); @@ -100,7 +99,6 @@ EROFS_ATTR_FEATURE(48bit); EROFS_ATTR_FEATURE(metabox); static struct attribute *erofs_feat_attrs[] = { - ATTR_LIST(zero_padding), ATTR_LIST(compr_cfgs), ATTR_LIST(big_pcluster), ATTR_LIST(chunked_file),