* [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