erofs: simplify compression configuration parser

commit efb4fb02ce upstream.

Move erofs_load_compr_cfgs() into decompressor.c as well as introduce
a callback instead of a hard-coded switch for each algorithm for
simplicity.

Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Link: https://lore.kernel.org/r/20231022130957.11398-1-xiang@kernel.org
Stable-dep-of: 118a8cf504 ("erofs: fix inconsistent per-file compression format")
Signed-off-by: Yue Hu <huyue2@coolpad.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Gao Xiang 2023-10-22 21:09:57 +08:00 committed by Greg Kroah-Hartman
parent b1301f15dd
commit 54407d9bc5
5 changed files with 76 additions and 92 deletions

View File

@ -21,6 +21,8 @@ struct z_erofs_decompress_req {
}; };
struct z_erofs_decompressor { struct z_erofs_decompressor {
int (*config)(struct super_block *sb, struct erofs_super_block *dsb,
void *data, int size);
int (*decompress)(struct z_erofs_decompress_req *rq, int (*decompress)(struct z_erofs_decompress_req *rq,
struct page **pagepool); struct page **pagepool);
char *name; char *name;
@ -93,6 +95,8 @@ int z_erofs_decompress(struct z_erofs_decompress_req *rq,
struct page **pagepool); struct page **pagepool);
/* prototypes for specific algorithms */ /* prototypes for specific algorithms */
int z_erofs_load_lzma_config(struct super_block *sb,
struct erofs_super_block *dsb, void *data, int size);
int z_erofs_lzma_decompress(struct z_erofs_decompress_req *rq, int z_erofs_lzma_decompress(struct z_erofs_decompress_req *rq,
struct page **pagepool); struct page **pagepool);
#endif #endif

View File

@ -24,11 +24,11 @@ struct z_erofs_lz4_decompress_ctx {
unsigned int oend; unsigned int oend;
}; };
int z_erofs_load_lz4_config(struct super_block *sb, static int z_erofs_load_lz4_config(struct super_block *sb,
struct erofs_super_block *dsb, struct erofs_super_block *dsb, void *data, int size)
struct z_erofs_lz4_cfgs *lz4, int size)
{ {
struct erofs_sb_info *sbi = EROFS_SB(sb); struct erofs_sb_info *sbi = EROFS_SB(sb);
struct z_erofs_lz4_cfgs *lz4 = data;
u16 distance; u16 distance;
if (lz4) { if (lz4) {
@ -374,17 +374,71 @@ static struct z_erofs_decompressor decompressors[] = {
.name = "interlaced" .name = "interlaced"
}, },
[Z_EROFS_COMPRESSION_LZ4] = { [Z_EROFS_COMPRESSION_LZ4] = {
.config = z_erofs_load_lz4_config,
.decompress = z_erofs_lz4_decompress, .decompress = z_erofs_lz4_decompress,
.name = "lz4" .name = "lz4"
}, },
#ifdef CONFIG_EROFS_FS_ZIP_LZMA #ifdef CONFIG_EROFS_FS_ZIP_LZMA
[Z_EROFS_COMPRESSION_LZMA] = { [Z_EROFS_COMPRESSION_LZMA] = {
.config = z_erofs_load_lzma_config,
.decompress = z_erofs_lzma_decompress, .decompress = z_erofs_lzma_decompress,
.name = "lzma" .name = "lzma"
}, },
#endif #endif
}; };
int z_erofs_parse_cfgs(struct super_block *sb, struct erofs_super_block *dsb)
{
struct erofs_sb_info *sbi = EROFS_SB(sb);
struct erofs_buf buf = __EROFS_BUF_INITIALIZER;
unsigned int algs, alg;
erofs_off_t offset;
int size, ret = 0;
if (!erofs_sb_has_compr_cfgs(sbi)) {
sbi->available_compr_algs = Z_EROFS_COMPRESSION_LZ4;
return z_erofs_load_lz4_config(sb, dsb, NULL, 0);
}
sbi->available_compr_algs = le16_to_cpu(dsb->u1.available_compr_algs);
if (sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS) {
erofs_err(sb, "unidentified algorithms %x, please upgrade kernel",
sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS);
return -EOPNOTSUPP;
}
offset = EROFS_SUPER_OFFSET + sbi->sb_size;
alg = 0;
for (algs = sbi->available_compr_algs; algs; algs >>= 1, ++alg) {
void *data;
if (!(algs & 1))
continue;
data = erofs_read_metadata(sb, &buf, &offset, &size);
if (IS_ERR(data)) {
ret = PTR_ERR(data);
break;
}
if (alg >= ARRAY_SIZE(decompressors) ||
!decompressors[alg].config) {
erofs_err(sb, "algorithm %d isn't enabled on this kernel",
alg);
ret = -EOPNOTSUPP;
} else {
ret = decompressors[alg].config(sb,
dsb, data, size);
}
kfree(data);
if (ret)
break;
}
erofs_put_metabuf(&buf);
return ret;
}
int z_erofs_decompress(struct z_erofs_decompress_req *rq, int z_erofs_decompress(struct z_erofs_decompress_req *rq,
struct page **pagepool) struct page **pagepool)
{ {

View File

@ -72,10 +72,10 @@ int z_erofs_lzma_init(void)
} }
int z_erofs_load_lzma_config(struct super_block *sb, int z_erofs_load_lzma_config(struct super_block *sb,
struct erofs_super_block *dsb, struct erofs_super_block *dsb, void *data, int size)
struct z_erofs_lzma_cfgs *lzma, int size)
{ {
static DEFINE_MUTEX(lzma_resize_mutex); static DEFINE_MUTEX(lzma_resize_mutex);
struct z_erofs_lzma_cfgs *lzma = data;
unsigned int dict_size, i; unsigned int dict_size, i;
struct z_erofs_lzma *strm, *head = NULL; struct z_erofs_lzma *strm, *head = NULL;
int err; int err;

View File

@ -471,6 +471,8 @@ struct erofs_map_dev {
/* data.c */ /* data.c */
extern const struct file_operations erofs_file_fops; extern const struct file_operations erofs_file_fops;
void *erofs_read_metadata(struct super_block *sb, struct erofs_buf *buf,
erofs_off_t *offset, int *lengthp);
void erofs_unmap_metabuf(struct erofs_buf *buf); void erofs_unmap_metabuf(struct erofs_buf *buf);
void erofs_put_metabuf(struct erofs_buf *buf); void erofs_put_metabuf(struct erofs_buf *buf);
void *erofs_bread(struct erofs_buf *buf, struct inode *inode, void *erofs_bread(struct erofs_buf *buf, struct inode *inode,
@ -565,9 +567,7 @@ void z_erofs_exit_zip_subsystem(void);
int erofs_try_to_free_all_cached_pages(struct erofs_sb_info *sbi, int erofs_try_to_free_all_cached_pages(struct erofs_sb_info *sbi,
struct erofs_workgroup *egrp); struct erofs_workgroup *egrp);
int erofs_try_to_free_cached_page(struct page *page); int erofs_try_to_free_cached_page(struct page *page);
int z_erofs_load_lz4_config(struct super_block *sb, int z_erofs_parse_cfgs(struct super_block *sb, struct erofs_super_block *dsb);
struct erofs_super_block *dsb,
struct z_erofs_lz4_cfgs *lz4, int len);
#else #else
static inline void erofs_shrinker_register(struct super_block *sb) {} static inline void erofs_shrinker_register(struct super_block *sb) {}
static inline void erofs_shrinker_unregister(struct super_block *sb) {} static inline void erofs_shrinker_unregister(struct super_block *sb) {}
@ -575,36 +575,14 @@ static inline int erofs_init_shrinker(void) { return 0; }
static inline void erofs_exit_shrinker(void) {} static inline void erofs_exit_shrinker(void) {}
static inline int z_erofs_init_zip_subsystem(void) { return 0; } static inline int z_erofs_init_zip_subsystem(void) { return 0; }
static inline void z_erofs_exit_zip_subsystem(void) {} static inline void z_erofs_exit_zip_subsystem(void) {}
static inline int z_erofs_load_lz4_config(struct super_block *sb,
struct erofs_super_block *dsb,
struct z_erofs_lz4_cfgs *lz4, int len)
{
if (lz4 || dsb->u1.lz4_max_distance) {
erofs_err(sb, "lz4 algorithm isn't enabled");
return -EINVAL;
}
return 0;
}
#endif /* !CONFIG_EROFS_FS_ZIP */ #endif /* !CONFIG_EROFS_FS_ZIP */
#ifdef CONFIG_EROFS_FS_ZIP_LZMA #ifdef CONFIG_EROFS_FS_ZIP_LZMA
int z_erofs_lzma_init(void); int z_erofs_lzma_init(void);
void z_erofs_lzma_exit(void); void z_erofs_lzma_exit(void);
int z_erofs_load_lzma_config(struct super_block *sb,
struct erofs_super_block *dsb,
struct z_erofs_lzma_cfgs *lzma, int size);
#else #else
static inline int z_erofs_lzma_init(void) { return 0; } static inline int z_erofs_lzma_init(void) { return 0; }
static inline int z_erofs_lzma_exit(void) { return 0; } static inline int z_erofs_lzma_exit(void) { return 0; }
static inline int z_erofs_load_lzma_config(struct super_block *sb,
struct erofs_super_block *dsb,
struct z_erofs_lzma_cfgs *lzma, int size) {
if (lzma) {
erofs_err(sb, "lzma algorithm isn't enabled");
return -EINVAL;
}
return 0;
}
#endif /* !CONFIG_EROFS_FS_ZIP */ #endif /* !CONFIG_EROFS_FS_ZIP */
/* flags for erofs_fscache_register_cookie() */ /* flags for erofs_fscache_register_cookie() */

View File

@ -126,8 +126,8 @@ static bool check_layout_compatibility(struct super_block *sb,
#ifdef CONFIG_EROFS_FS_ZIP #ifdef CONFIG_EROFS_FS_ZIP
/* read variable-sized metadata, offset will be aligned by 4-byte */ /* read variable-sized metadata, offset will be aligned by 4-byte */
static void *erofs_read_metadata(struct super_block *sb, struct erofs_buf *buf, void *erofs_read_metadata(struct super_block *sb, struct erofs_buf *buf,
erofs_off_t *offset, int *lengthp) erofs_off_t *offset, int *lengthp)
{ {
u8 *buffer, *ptr; u8 *buffer, *ptr;
int len, i, cnt; int len, i, cnt;
@ -159,64 +159,15 @@ static void *erofs_read_metadata(struct super_block *sb, struct erofs_buf *buf,
} }
return buffer; return buffer;
} }
static int erofs_load_compr_cfgs(struct super_block *sb,
struct erofs_super_block *dsb)
{
struct erofs_sb_info *sbi = EROFS_SB(sb);
struct erofs_buf buf = __EROFS_BUF_INITIALIZER;
unsigned int algs, alg;
erofs_off_t offset;
int size, ret = 0;
sbi->available_compr_algs = le16_to_cpu(dsb->u1.available_compr_algs);
if (sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS) {
erofs_err(sb, "try to load compressed fs with unsupported algorithms %x",
sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS);
return -EINVAL;
}
offset = EROFS_SUPER_OFFSET + sbi->sb_size;
alg = 0;
for (algs = sbi->available_compr_algs; algs; algs >>= 1, ++alg) {
void *data;
if (!(algs & 1))
continue;
data = erofs_read_metadata(sb, &buf, &offset, &size);
if (IS_ERR(data)) {
ret = PTR_ERR(data);
break;
}
switch (alg) {
case Z_EROFS_COMPRESSION_LZ4:
ret = z_erofs_load_lz4_config(sb, dsb, data, size);
break;
case Z_EROFS_COMPRESSION_LZMA:
ret = z_erofs_load_lzma_config(sb, dsb, data, size);
break;
default:
DBG_BUGON(1);
ret = -EFAULT;
}
kfree(data);
if (ret)
break;
}
erofs_put_metabuf(&buf);
return ret;
}
#else #else
static int erofs_load_compr_cfgs(struct super_block *sb, static int z_erofs_parse_cfgs(struct super_block *sb,
struct erofs_super_block *dsb) struct erofs_super_block *dsb)
{ {
if (dsb->u1.available_compr_algs) { if (!dsb->u1.available_compr_algs)
erofs_err(sb, "try to load compressed fs when compression is disabled"); return 0;
return -EINVAL;
} erofs_err(sb, "compression disabled, unable to mount compressed EROFS");
return 0; return -EOPNOTSUPP;
} }
#endif #endif
@ -398,10 +349,7 @@ static int erofs_read_superblock(struct super_block *sb)
} }
/* parse on-disk compression configurations */ /* parse on-disk compression configurations */
if (erofs_sb_has_compr_cfgs(sbi)) ret = z_erofs_parse_cfgs(sb, dsb);
ret = erofs_load_compr_cfgs(sb, dsb);
else
ret = z_erofs_load_lz4_config(sb, dsb, NULL, 0);
if (ret < 0) if (ret < 0)
goto out; goto out;