On incremental uncompressed builds, z_erofs_parse_cfgs takes the legacy path for images without COMPR_CFGS and unconditionally sets available_compr_algs to LZ4, regardless of whether compression was actually used. When the current build requests no compression, z_erofs_compress_init returns early leaving ccfg uninitialized and available_compr_algs unchanged, subsquently causing a crash when alg is dereferenced.
Fix this by gating compression on whether the per-algorithm ccfg entry was actually initialized rather than trusting the superblock bitmask. Simple repro with alpine rootfs: ./mkfs.erofs /tmp/alpine.erofs /tmp/alpine ./mkfs.erofs --incremental=data /tmp/alpine.erofs /tmp/alpine mkfs.erofs 1.9-g1d5bacbb <W> erofs: EXPERIMENTAL incremental build in use. Use at your own risk! Processing bin/sh ...zsh: segmentation fault (core dumped) ./mkfs.erofs --incremental=data /tmp/alpine.erofs /tmp/alpine Signed-off-by: Jonathan Calmels <[email protected]> --- lib/compress.c | 10 ++++++++++ lib/inode.c | 17 ++++++++++++----- lib/liberofs_compress.h | 1 + 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/lib/compress.c b/lib/compress.c index ea07409..e5bb784 100644 --- a/lib/compress.c +++ b/lib/compress.c @@ -2186,6 +2186,16 @@ static int z_erofs_build_compr_cfgs(struct erofs_importer *im, return ret; } +bool z_erofs_compress_alg_enabled(const struct erofs_importer *im, u8 algid) +{ + struct erofs_sb_info *sbi = im->sbi; + + if (!sbi->available_compr_algs || !sbi->zmgr || algid >= EROFS_MAX_COMPR_CFGS) + return false; + + return sbi->zmgr->ccfg[algid].enable; +} + int z_erofs_compress_init(struct erofs_importer *im) { const struct erofs_importer_params *params = im->params; diff --git a/lib/inode.c b/lib/inode.c index c225faa..05344e7 100644 --- a/lib/inode.c +++ b/lib/inode.c @@ -624,9 +624,18 @@ int erofs_write_file_from_buffer(struct erofs_inode *inode, char *buf) static bool erofs_file_is_compressible(struct erofs_importer *im, struct erofs_inode *inode) { - if (erofs_is_metabox_inode(inode) && - !im->params->pclusterblks_metabox) + u8 algid; + + if (erofs_is_metabox_inode(inode)) { + if (!im->params->pclusterblks_metabox) + return false; + algid = cfg.c_mkfs_metabox_algid; + } else { + algid = inode->z_algorithmtype[0]; + } + if (!z_erofs_compress_alg_enabled(im, algid)) return false; + if (cfg.c_compress_hints_file) return z_erofs_apply_compress_hints(im, inode); return true; @@ -2049,7 +2058,6 @@ static int erofs_mkfs_begin_nondirectory(const struct erofs_mkfs_btctx *btctx, return ret; if (inode->datasource != EROFS_INODE_DATA_SOURCE_REBUILD_BLOB && - inode->sbi->available_compr_algs && erofs_file_is_compressible(im, inode)) { ctx.ictx = erofs_prepare_compressed_file(im, inode); if (IS_ERR(ctx.ictx)) @@ -2378,8 +2386,7 @@ struct erofs_inode *erofs_mkfs_build_special_from_fd(struct erofs_importer *im, return ERR_PTR(ret); } - if (sbi->available_compr_algs && - erofs_file_is_compressible(im, inode)) { + if (erofs_file_is_compressible(im, inode)) { ictx = erofs_prepare_compressed_file(im, inode); if (IS_ERR(ictx)) return ERR_CAST(ictx); diff --git a/lib/liberofs_compress.h b/lib/liberofs_compress.h index da6eb1a..32e8e03 100644 --- a/lib/liberofs_compress.h +++ b/lib/liberofs_compress.h @@ -14,6 +14,7 @@ struct z_erofs_compress_ictx; +bool z_erofs_compress_alg_enabled(const struct erofs_importer *im, u8 algid); void z_erofs_drop_inline_pcluster(struct erofs_inode *inode); void *erofs_prepare_compressed_file(struct erofs_importer *im, struct erofs_inode *inode); -- 2.53.0
