* [PATCH v2 1/3] erofs-utils: lib: migrate `c_chunkbits` and `c_blobdev_path` @ 2026-09-02 15:53 Gao Xiang 2026-09-02 15:53 ` [PATCH v2 2/3] erofs-utils: mkfs: introduce ddev_id_def Gao Xiang 2026-09-02 15:53 ` [PATCH v2 3/3] erofs-utils: mkfs: enable `--blobdev` for flat inode layouts Gao Xiang 0 siblings, 2 replies; 4+ messages in thread From: Gao Xiang @ 2026-09-02 15:53 UTC (permalink / raw) To: linux-erofs; +Cc: Gao Xiang Signed-off-by: Gao Xiang <xiang@kernel.org> --- address Xusheng's comments: https://lore.kernel.org/r/20260902071406.3292294-1-zhanxusheng@xiaomi.com include/erofs/config.h | 2 -- include/erofs/importer.h | 1 + lib/inode.c | 25 +++++++++-------- mkfs/main.c | 58 +++++++++++++++++++++------------------- 4 files changed, 46 insertions(+), 40 deletions(-) diff --git a/include/erofs/config.h b/include/erofs/config.h index 95d7e9f..c796c95 100644 --- a/include/erofs/config.h +++ b/include/erofs/config.h @@ -34,7 +34,6 @@ struct erofs_configure { int c_dbg_lvl; bool c_dry_run; char c_timeinherit; - char c_chunkbits; char c_dedupe; bool c_showprogress; bool c_extra_ea_name_prefixes; @@ -46,7 +45,6 @@ struct erofs_configure { /* related arguments for mkfs.erofs */ char *c_img_path; char *c_src_path; - char *c_blobdev_path; char *c_compress_hints_file; char c_force_chunkformat; u8 c_mkfs_metabox_algid; diff --git a/include/erofs/importer.h b/include/erofs/importer.h index 07e40b4..c09b169 100644 --- a/include/erofs/importer.h +++ b/include/erofs/importer.h @@ -63,6 +63,7 @@ struct erofs_importer_params { bool all_fragments; bool compress_dir; char fragdedupe; + char chunkszbits_def; }; struct erofs_importer { diff --git a/lib/inode.c b/lib/inode.c index ea3277b..728040a 100644 --- a/lib/inode.c +++ b/lib/inode.c @@ -704,13 +704,15 @@ static int erofs_write_unencoded_data(struct erofs_inode *inode, return 0; } -int erofs_write_unencoded_file(struct erofs_inode *inode, int fd, u64 fpos) +static int erofs_write_unencoded_file(const struct erofs_importer *im, + struct erofs_inode *inode, int fd, u64 fpos) { struct erofs_vfile vf = { .fd = fd }; + char chunkbits = im->params->chunkszbits_def; - if (cfg.c_chunkbits && + if (chunkbits && inode->datasource != EROFS_INODE_DATA_SOURCE_REBUILD_BLOB) { - inode->u.chunkbits = cfg.c_chunkbits; + inode->u.chunkbits = chunkbits; /* chunk indexes when explicitly specified */ inode->u.chunkformat = 0; if (cfg.c_force_chunkformat == FORCE_INODE_CHUNK_INDEXES) @@ -1491,6 +1493,11 @@ static int erofs_inode_reserve_data_blocks(struct erofs_inode *inode) return 0; } +struct erofs_mkfs_btctx { + struct erofs_importer *im; + bool rebuild, incremental; +}; + struct erofs_mkfs_job_ndir_ctx { struct erofs_inode *inode; void *ictx; @@ -1498,7 +1505,8 @@ struct erofs_mkfs_job_ndir_ctx { u64 fpos; }; -static int erofs_mkfs_job_write_file(struct erofs_mkfs_job_ndir_ctx *ctx) +static int erofs_mkfs_job_write_file(const struct erofs_mkfs_btctx *btctx, + struct erofs_mkfs_job_ndir_ctx *ctx) { struct erofs_inode *inode = ctx->inode; int ret; @@ -1519,7 +1527,7 @@ static int erofs_mkfs_job_write_file(struct erofs_mkfs_job_ndir_ctx *ctx) } } /* fallback to all data uncompressed */ - ret = erofs_write_unencoded_file(inode, ctx->fd, ctx->fpos); + ret = erofs_write_unencoded_file(btctx->im, inode, ctx->fd, ctx->fpos); out: if (inode->datasource == EROFS_INODE_DATA_SOURCE_DISKBUF) { erofs_diskbuf_close(inode->i_diskbuf); @@ -1539,11 +1547,6 @@ out: return ret; } -struct erofs_mkfs_btctx { - struct erofs_importer *im; - bool rebuild, incremental; -}; - static int erofs_mkfs_handle_nondirectory(const struct erofs_mkfs_btctx *btctx, struct erofs_mkfs_job_ndir_ctx *ctx) { @@ -1575,7 +1578,7 @@ static int erofs_mkfs_handle_nondirectory(const struct erofs_mkfs_btctx *btctx, if (inode->datasource == EROFS_INODE_DATA_SOURCE_RESVSP) ret = erofs_inode_reserve_data_blocks(inode); else if (ctx->fd >= 0) - ret = erofs_mkfs_job_write_file(ctx); + ret = erofs_mkfs_job_write_file(btctx, ctx); } if (ret) return ret; diff --git a/mkfs/main.c b/mkfs/main.c index 8da3753..ce29319 100644 --- a/mkfs/main.c +++ b/mkfs/main.c @@ -282,9 +282,11 @@ static void version(void) static struct erofsmkfs_cfg { struct z_erofs_paramset zcfgs[EROFS_MAX_COMPR_CFGS + 1]; + char *blobdev_path; /* < 0, xattr disabled and >= INT_MAX, always use inline xattrs */ long inlinexattr_tolerance; bool inode_metazone; + char chunkbits; u64 unix_timestamp; unsigned int total_zcfgs; } mkfscfg = { @@ -1265,8 +1267,8 @@ static int mkfs_parse_options_cfg(struct erofs_importer_params *params, erofs_err("invalid chunksize %s", optarg); return -EINVAL; } - cfg.c_chunkbits = ilog2(i); - if ((1 << cfg.c_chunkbits) != i) { + mkfscfg.chunkbits = ilog2(i); + if ((1 << mkfscfg.chunkbits) != i) { erofs_err("chunksize %s must be a power of two", optarg); return -EINVAL; @@ -1277,7 +1279,7 @@ static int mkfs_parse_options_cfg(struct erofs_importer_params *params, quiet = true; break; case 13: - cfg.c_blobdev_path = optarg; + mkfscfg.blobdev_path = optarg; break; case 14: params->ignore_mtime = true; @@ -1506,13 +1508,13 @@ static int mkfs_parse_options_cfg(struct erofs_importer_params *params, } } - if (cfg.c_blobdev_path && cfg.c_chunkbits < mkfs_blkszbits) { + if (mkfscfg.blobdev_path && mkfscfg.chunkbits < mkfs_blkszbits) { erofs_err("--blobdev must be used together with --chunksize"); return -EINVAL; } /* TODO: can be implemented with (deviceslot) mapped_blkaddr */ - if (cfg.c_blobdev_path && + if (mkfscfg.blobdev_path && cfg.c_force_chunkformat == FORCE_INODE_BLOCK_MAP) { erofs_err("--blobdev cannot work with block map currently"); return -EINVAL; @@ -1564,9 +1566,9 @@ static int mkfs_parse_options_cfg(struct erofs_importer_params *params, params->pclusterblks_max = pclustersize_max >> mkfs_blkszbits; params->pclusterblks_def = params->pclusterblks_max; } - if (cfg.c_chunkbits && cfg.c_chunkbits < mkfs_blkszbits) { + if (mkfscfg.chunkbits && mkfscfg.chunkbits < mkfs_blkszbits) { erofs_err("chunksize %u must be larger than block size", - 1u << cfg.c_chunkbits); + 1u << mkfscfg.chunkbits); return -EINVAL; } @@ -1579,10 +1581,10 @@ static int mkfs_parse_options_cfg(struct erofs_importer_params *params, * unaligned. Therefore, let's issue a warning here and still skip * alignment for now. */ - if (cfg.c_chunkbits && dsunit && - (1u << (cfg.c_chunkbits - g_sbi.blkszbits)) < dsunit) { + if (mkfscfg.chunkbits && dsunit && + (1u << (mkfscfg.chunkbits - g_sbi.blkszbits)) < dsunit) { erofs_warn("chunksize %u bytes is smaller than dsunit %u blocks, ignore dsunit !", - 1u << cfg.c_chunkbits, dsunit); + 1u << mkfscfg.chunkbits, dsunit); } if (pclustersize_packed) { @@ -1896,26 +1898,28 @@ int main(int argc, char **argv) importer_params.source = cfg.c_src_path; importer_params.no_datainline = mkfs_no_datainline; importer_params.dot_omitted = mkfs_dot_omitted; + if (importer_params.dedupe == EROFS_DEDUPE_FORCE_ON && + !mkfscfg.chunkbits && !mkfscfg.total_zcfgs) { + erofs_err("Compression is not enabled. Turn on chunk-based data deduplication instead."); + mkfscfg.chunkbits = g_sbi.blkszbits; + } + importer_params.chunkszbits_def = mkfscfg.chunkbits; err = erofs_importer_init(&importer); if (err) goto exit; - if (importer_params.dedupe == EROFS_DEDUPE_FORCE_ON) { - if (!g_sbi.available_compr_algs) { - erofs_err("Compression is not enabled. Turn on chunk-based data deduplication instead."); - cfg.c_chunkbits = g_sbi.blkszbits; - } else { - err = z_erofs_dedupe_init(erofs_blksiz(&g_sbi)); - if (err) { - erofs_err("failed to initialize deduplication: %s", - erofs_strerror(err)); - goto exit; - } + if (importer_params.dedupe == EROFS_DEDUPE_FORCE_ON && + g_sbi.available_compr_algs) { + err = z_erofs_dedupe_init(erofs_blksiz(&g_sbi)); + if (err) { + erofs_err("failed to initialize deduplication: %s", + erofs_strerror(err)); + goto exit; } } cfg.c_dedupe = importer_params.dedupe; - if (tar_index_512b || cfg.c_blobdev_path) { + if (tar_index_512b || mkfscfg.blobdev_path) { err = erofs_mkfs_init_devices(&g_sbi, 1); if (err) { erofs_err("failed to generate device table: %s", @@ -1924,9 +1928,9 @@ int main(int argc, char **argv) } } - if (tar_index_512b || cfg.c_chunkbits) { - if (g_sbi.extra_devices && cfg.c_blobdev_path) { - g_sbi.devs[0].src_path = strdup(cfg.c_blobdev_path); + if (tar_index_512b || mkfscfg.chunkbits) { + if (g_sbi.extra_devices && mkfscfg.blobdev_path) { + g_sbi.devs[0].src_path = strdup(mkfscfg.blobdev_path); if (!g_sbi.devs[0].src_path) { err = -ENOMEM; goto exit; @@ -1937,7 +1941,7 @@ int main(int argc, char **argv) goto exit; } - err = erofs_blob_init(&g_sbi, cfg.c_blobdev_path ? 1 : 0, cfg.c_chunkbits); + err = erofs_blob_init(&g_sbi, mkfscfg.blobdev_path ? 1 : 0, mkfscfg.chunkbits); if (err) goto exit; } @@ -2047,7 +2051,7 @@ int main(int argc, char **argv) } } - if (erofstar.index_mode || cfg.c_chunkbits || g_sbi.extra_devices) { + if (erofstar.index_mode || mkfscfg.chunkbits || g_sbi.extra_devices) { err = erofs_mkfs_dump_blobs(&g_sbi); if (err) goto exit; -- 2.47.3 ^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v2 2/3] erofs-utils: mkfs: introduce ddev_id_def 2026-09-02 15:53 [PATCH v2 1/3] erofs-utils: lib: migrate `c_chunkbits` and `c_blobdev_path` Gao Xiang @ 2026-09-02 15:53 ` Gao Xiang 2026-09-02 15:53 ` [PATCH v2 3/3] erofs-utils: mkfs: enable `--blobdev` for flat inode layouts Gao Xiang 1 sibling, 0 replies; 4+ messages in thread From: Gao Xiang @ 2026-09-02 15:53 UTC (permalink / raw) To: linux-erofs; +Cc: Gao Xiang It indicates the default blob device containing the inode data. Signed-off-by: Gao Xiang <xiang@kernel.org> --- include/erofs/importer.h | 1 + lib/blobchunk.c | 11 +++-------- lib/inode.c | 3 ++- lib/liberofs_chunk.h | 5 ++--- mkfs/main.c | 3 ++- 5 files changed, 10 insertions(+), 13 deletions(-) diff --git a/include/erofs/importer.h b/include/erofs/importer.h index c09b169..5141965 100644 --- a/include/erofs/importer.h +++ b/include/erofs/importer.h @@ -64,6 +64,7 @@ struct erofs_importer_params { bool compress_dir; char fragdedupe; char chunkszbits_def; + u16 ddev_id_def; /* target device id for inode data */ }; struct erofs_importer { diff --git a/lib/blobchunk.c b/lib/blobchunk.c index dcb7dfe..5a90991 100644 --- a/lib/blobchunk.c +++ b/lib/blobchunk.c @@ -34,7 +34,6 @@ struct erofs_chunkitem erofs_holechunk = { struct erofs_chunkmgr { struct list_head chunks[65536]; struct list_head unhashed_chunks; - int device_id; }; #define EROFS_CHUNK_NR_BUCKETS \ @@ -49,7 +48,7 @@ struct erofs_chunkitem *erofs_get_unhashed_chunk(struct erofs_sb_info *sbi, int ret; if (__erofs_unlikely(!chunkmgr)) { - ret = erofs_blob_init(sbi, 0, 0); + ret = erofs_blob_init(sbi, 0); if (ret) return ERR_PTR(ret); chunkmgr = sbi->chunkmgr; @@ -323,11 +322,9 @@ static bool erofs_blob_can_merge(struct erofs_sb_info *sbi, } int erofs_blob_write_chunked_file(struct erofs_inode *inode, int fd, - erofs_off_t startoff) + erofs_off_t startoff, int device_id) { struct erofs_sb_info *sbi = inode->sbi; - struct erofs_chunkmgr *cmgr = sbi->chunkmgr; - int device_id = cmgr->device_id; unsigned int chunkbits = inode->u.chunkbits; unsigned int count, unit; struct erofs_chunkitem *chunk, *lastch; @@ -636,8 +633,7 @@ err_vf: return ret; } -int erofs_blob_init(struct erofs_sb_info *sbi, int blobdev_id, - unsigned int chunkbits_zero) +int erofs_blob_init(struct erofs_sb_info *sbi, unsigned int chunkbits_zero) { struct erofs_chunkmgr *cmgr; int i, ret; @@ -656,7 +652,6 @@ int erofs_blob_init(struct erofs_sb_info *sbi, int blobdev_id, if (ret) goto err_out; } - cmgr->device_id = blobdev_id; sbi->chunkmgr = cmgr; } return 0; diff --git a/lib/inode.c b/lib/inode.c index 728040a..a3fc181 100644 --- a/lib/inode.c +++ b/lib/inode.c @@ -709,6 +709,7 @@ static int erofs_write_unencoded_file(const struct erofs_importer *im, { struct erofs_vfile vf = { .fd = fd }; char chunkbits = im->params->chunkszbits_def; + int device_id = im->params->ddev_id_def; if (chunkbits && inode->datasource != EROFS_INODE_DATA_SOURCE_REBUILD_BLOB) { @@ -717,7 +718,7 @@ static int erofs_write_unencoded_file(const struct erofs_importer *im, inode->u.chunkformat = 0; if (cfg.c_force_chunkformat == FORCE_INODE_CHUNK_INDEXES) inode->u.chunkformat = EROFS_CHUNK_FORMAT_INDEXES; - return erofs_blob_write_chunked_file(inode, fd, fpos); + return erofs_blob_write_chunked_file(inode, fd, fpos, device_id); } if (inode->datasource == EROFS_INODE_DATA_SOURCE_REBUILD_BLOB) { diff --git a/lib/liberofs_chunk.h b/lib/liberofs_chunk.h index 3af88df..ff31891 100644 --- a/lib/liberofs_chunk.h +++ b/lib/liberofs_chunk.h @@ -21,12 +21,11 @@ void erofs_inode_fixup_chunkformat(struct erofs_inode *inode); int erofs_write_chunk_indexes(struct erofs_inode *inode, struct erofs_vfile *vf, erofs_off_t off); int erofs_blob_write_chunked_file(struct erofs_inode *inode, int fd, - erofs_off_t startoff); + erofs_off_t startoff, int device_id); int erofs_write_zero_inode(struct erofs_inode *inode); int tarerofs_write_chunkes(struct erofs_inode *inode, erofs_off_t data_offset); int erofs_mkfs_dump_blobs(struct erofs_sb_info *sbi); -int erofs_blob_init(struct erofs_sb_info *sbi, int blobdev_id, - unsigned int chunkbits_def); +int erofs_blob_init(struct erofs_sb_info *sbi, unsigned int chunkbits_zero); int erofs_blob_init_device(struct erofs_sb_info *sbi, int device_id); int erofs_chunkmgr_exit(struct erofs_sb_info *sbi); diff --git a/mkfs/main.c b/mkfs/main.c index ce29319..688e474 100644 --- a/mkfs/main.c +++ b/mkfs/main.c @@ -1941,7 +1941,8 @@ int main(int argc, char **argv) goto exit; } - err = erofs_blob_init(&g_sbi, mkfscfg.blobdev_path ? 1 : 0, mkfscfg.chunkbits); + importer_params.ddev_id_def = mkfscfg.blobdev_path ? 1 : 0; + err = erofs_blob_init(&g_sbi, mkfscfg.chunkbits); if (err) goto exit; } -- 2.47.3 ^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v2 3/3] erofs-utils: mkfs: enable `--blobdev` for flat inode layouts 2026-09-02 15:53 [PATCH v2 1/3] erofs-utils: lib: migrate `c_chunkbits` and `c_blobdev_path` Gao Xiang 2026-09-02 15:53 ` [PATCH v2 2/3] erofs-utils: mkfs: introduce ddev_id_def Gao Xiang @ 2026-09-02 15:53 ` Gao Xiang 2026-09-03 7:57 ` [PATCH v3] " Yifan Zhao 1 sibling, 1 reply; 4+ messages in thread From: Gao Xiang @ 2026-09-02 15:53 UTC (permalink / raw) To: linux-erofs; +Cc: Gao Xiang Add metadata-only image support for PLAIN/INLINE inode layouts: $ mkfs.erofs --blobdev blob.erofs fsmeta.erofs foo/ Follow-up: add `--blobdev` support for compressed inode layouts. Signed-off-by: Gao Xiang <xiang@kernel.org> --- include/erofs/inode.h | 2 +- include/erofs/internal.h | 1 + lib/blobchunk.c | 12 ---------- lib/importer.c | 5 +++++ lib/inode.c | 48 ++++++++++++++++++++++++---------------- lib/liberofs_chunk.h | 1 - lib/remotes/s3.c | 2 +- lib/super.c | 37 ++++++++++++++++++++----------- lib/tar.c | 2 +- mkfs/main.c | 24 ++++++++------------ 10 files changed, 71 insertions(+), 63 deletions(-) diff --git a/include/erofs/inode.h b/include/erofs/inode.h index bf089e8..23848e8 100644 --- a/include/erofs/inode.h +++ b/include/erofs/inode.h @@ -39,7 +39,7 @@ int erofs_iflush(struct erofs_inode *inode); struct erofs_dentry *erofs_d_alloc(struct erofs_inode *parent, const char *name); int erofs_allocate_inode_bh_data(struct erofs_inode *inode, erofs_blk_t nblocks, - bool in_metazone); + int device_id); bool erofs_dentry_is_wht(struct erofs_sb_info *sbi, struct erofs_dentry *d); int __erofs_fill_inode(struct erofs_importer *im, struct erofs_inode *inode, struct stat *st, const char *path); diff --git a/include/erofs/internal.h b/include/erofs/internal.h index 95f5627..4d09c58 100644 --- a/include/erofs/internal.h +++ b/include/erofs/internal.h @@ -461,6 +461,7 @@ void erofs_put_super(struct erofs_sb_info *sbi); int erofs_writesb(struct erofs_sb_info *sbi); struct erofs_buffer_head *erofs_reserve_sb(struct erofs_bufmgr *bmgr); int erofs_mkfs_init_devices(struct erofs_sb_info *sbi, unsigned int devices); +int erofs_update_all_devices(struct erofs_sb_info *sbi); int erofs_write_device_table(struct erofs_sb_info *sbi); int erofs_enable_sb_chksum(struct erofs_sb_info *sbi, u32 *crc); int erofs_superblock_csum_verify(struct erofs_sb_info *sbi); diff --git a/lib/blobchunk.c b/lib/blobchunk.c index 5a90991..8f43dd0 100644 --- a/lib/blobchunk.c +++ b/lib/blobchunk.c @@ -554,18 +554,6 @@ int tarerofs_write_chunkes(struct erofs_inode *inode, erofs_off_t data_offset) return 0; } -int erofs_mkfs_dump_blobs(struct erofs_sb_info *sbi) -{ - struct erofs_device_info *di; - - for (di = sbi->devs; di < sbi->devs + sbi->extra_devices; ++di) { - if (!di->bmgr) - continue; - di->blocks = erofs_mapbh(di->bmgr, NULL); - } - return 0; -} - static int erofs_insert_zerochunk(struct erofs_chunkmgr *cmgr, unsigned int cbitsdef) { diff --git a/lib/importer.c b/lib/importer.c index 2a635d2..89d4d8b 100644 --- a/lib/importer.c +++ b/lib/importer.c @@ -127,6 +127,11 @@ int erofs_importer_flush_all(struct erofs_importer *im) fsalignblks = im->params->fsalignblks ? roundup_pow_of_two(im->params->fsalignblks) : 1; sbi->dif0.blocks = roundup(erofs_mapbh(sbi->bmgr, NULL), fsalignblks); + + err = erofs_update_all_devices(sbi); + if (err) + return err; + err = erofs_write_device_table(sbi); if (err) return err; diff --git a/lib/inode.c b/lib/inode.c index a3fc181..b3aa066 100644 --- a/lib/inode.c +++ b/lib/inode.c @@ -198,26 +198,33 @@ struct erofs_dentry *erofs_d_alloc(struct erofs_inode *parent, /* allocate main data for an inode */ int erofs_allocate_inode_bh_data(struct erofs_inode *inode, erofs_blk_t nblocks, - bool in_metazone) + int device_id) { struct erofs_sb_info *sbi = inode->sbi; - struct erofs_bufmgr *bmgr = in_metazone ? + struct erofs_bufmgr *bmgr = device_id ? erofs_metadata_bmgr(sbi, false) : sbi->bmgr; struct erofs_buffer_head *bh; int ret, type; + if (device_id < 0) + bmgr = erofs_metadata_bmgr(sbi, false); + else if (!device_id) + bmgr = sbi->bmgr; + else + bmgr = sbi->devs[device_id - 1].bmgr; + + if (!bmgr) { + erofs_err("cannot allocate data in unavailable device %d for %s", + device_id, inode->i_srcpath); + return -EINVAL; + } + if (!nblocks) { /* it has only tail-end data */ inode->u.i_blkaddr = EROFS_NULL_ADDR; return 0; } - if (in_metazone && !bmgr) { - erofs_err("cannot allocate data in the metazone when unavailable for %s", - inode->i_srcpath); - return -EINVAL; - } - /* allocate main data buffer */ type = S_ISDIR(inode->i_mode) ? DIRA : DATA; bh = erofs_balloc(bmgr, type, erofs_pos(sbi, nblocks), 0); @@ -232,8 +239,10 @@ int erofs_allocate_inode_bh_data(struct erofs_inode *inode, erofs_blk_t nblocks, DBG_BUGON(ret < 0); /* write blocks except for the tail-end block */ - inode->u.i_blkaddr = bh->block->blkaddr | (in_metazone ? - (sbi->extra_devices + 1ULL) << EROFS_I_BLKADDR_DEV_ID_BIT : 0); + if (device_id < 0) + device_id = sbi->extra_devices + 1; + inode->u.i_blkaddr = bh->block->blkaddr | + ((u64)device_id << EROFS_I_BLKADDR_DEV_ID_BIT); return 0; } @@ -604,7 +613,7 @@ int erofs_write_file_from_buffer(struct erofs_inode *inode, char *buf) inode->datalayout = EROFS_INODE_FLAT_INLINE; - ret = erofs_allocate_inode_bh_data(inode, nblocks, false); + ret = erofs_allocate_inode_bh_data(inode, nblocks, 0); if (ret) return ret; @@ -635,7 +644,7 @@ static bool erofs_file_is_compressible(struct erofs_importer *im, static int erofs_write_unencoded_data(struct erofs_inode *inode, struct erofs_vfile *vf, erofs_off_t fpos, - bool noseek, bool in_metazone) + bool noseek, int device_id) { struct erofs_sb_info *sbi = inode->sbi; struct erofs_buffer_head *bh; @@ -646,7 +655,7 @@ static int erofs_write_unencoded_data(struct erofs_inode *inode, if (!noseek && erofs_sb_has_48bit(sbi)) { if (erofs_io_lseek(vf, fpos, SEEK_DATA) == -ENXIO) { - ret = erofs_allocate_inode_bh_data(inode, 0, false); + ret = erofs_allocate_inode_bh_data(inode, 0, 0); if (ret) return ret; inode->datalayout = EROFS_INODE_FLAT_PLAIN; @@ -663,7 +672,7 @@ static int erofs_write_unencoded_data(struct erofs_inode *inode, remaining = inode->i_size - inode->idata_size; ret = erofs_allocate_inode_bh_data(inode, remaining >> sbi->blkszbits, - in_metazone); + device_id); if (ret) return ret; @@ -724,13 +733,14 @@ static int erofs_write_unencoded_file(const struct erofs_importer *im, if (inode->datasource == EROFS_INODE_DATA_SOURCE_REBUILD_BLOB) { if (erofs_io_lseek(&vf, fpos, SEEK_SET) != (off_t)fpos) return -EIO; - return erofs_write_unencoded_data(inode, &vf, fpos, true, false); + return erofs_write_unencoded_data(inode, &vf, fpos, true, device_id); } inode->datalayout = EROFS_INODE_FLAT_INLINE; /* fallback to all data uncompressed */ return erofs_write_unencoded_data(inode, &vf, fpos, - inode->datasource == EROFS_INODE_DATA_SOURCE_DISKBUF, false); + inode->datasource == EROFS_INODE_DATA_SOURCE_DISKBUF, + device_id); } static int erofs_write_dir_file(const struct erofs_importer *im, @@ -749,7 +759,7 @@ static int erofs_write_dir_file(const struct erofs_importer *im, } else { DBG_BUGON(dir->idata_size != (dir->i_size & (bsz - 1))); err = erofs_write_unencoded_data(dir, vf, 0, true, - im->params->dirdata_in_metazone); + im->params->dirdata_in_metazone ? -1 : 0); } erofs_io_close(vf); return err; @@ -1135,7 +1145,7 @@ static int erofs_write_tail_end(struct erofs_importer *im, params->dirdata_in_metazone; ret = erofs_allocate_inode_bh_data(inode, 1, - in_metazone); + in_metazone ? -1 : params->ddev_id_def); if (ret) return ret; bh = inode->bh_data; @@ -2412,7 +2422,7 @@ struct erofs_inode *erofs_mkfs_build_special_from_fd(struct erofs_importer *im, ret = erofs_write_unencoded_data(inode, &(struct erofs_vfile){ .fd = fd }, 0, inode->datasource == EROFS_INODE_DATA_SOURCE_DISKBUF, - false); + 0); if (ret) return ERR_PTR(ret); out: diff --git a/lib/liberofs_chunk.h b/lib/liberofs_chunk.h index ff31891..16f3d05 100644 --- a/lib/liberofs_chunk.h +++ b/lib/liberofs_chunk.h @@ -24,7 +24,6 @@ int erofs_blob_write_chunked_file(struct erofs_inode *inode, int fd, erofs_off_t startoff, int device_id); int erofs_write_zero_inode(struct erofs_inode *inode); int tarerofs_write_chunkes(struct erofs_inode *inode, erofs_off_t data_offset); -int erofs_mkfs_dump_blobs(struct erofs_sb_info *sbi); int erofs_blob_init(struct erofs_sb_info *sbi, unsigned int chunkbits_zero); int erofs_blob_init_device(struct erofs_sb_info *sbi, int device_id); int erofs_chunkmgr_exit(struct erofs_sb_info *sbi); diff --git a/lib/remotes/s3.c b/lib/remotes/s3.c index b3352df..56ab808 100644 --- a/lib/remotes/s3.c +++ b/lib/remotes/s3.c @@ -1058,7 +1058,7 @@ static int s3erofs_remote_getobject(struct erofs_importer *im, inode->idata_size = 0; ret = erofs_allocate_inode_bh_data(inode, DIV_ROUND_UP(inode->i_size, 1U << sbi->blkszbits), - false); + im->params->ddev_id_def); if (ret) return ret; resp.vf = &sbi->bdev; diff --git a/lib/super.c b/lib/super.c index 9e52dd8..2bb22ac 100644 --- a/lib/super.c +++ b/lib/super.c @@ -414,15 +414,30 @@ int erofs_mkfs_init_devices(struct erofs_sb_info *sbi, unsigned int devices) return 0; } +int erofs_update_all_devices(struct erofs_sb_info *sbi) +{ + struct erofs_device_info *di; + erofs_blk_t last_uniaddr = sbi->dif0.blocks; + + for (di = sbi->devs; di < sbi->devs + sbi->extra_devices; ++di) { + if (di->bmgr) + di->blocks = erofs_mapbh(di->bmgr, NULL); + di->uniaddr = last_uniaddr; + last_uniaddr += di->blocks; + } + sbi->total_blocks = last_uniaddr; + return 0; +} + int erofs_write_device_table(struct erofs_sb_info *sbi) { - erofs_blk_t nblocks = sbi->dif0.blocks; struct erofs_buffer_head *bh = sbi->bh_devt; + struct erofs_device_info *di = sbi->devs; erofs_off_t pos; - unsigned int i, ret; + unsigned int ret; if (!sbi->extra_devices) - goto out; + return 0; if (!bh) { if (erofs_sb_has_device_table(sbi)) return 0; @@ -435,28 +450,24 @@ int erofs_write_device_table(struct erofs_sb_info *sbi) return -EINVAL; } - i = 0; do { struct erofs_deviceslot dis = { - .uniaddr_lo = cpu_to_le32(nblocks), - .blocks_lo = cpu_to_le32(sbi->devs[i].blocks), - .blocks_hi = cpu_to_le16(sbi->devs[i].blocks >> 32), - .uniaddr_hi = cpu_to_le16(nblocks >> 32), + .uniaddr_lo = cpu_to_le32(di->uniaddr), + .blocks_lo = cpu_to_le32(di->blocks), + .blocks_hi = cpu_to_le16(di->blocks >> 32), + .uniaddr_hi = cpu_to_le16(di->uniaddr >> 32), }; - memcpy(dis.tag, sbi->devs[i].tag, sizeof(dis.tag)); + memcpy(dis.tag, di->tag, sizeof(dis.tag)); ret = erofs_dev_write(sbi, &dis, pos, sizeof(dis)); if (ret) return ret; pos += sizeof(dis); - nblocks += sbi->devs[i].blocks; - } while (++i < sbi->extra_devices); + } while (++di < sbi->devs + sbi->extra_devices); bh->op = &erofs_drop_directly_bhops; erofs_bdrop(bh, false); sbi->bh_devt = NULL; -out: - sbi->total_blocks = nblocks; return 0; } diff --git a/lib/tar.c b/lib/tar.c index cbe9f40..f027532 100644 --- a/lib/tar.c +++ b/lib/tar.c @@ -691,7 +691,7 @@ static int tarerofs_write_uncompressed_file(struct erofs_inode *inode, inode->datalayout = EROFS_INODE_FLAT_PLAIN; nblocks = DIV_ROUND_UP(inode->i_size, 1U << sbi->blkszbits); - ret = erofs_allocate_inode_bh_data(inode, nblocks, false); + ret = erofs_allocate_inode_bh_data(inode, nblocks, 0); if (ret) return ret; diff --git a/mkfs/main.c b/mkfs/main.c index 688e474..cfdffa5 100644 --- a/mkfs/main.c +++ b/mkfs/main.c @@ -1508,11 +1508,6 @@ static int mkfs_parse_options_cfg(struct erofs_importer_params *params, } } - if (mkfscfg.blobdev_path && mkfscfg.chunkbits < mkfs_blkszbits) { - erofs_err("--blobdev must be used together with --chunksize"); - return -EINVAL; - } - /* TODO: can be implemented with (deviceslot) mapped_blkaddr */ if (mkfscfg.blobdev_path && cfg.c_force_chunkformat == FORCE_INODE_BLOCK_MAP) { @@ -1533,6 +1528,11 @@ static int mkfs_parse_options_cfg(struct erofs_importer_params *params, err = mkfs_parse_sources(argc, argv, optind); if (err) return err; + + if (mkfscfg.blobdev_path && source_mode == EROFS_MKFS_SOURCE_REBUILD) { + erofs_err("--blobdev is currently incompatible with rebuild mode"); + return -EINVAL; + } } else if (source_mode != EROFS_MKFS_SOURCE_TAR) { erofs_err("missing argument: SOURCE(s)"); return -EINVAL; @@ -1926,10 +1926,7 @@ int main(int argc, char **argv) erofs_strerror(err)); goto exit; } - } - - if (tar_index_512b || mkfscfg.chunkbits) { - if (g_sbi.extra_devices && mkfscfg.blobdev_path) { + if (mkfscfg.blobdev_path) { g_sbi.devs[0].src_path = strdup(mkfscfg.blobdev_path); if (!g_sbi.devs[0].src_path) { err = -ENOMEM; @@ -1942,6 +1939,9 @@ int main(int argc, char **argv) } importer_params.ddev_id_def = mkfscfg.blobdev_path ? 1 : 0; + } + + if (tar_index_512b || mkfscfg.chunkbits) { err = erofs_blob_init(&g_sbi, mkfscfg.chunkbits); if (err) goto exit; @@ -2052,12 +2052,6 @@ int main(int argc, char **argv) } } - if (erofstar.index_mode || mkfscfg.chunkbits || g_sbi.extra_devices) { - err = erofs_mkfs_dump_blobs(&g_sbi); - if (err) - goto exit; - } - err = erofs_importer_flush_all(&importer); if (err) goto exit; -- 2.47.3 ^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v3] erofs-utils: mkfs: enable `--blobdev` for flat inode layouts 2026-09-02 15:53 ` [PATCH v2 3/3] erofs-utils: mkfs: enable `--blobdev` for flat inode layouts Gao Xiang @ 2026-09-03 7:57 ` Yifan Zhao 0 siblings, 0 replies; 4+ messages in thread From: Yifan Zhao @ 2026-09-03 7:57 UTC (permalink / raw) To: Gao Xiang; +Cc: linux-erofs From: Gao Xiang <xiang@kernel.org> Add metadata-only image support for PLAIN/INLINE inode layouts: $ mkfs.erofs --blobdev blob.erofs fsmeta.erofs foo/ Follow-up: add `--blobdev` support for compressed inode layouts. Link: https://patch.msgid.link/20260902155333.57247-3-xiang@kernel.org Signed-off-by: Gao Xiang <xiang@kernel.org> Assisted-by: Codex:gpt-5.6-sol Signed-off-by: Yifan Zhao <stopire@gmail.com> --- I would suggest v3 which disables three paths or combinations that cannot currently work correctly: - Flat `--blobdev` with `-m` or `--MZ=i` and no `--chunksize`. - Direct S3 writes when inode data targets an extra device. - The tar no-reorder fast path when inode data targets an extra device. Interdiff against v2: diff --git a/lib/inode.c b/lib/inode.c index 24be613..d71a9d1 100644 --- a/lib/inode.c +++ b/lib/inode.c @@ -201,8 +201,7 @@ int erofs_allocate_inode_bh_data(struct erofs_inode *inode, erofs_blk_t nblocks, int device_id) { struct erofs_sb_info *sbi = inode->sbi; - struct erofs_bufmgr *bmgr = device_id ? - erofs_metadata_bmgr(sbi, false) : sbi->bmgr; + struct erofs_bufmgr *bmgr; struct erofs_buffer_head *bh; int ret, type; diff --git a/lib/remotes/s3.c b/lib/remotes/s3.c index 56ab808..1f2a5e0 100644 --- a/lib/remotes/s3.c +++ b/lib/remotes/s3.c @@ -1053,12 +1053,13 @@ static int s3erofs_remote_getobject(struct erofs_importer *im, return -EIO; resp.pos = 0; - if (!sbi->available_compr_algs && im->params->no_datainline) { + if (!sbi->available_compr_algs && im->params->no_datainline && + !im->params->ddev_id_def) { inode->datalayout = EROFS_INODE_FLAT_PLAIN; inode->idata_size = 0; ret = erofs_allocate_inode_bh_data(inode, DIV_ROUND_UP(inode->i_size, 1U << sbi->blkszbits), - im->params->ddev_id_def); + 0); if (ret) return ret; resp.vf = &sbi->bdev; diff --git a/lib/tar.c b/lib/tar.c index f027532..b979d5a 100644 --- a/lib/tar.c +++ b/lib/tar.c @@ -1207,7 +1207,8 @@ new_inode: ret = -EIO; } else if (tar->try_no_reorder && !sbi->available_compr_algs && - params->no_datainline) { + params->no_datainline && + !params->ddev_id_def) { ret = tarerofs_write_uncompressed_file(inode, tar); } else { ret = tarerofs_write_file_data(inode, tar); diff --git a/mkfs/main.c b/mkfs/main.c index cfdffa5..3d1c5a7 100644 --- a/mkfs/main.c +++ b/mkfs/main.c @@ -1903,6 +1903,12 @@ int main(int argc, char **argv) erofs_err("Compression is not enabled. Turn on chunk-based data deduplication instead."); mkfscfg.chunkbits = g_sbi.blkszbits; } + if (mkfscfg.blobdev_path && !mkfscfg.chunkbits && + (erofs_sb_has_metabox(&g_sbi) || mkfscfg.inode_metazone)) { + erofs_err("--blobdev without --chunksize cannot be used with -m or --MZ=i"); + err = -EINVAL; + goto exit; + } importer_params.chunkszbits_def = mkfscfg.chunkbits; err = erofs_importer_init(&importer); if (err) include/erofs/inode.h | 2 +- include/erofs/internal.h | 1 + lib/blobchunk.c | 12 ---------- lib/importer.c | 5 ++++ lib/inode.c | 49 ++++++++++++++++++++++++---------------- lib/liberofs_chunk.h | 1 - lib/remotes/s3.c | 5 ++-- lib/super.c | 37 +++++++++++++++++++----------- lib/tar.c | 5 ++-- mkfs/main.c | 30 ++++++++++++------------ 10 files changed, 81 insertions(+), 66 deletions(-) diff --git a/include/erofs/inode.h b/include/erofs/inode.h index bf089e8..23848e8 100644 --- a/include/erofs/inode.h +++ b/include/erofs/inode.h @@ -39,7 +39,7 @@ int erofs_iflush(struct erofs_inode *inode); struct erofs_dentry *erofs_d_alloc(struct erofs_inode *parent, const char *name); int erofs_allocate_inode_bh_data(struct erofs_inode *inode, erofs_blk_t nblocks, - bool in_metazone); + int device_id); bool erofs_dentry_is_wht(struct erofs_sb_info *sbi, struct erofs_dentry *d); int __erofs_fill_inode(struct erofs_importer *im, struct erofs_inode *inode, struct stat *st, const char *path); diff --git a/include/erofs/internal.h b/include/erofs/internal.h index 95f5627..4d09c58 100644 --- a/include/erofs/internal.h +++ b/include/erofs/internal.h @@ -461,6 +461,7 @@ void erofs_put_super(struct erofs_sb_info *sbi); int erofs_writesb(struct erofs_sb_info *sbi); struct erofs_buffer_head *erofs_reserve_sb(struct erofs_bufmgr *bmgr); int erofs_mkfs_init_devices(struct erofs_sb_info *sbi, unsigned int devices); +int erofs_update_all_devices(struct erofs_sb_info *sbi); int erofs_write_device_table(struct erofs_sb_info *sbi); int erofs_enable_sb_chksum(struct erofs_sb_info *sbi, u32 *crc); int erofs_superblock_csum_verify(struct erofs_sb_info *sbi); diff --git a/lib/blobchunk.c b/lib/blobchunk.c index 5a90991..8f43dd0 100644 --- a/lib/blobchunk.c +++ b/lib/blobchunk.c @@ -554,18 +554,6 @@ int tarerofs_write_chunkes(struct erofs_inode *inode, erofs_off_t data_offset) return 0; } -int erofs_mkfs_dump_blobs(struct erofs_sb_info *sbi) -{ - struct erofs_device_info *di; - - for (di = sbi->devs; di < sbi->devs + sbi->extra_devices; ++di) { - if (!di->bmgr) - continue; - di->blocks = erofs_mapbh(di->bmgr, NULL); - } - return 0; -} - static int erofs_insert_zerochunk(struct erofs_chunkmgr *cmgr, unsigned int cbitsdef) { diff --git a/lib/importer.c b/lib/importer.c index 2a635d2..89d4d8b 100644 --- a/lib/importer.c +++ b/lib/importer.c @@ -127,6 +127,11 @@ int erofs_importer_flush_all(struct erofs_importer *im) fsalignblks = im->params->fsalignblks ? roundup_pow_of_two(im->params->fsalignblks) : 1; sbi->dif0.blocks = roundup(erofs_mapbh(sbi->bmgr, NULL), fsalignblks); + + err = erofs_update_all_devices(sbi); + if (err) + return err; + err = erofs_write_device_table(sbi); if (err) return err; diff --git a/lib/inode.c b/lib/inode.c index a3fc181..d71a9d1 100644 --- a/lib/inode.c +++ b/lib/inode.c @@ -198,26 +198,32 @@ struct erofs_dentry *erofs_d_alloc(struct erofs_inode *parent, /* allocate main data for an inode */ int erofs_allocate_inode_bh_data(struct erofs_inode *inode, erofs_blk_t nblocks, - bool in_metazone) + int device_id) { struct erofs_sb_info *sbi = inode->sbi; - struct erofs_bufmgr *bmgr = in_metazone ? - erofs_metadata_bmgr(sbi, false) : sbi->bmgr; + struct erofs_bufmgr *bmgr; struct erofs_buffer_head *bh; int ret, type; + if (device_id < 0) + bmgr = erofs_metadata_bmgr(sbi, false); + else if (!device_id) + bmgr = sbi->bmgr; + else + bmgr = sbi->devs[device_id - 1].bmgr; + + if (!bmgr) { + erofs_err("cannot allocate data on unavailable device %d for %s", + device_id, inode->i_srcpath); + return -EINVAL; + } + if (!nblocks) { /* it has only tail-end data */ inode->u.i_blkaddr = EROFS_NULL_ADDR; return 0; } - if (in_metazone && !bmgr) { - erofs_err("cannot allocate data in the metazone when unavailable for %s", - inode->i_srcpath); - return -EINVAL; - } - /* allocate main data buffer */ type = S_ISDIR(inode->i_mode) ? DIRA : DATA; bh = erofs_balloc(bmgr, type, erofs_pos(sbi, nblocks), 0); @@ -232,8 +238,10 @@ int erofs_allocate_inode_bh_data(struct erofs_inode *inode, erofs_blk_t nblocks, DBG_BUGON(ret < 0); /* write blocks except for the tail-end block */ - inode->u.i_blkaddr = bh->block->blkaddr | (in_metazone ? - (sbi->extra_devices + 1ULL) << EROFS_I_BLKADDR_DEV_ID_BIT : 0); + if (device_id < 0) + device_id = sbi->extra_devices + 1; + inode->u.i_blkaddr = bh->block->blkaddr | + ((u64)device_id << EROFS_I_BLKADDR_DEV_ID_BIT); return 0; } @@ -604,7 +612,7 @@ int erofs_write_file_from_buffer(struct erofs_inode *inode, char *buf) inode->datalayout = EROFS_INODE_FLAT_INLINE; - ret = erofs_allocate_inode_bh_data(inode, nblocks, false); + ret = erofs_allocate_inode_bh_data(inode, nblocks, 0); if (ret) return ret; @@ -635,7 +643,7 @@ static bool erofs_file_is_compressible(struct erofs_importer *im, static int erofs_write_unencoded_data(struct erofs_inode *inode, struct erofs_vfile *vf, erofs_off_t fpos, - bool noseek, bool in_metazone) + bool noseek, int device_id) { struct erofs_sb_info *sbi = inode->sbi; struct erofs_buffer_head *bh; @@ -646,7 +654,7 @@ static int erofs_write_unencoded_data(struct erofs_inode *inode, if (!noseek && erofs_sb_has_48bit(sbi)) { if (erofs_io_lseek(vf, fpos, SEEK_DATA) == -ENXIO) { - ret = erofs_allocate_inode_bh_data(inode, 0, false); + ret = erofs_allocate_inode_bh_data(inode, 0, 0); if (ret) return ret; inode->datalayout = EROFS_INODE_FLAT_PLAIN; @@ -663,7 +671,7 @@ static int erofs_write_unencoded_data(struct erofs_inode *inode, remaining = inode->i_size - inode->idata_size; ret = erofs_allocate_inode_bh_data(inode, remaining >> sbi->blkszbits, - in_metazone); + device_id); if (ret) return ret; @@ -724,13 +732,14 @@ static int erofs_write_unencoded_file(const struct erofs_importer *im, if (inode->datasource == EROFS_INODE_DATA_SOURCE_REBUILD_BLOB) { if (erofs_io_lseek(&vf, fpos, SEEK_SET) != (off_t)fpos) return -EIO; - return erofs_write_unencoded_data(inode, &vf, fpos, true, false); + return erofs_write_unencoded_data(inode, &vf, fpos, true, device_id); } inode->datalayout = EROFS_INODE_FLAT_INLINE; /* fallback to all data uncompressed */ return erofs_write_unencoded_data(inode, &vf, fpos, - inode->datasource == EROFS_INODE_DATA_SOURCE_DISKBUF, false); + inode->datasource == EROFS_INODE_DATA_SOURCE_DISKBUF, + device_id); } static int erofs_write_dir_file(const struct erofs_importer *im, @@ -749,7 +758,7 @@ static int erofs_write_dir_file(const struct erofs_importer *im, } else { DBG_BUGON(dir->idata_size != (dir->i_size & (bsz - 1))); err = erofs_write_unencoded_data(dir, vf, 0, true, - im->params->dirdata_in_metazone); + im->params->dirdata_in_metazone ? -1 : 0); } erofs_io_close(vf); return err; @@ -1135,7 +1144,7 @@ static int erofs_write_tail_end(struct erofs_importer *im, params->dirdata_in_metazone; ret = erofs_allocate_inode_bh_data(inode, 1, - in_metazone); + in_metazone ? -1 : params->ddev_id_def); if (ret) return ret; bh = inode->bh_data; @@ -2412,7 +2421,7 @@ struct erofs_inode *erofs_mkfs_build_special_from_fd(struct erofs_importer *im, ret = erofs_write_unencoded_data(inode, &(struct erofs_vfile){ .fd = fd }, 0, inode->datasource == EROFS_INODE_DATA_SOURCE_DISKBUF, - false); + 0); if (ret) return ERR_PTR(ret); out: diff --git a/lib/liberofs_chunk.h b/lib/liberofs_chunk.h index ff31891..16f3d05 100644 --- a/lib/liberofs_chunk.h +++ b/lib/liberofs_chunk.h @@ -24,7 +24,6 @@ int erofs_blob_write_chunked_file(struct erofs_inode *inode, int fd, erofs_off_t startoff, int device_id); int erofs_write_zero_inode(struct erofs_inode *inode); int tarerofs_write_chunkes(struct erofs_inode *inode, erofs_off_t data_offset); -int erofs_mkfs_dump_blobs(struct erofs_sb_info *sbi); int erofs_blob_init(struct erofs_sb_info *sbi, unsigned int chunkbits_zero); int erofs_blob_init_device(struct erofs_sb_info *sbi, int device_id); int erofs_chunkmgr_exit(struct erofs_sb_info *sbi); diff --git a/lib/remotes/s3.c b/lib/remotes/s3.c index b3352df..1f2a5e0 100644 --- a/lib/remotes/s3.c +++ b/lib/remotes/s3.c @@ -1053,12 +1053,13 @@ static int s3erofs_remote_getobject(struct erofs_importer *im, return -EIO; resp.pos = 0; - if (!sbi->available_compr_algs && im->params->no_datainline) { + if (!sbi->available_compr_algs && im->params->no_datainline && + !im->params->ddev_id_def) { inode->datalayout = EROFS_INODE_FLAT_PLAIN; inode->idata_size = 0; ret = erofs_allocate_inode_bh_data(inode, DIV_ROUND_UP(inode->i_size, 1U << sbi->blkszbits), - false); + 0); if (ret) return ret; resp.vf = &sbi->bdev; diff --git a/lib/super.c b/lib/super.c index 9e52dd8..2bb22ac 100644 --- a/lib/super.c +++ b/lib/super.c @@ -414,15 +414,30 @@ int erofs_mkfs_init_devices(struct erofs_sb_info *sbi, unsigned int devices) return 0; } +int erofs_update_all_devices(struct erofs_sb_info *sbi) +{ + struct erofs_device_info *di; + erofs_blk_t last_uniaddr = sbi->dif0.blocks; + + for (di = sbi->devs; di < sbi->devs + sbi->extra_devices; ++di) { + if (di->bmgr) + di->blocks = erofs_mapbh(di->bmgr, NULL); + di->uniaddr = last_uniaddr; + last_uniaddr += di->blocks; + } + sbi->total_blocks = last_uniaddr; + return 0; +} + int erofs_write_device_table(struct erofs_sb_info *sbi) { - erofs_blk_t nblocks = sbi->dif0.blocks; struct erofs_buffer_head *bh = sbi->bh_devt; + struct erofs_device_info *di = sbi->devs; erofs_off_t pos; - unsigned int i, ret; + unsigned int ret; if (!sbi->extra_devices) - goto out; + return 0; if (!bh) { if (erofs_sb_has_device_table(sbi)) return 0; @@ -435,28 +450,24 @@ int erofs_write_device_table(struct erofs_sb_info *sbi) return -EINVAL; } - i = 0; do { struct erofs_deviceslot dis = { - .uniaddr_lo = cpu_to_le32(nblocks), - .blocks_lo = cpu_to_le32(sbi->devs[i].blocks), - .blocks_hi = cpu_to_le16(sbi->devs[i].blocks >> 32), - .uniaddr_hi = cpu_to_le16(nblocks >> 32), + .uniaddr_lo = cpu_to_le32(di->uniaddr), + .blocks_lo = cpu_to_le32(di->blocks), + .blocks_hi = cpu_to_le16(di->blocks >> 32), + .uniaddr_hi = cpu_to_le16(di->uniaddr >> 32), }; - memcpy(dis.tag, sbi->devs[i].tag, sizeof(dis.tag)); + memcpy(dis.tag, di->tag, sizeof(dis.tag)); ret = erofs_dev_write(sbi, &dis, pos, sizeof(dis)); if (ret) return ret; pos += sizeof(dis); - nblocks += sbi->devs[i].blocks; - } while (++i < sbi->extra_devices); + } while (++di < sbi->devs + sbi->extra_devices); bh->op = &erofs_drop_directly_bhops; erofs_bdrop(bh, false); sbi->bh_devt = NULL; -out: - sbi->total_blocks = nblocks; return 0; } diff --git a/lib/tar.c b/lib/tar.c index cbe9f40..b979d5a 100644 --- a/lib/tar.c +++ b/lib/tar.c @@ -691,7 +691,7 @@ static int tarerofs_write_uncompressed_file(struct erofs_inode *inode, inode->datalayout = EROFS_INODE_FLAT_PLAIN; nblocks = DIV_ROUND_UP(inode->i_size, 1U << sbi->blkszbits); - ret = erofs_allocate_inode_bh_data(inode, nblocks, false); + ret = erofs_allocate_inode_bh_data(inode, nblocks, 0); if (ret) return ret; @@ -1207,7 +1207,8 @@ new_inode: ret = -EIO; } else if (tar->try_no_reorder && !sbi->available_compr_algs && - params->no_datainline) { + params->no_datainline && + !params->ddev_id_def) { ret = tarerofs_write_uncompressed_file(inode, tar); } else { ret = tarerofs_write_file_data(inode, tar); diff --git a/mkfs/main.c b/mkfs/main.c index 688e474..3d1c5a7 100644 --- a/mkfs/main.c +++ b/mkfs/main.c @@ -1508,11 +1508,6 @@ static int mkfs_parse_options_cfg(struct erofs_importer_params *params, } } - if (mkfscfg.blobdev_path && mkfscfg.chunkbits < mkfs_blkszbits) { - erofs_err("--blobdev must be used together with --chunksize"); - return -EINVAL; - } - /* TODO: can be implemented with (deviceslot) mapped_blkaddr */ if (mkfscfg.blobdev_path && cfg.c_force_chunkformat == FORCE_INODE_BLOCK_MAP) { @@ -1533,6 +1528,11 @@ static int mkfs_parse_options_cfg(struct erofs_importer_params *params, err = mkfs_parse_sources(argc, argv, optind); if (err) return err; + + if (mkfscfg.blobdev_path && source_mode == EROFS_MKFS_SOURCE_REBUILD) { + erofs_err("--blobdev is currently incompatible with rebuild mode"); + return -EINVAL; + } } else if (source_mode != EROFS_MKFS_SOURCE_TAR) { erofs_err("missing argument: SOURCE(s)"); return -EINVAL; @@ -1903,6 +1903,12 @@ int main(int argc, char **argv) erofs_err("Compression is not enabled. Turn on chunk-based data deduplication instead."); mkfscfg.chunkbits = g_sbi.blkszbits; } + if (mkfscfg.blobdev_path && !mkfscfg.chunkbits && + (erofs_sb_has_metabox(&g_sbi) || mkfscfg.inode_metazone)) { + erofs_err("--blobdev without --chunksize cannot be used with -m or --MZ=i"); + err = -EINVAL; + goto exit; + } importer_params.chunkszbits_def = mkfscfg.chunkbits; err = erofs_importer_init(&importer); if (err) @@ -1926,10 +1932,7 @@ int main(int argc, char **argv) erofs_strerror(err)); goto exit; } - } - - if (tar_index_512b || mkfscfg.chunkbits) { - if (g_sbi.extra_devices && mkfscfg.blobdev_path) { + if (mkfscfg.blobdev_path) { g_sbi.devs[0].src_path = strdup(mkfscfg.blobdev_path); if (!g_sbi.devs[0].src_path) { err = -ENOMEM; @@ -1942,6 +1945,9 @@ int main(int argc, char **argv) } importer_params.ddev_id_def = mkfscfg.blobdev_path ? 1 : 0; + } + + if (tar_index_512b || mkfscfg.chunkbits) { err = erofs_blob_init(&g_sbi, mkfscfg.chunkbits); if (err) goto exit; @@ -2052,12 +2058,6 @@ int main(int argc, char **argv) } } - if (erofstar.index_mode || mkfscfg.chunkbits || g_sbi.extra_devices) { - err = erofs_mkfs_dump_blobs(&g_sbi); - if (err) - goto exit; - } - err = erofs_importer_flush_all(&importer); if (err) goto exit; -- 2.55.0 ^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-09-03 7:57 UTC | newest] Thread overview: 4+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-09-02 15:53 [PATCH v2 1/3] erofs-utils: lib: migrate `c_chunkbits` and `c_blobdev_path` Gao Xiang 2026-09-02 15:53 ` [PATCH v2 2/3] erofs-utils: mkfs: introduce ddev_id_def Gao Xiang 2026-09-02 15:53 ` [PATCH v2 3/3] erofs-utils: mkfs: enable `--blobdev` for flat inode layouts Gao Xiang 2026-09-03 7:57 ` [PATCH v3] " Yifan Zhao
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox