[PATCH 2/3] erofs-utils: lib: introduce API helpers to prepare mkfs context

Gao Xiang hsiangkao at linux.alibaba.com
Wed Aug 20 15:38:05 AEST 2025


 - erofs_mkfs_format_fs  Create a new filesystem

 - erofs_mkfs_load_fs    Load an existing filesystem, especially for
                         incremental builds;

Unlike importer APIs (designed for multiple data sources), this can
only be executed once.

Signed-off-by: Gao Xiang <hsiangkao at linux.alibaba.com>
---
 include/erofs/compress.h |  3 +-
 include/erofs/internal.h |  6 ++-
 lib/cache.c              |  1 +
 lib/compress.c           |  5 +-
 lib/importer.c           |  4 ++
 lib/super.c              | 55 +++++++++++++++++++++-
 mkfs/main.c              | 99 ++++++++++++----------------------------
 7 files changed, 98 insertions(+), 75 deletions(-)

diff --git a/include/erofs/compress.h b/include/erofs/compress.h
index d5b2519..00e7715 100644
--- a/include/erofs/compress.h
+++ b/include/erofs/compress.h
@@ -23,8 +23,7 @@ void z_erofs_drop_inline_pcluster(struct erofs_inode *inode);
 void *erofs_begin_compressed_file(struct erofs_inode *inode, int fd, u64 fpos);
 int erofs_write_compressed_file(struct z_erofs_compress_ictx *ictx);
 
-int z_erofs_compress_init(struct erofs_sb_info *sbi,
-			  struct erofs_buffer_head *bh);
+int z_erofs_compress_init(struct erofs_sb_info *sbi);
 int z_erofs_compress_exit(struct erofs_sb_info *sbi);
 
 const char *z_erofs_list_supported_algorithms(int i, unsigned int *mask);
diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 92e83fd..a609fbd 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -150,6 +150,7 @@ struct erofs_sb_info {
 	struct z_erofs_mgr *zmgr;
 	struct erofs_metaboxmgr *m2gr;
 	struct erofs_packed_inode *packedinode;
+	struct erofs_buffer_head *bh_sb;
 	struct erofs_buffer_head *bh_devt;
 	bool useqpl;
 };
@@ -432,12 +433,15 @@ void liberofs_global_exit(void);
 /* super.c */
 int erofs_read_superblock(struct erofs_sb_info *sbi);
 void erofs_put_super(struct erofs_sb_info *sbi);
-int erofs_writesb(struct erofs_sb_info *sbi, struct erofs_buffer_head *sb_bh);
+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_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);
+int erofs_mkfs_format_fs(struct erofs_sb_info *sbi,
+			 unsigned int blkszbits, unsigned int dsunit);
+int erofs_mkfs_load_fs(struct erofs_sb_info *sbi, unsigned int dsunit);
 
 /* namei.c */
 int erofs_read_inode_from_disk(struct erofs_inode *vi);
diff --git a/lib/cache.c b/lib/cache.c
index 079465e..cd11737 100644
--- a/lib/cache.c
+++ b/lib/cache.c
@@ -533,5 +533,6 @@ erofs_blk_t erofs_total_metablocks(struct erofs_bufmgr *bmgr)
 
 void erofs_buffer_exit(struct erofs_bufmgr *bmgr)
 {
+	DBG_BUGON(!list_empty(&bmgr->blkh.list));
 	free(bmgr);
 }
diff --git a/lib/compress.c b/lib/compress.c
index 0bfad3f..0049199 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -2035,11 +2035,12 @@ static int z_erofs_build_compr_cfgs(struct erofs_sb_info *sbi,
 	return ret;
 }
 
-int z_erofs_compress_init(struct erofs_sb_info *sbi, struct erofs_buffer_head *sb_bh)
+int z_erofs_compress_init(struct erofs_sb_info *sbi)
 {
-	int i, ret, id;
+	struct erofs_buffer_head *sb_bh = sbi->bh_sb;
 	u32 max_dict_size[Z_EROFS_COMPRESSION_MAX] = {};
 	u32 available_compr_algs = 0;
+	int i, ret, id;
 
 	if (!sbi->zmgr) {
 		sbi->zmgr = calloc(1, sizeof(*sbi->zmgr));
diff --git a/lib/importer.c b/lib/importer.c
index a65fa39..95f006d 100644
--- a/lib/importer.c
+++ b/lib/importer.c
@@ -39,6 +39,7 @@ void erofs_importer_global_init(void)
 int erofs_importer_init(struct erofs_importer *im)
 {
 	struct erofs_sb_info *sbi = im->sbi;
+	struct erofs_importer_params *params = im->params;
 	const char *subsys = NULL;
 	int err;
 
@@ -67,6 +68,9 @@ int erofs_importer_init(struct erofs_importer *im)
 		if (err)
 			goto out_err;
 	}
+
+	if (params->dot_omitted)
+		erofs_sb_set_48bit(sbi);
 	return 0;
 
 out_err:
diff --git a/lib/super.c b/lib/super.c
index 57849fb..97d955f 100644
--- a/lib/super.c
+++ b/lib/super.c
@@ -172,8 +172,9 @@ void erofs_put_super(struct erofs_sb_info *sbi)
 	}
 }
 
-int erofs_writesb(struct erofs_sb_info *sbi, struct erofs_buffer_head *sb_bh)
+int erofs_writesb(struct erofs_sb_info *sbi)
 {
+	struct erofs_buffer_head *sb_bh = sbi->bh_sb;
 	struct erofs_super_block sb = {
 		.magic     = cpu_to_le32(EROFS_SUPER_MAGIC_V1),
 		.blkszbits = sbi->blkszbits,
@@ -408,3 +409,55 @@ out:
 	sbi->total_blocks = nblocks;
 	return 0;
 }
+
+int erofs_mkfs_format_fs(struct erofs_sb_info *sbi,
+			 unsigned int blkszbits, unsigned int dsunit)
+{
+	struct erofs_buffer_head *bh;
+	struct erofs_bufmgr *bmgr;
+
+	sbi->blkszbits = blkszbits;
+	bmgr = erofs_buffer_init(sbi, 0, NULL);
+	if (!bmgr)
+		return -ENOMEM;
+	sbi->bmgr = bmgr;
+	bmgr->dsunit = dsunit;
+
+	bh = erofs_reserve_sb(bmgr);
+	if (IS_ERR(bh))
+		return PTR_ERR(bh);
+	sbi->bh_sb = bh;
+	return 0;
+}
+
+int erofs_mkfs_load_fs(struct erofs_sb_info *sbi, unsigned int dsunit)
+{
+	union {
+		struct stat st;
+		erofs_blk_t startblk;
+	} u;
+	struct erofs_bufmgr *bmgr;
+	int err;
+
+	sbi->bh_sb = NULL;
+	erofs_warn("EXPERIMENTAL incremental build in use. Use at your own risk!");
+	err = erofs_read_superblock(sbi);
+	if (err) {
+		erofs_err("failed to read superblock of %s: %s", sbi->devname,
+			  erofs_strerror(err));
+		return err;
+	}
+
+	err = erofs_io_fstat(&sbi->bdev, &u.st);
+	if (!err && S_ISREG(u.st.st_mode))
+		u.startblk = DIV_ROUND_UP(u.st.st_size, erofs_blksiz(sbi));
+	else
+		u.startblk = sbi->primarydevice_blocks;
+
+	bmgr = erofs_buffer_init(sbi, u.startblk, NULL);
+	if (!bmgr)
+		return -ENOMEM;
+	sbi->bmgr = bmgr;
+	bmgr->dsunit = dsunit;
+	return 0;
+}
diff --git a/mkfs/main.c b/mkfs/main.c
index 0a8f477..d2950b7 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -372,6 +372,7 @@ static int erofs_mkfs_feat_set_48bit(bool en, const char *val,
 }
 
 static bool mkfs_dot_omitted;
+static unsigned char mkfs_blkszbits;
 
 static int erofs_mkfs_feat_set_dot_omitted(bool en, const char *val,
 					   unsigned int vallen)
@@ -884,7 +885,7 @@ static int mkfs_parse_options_cfg(struct erofs_importer_params *params,
 				erofs_err("invalid block size %s", optarg);
 				return -EINVAL;
 			}
-			g_sbi.blkszbits = ilog2(i);
+			mkfs_blkszbits = ilog2(i);
 			break;
 
 		case 'd':
@@ -1234,7 +1235,7 @@ static int mkfs_parse_options_cfg(struct erofs_importer_params *params,
 		}
 	}
 
-	if (cfg.c_blobdev_path && cfg.c_chunkbits < g_sbi.blkszbits) {
+	if (cfg.c_blobdev_path && cfg.c_chunkbits < mkfs_blkszbits) {
 		erofs_err("--blobdev must be used together with --chunksize");
 		return -EINVAL;
 	}
@@ -1283,8 +1284,8 @@ static int mkfs_parse_options_cfg(struct erofs_importer_params *params,
 	}
 
 	if (pclustersize_max) {
-		if (pclustersize_max < erofs_blksiz(&g_sbi) ||
-		    pclustersize_max % erofs_blksiz(&g_sbi)) {
+		if (pclustersize_max < (1U << mkfs_blkszbits) ||
+		    pclustersize_max % (1U << mkfs_blkszbits)) {
 			erofs_err("invalid physical clustersize %u",
 				  pclustersize_max);
 			return -EINVAL;
@@ -1292,15 +1293,15 @@ static int mkfs_parse_options_cfg(struct erofs_importer_params *params,
 		cfg.c_mkfs_pclustersize_max = pclustersize_max;
 		cfg.c_mkfs_pclustersize_def = cfg.c_mkfs_pclustersize_max;
 	}
-	if (cfg.c_chunkbits && cfg.c_chunkbits < g_sbi.blkszbits) {
+	if (cfg.c_chunkbits && cfg.c_chunkbits < mkfs_blkszbits) {
 		erofs_err("chunksize %u must be larger than block size",
 			  1u << cfg.c_chunkbits);
 		return -EINVAL;
 	}
 
 	if (pclustersize_packed) {
-		if (pclustersize_packed < erofs_blksiz(&g_sbi) ||
-		    pclustersize_packed % erofs_blksiz(&g_sbi)) {
+		if (pclustersize_packed < (1U << mkfs_blkszbits) ||
+		    pclustersize_packed % (1U << mkfs_blkszbits)) {
 			erofs_err("invalid pcluster size for the packed file %u",
 				  pclustersize_packed);
 			return -EINVAL;
@@ -1310,8 +1311,8 @@ static int mkfs_parse_options_cfg(struct erofs_importer_params *params,
 
 	if (pclustersize_metabox >= 0) {
 		if (pclustersize_metabox &&
-		    (pclustersize_metabox < erofs_blksiz(&g_sbi) ||
-		     pclustersize_metabox % erofs_blksiz(&g_sbi))) {
+		    (pclustersize_metabox < (1U << mkfs_blkszbits) ||
+		     pclustersize_metabox % (1U << mkfs_blkszbits))) {
 			erofs_err("invalid pcluster size %u for the metabox inode",
 				  pclustersize_metabox);
 			return -EINVAL;
@@ -1334,8 +1335,8 @@ static void erofs_mkfs_default_options(void)
 	cfg.c_mt_workers = erofs_get_available_processors();
 	cfg.c_mkfs_segment_size = 16ULL * 1024 * 1024;
 #endif
-	g_sbi.blkszbits = ilog2(min_t(u32, getpagesize(), EROFS_MAX_BLOCK_SIZE));
-	cfg.c_mkfs_pclustersize_max = erofs_blksiz(&g_sbi);
+	mkfs_blkszbits = ilog2(min_t(u32, getpagesize(), EROFS_MAX_BLOCK_SIZE));
+	cfg.c_mkfs_pclustersize_max = 1U << mkfs_blkszbits;
 	cfg.c_mkfs_pclustersize_def = cfg.c_mkfs_pclustersize_max;
 	g_sbi.feature_incompat = EROFS_FEATURE_INCOMPAT_ZERO_PADDING;
 	g_sbi.feature_compat = EROFS_FEATURE_COMPAT_SB_CHKSUM |
@@ -1468,7 +1469,7 @@ static void erofs_mkfs_showsummaries(void)
 		"Filesystem total inodes: %llu\n"
 		"Filesystem %s metadata blocks: %llu\n"
 		"Filesystem %s deduplicated bytes (of source files): %llu\n",
-		uuid_str, g_sbi.total_blocks | 0ULL, 1U << g_sbi.blkszbits,
+		uuid_str, g_sbi.total_blocks | 0ULL, 1U << mkfs_blkszbits,
 		g_sbi.inos | 0ULL,
 		incr, erofs_total_metablocks(g_sbi.bmgr) | 0ULL,
 		incr, g_sbi.saved_by_deduplication | 0ULL);
@@ -1481,7 +1482,6 @@ int main(int argc, char **argv)
 		.params = &importer_params,
 		.sbi = &g_sbi,
 	};
-	struct erofs_buffer_head *sb_bh;
 	struct erofs_inode *root = NULL;
 	bool tar_index_512b = false;
 	struct timeval t;
@@ -1539,16 +1539,6 @@ int main(int argc, char **argv)
 #endif
 	erofs_show_config();
 
-	importer_params.source = cfg.c_src_path;
-	importer_params.no_datainline = mkfs_no_datainline;
-	importer_params.dot_omitted = mkfs_dot_omitted;
-	if (importer_params.dot_omitted)
-		erofs_sb_set_48bit(&g_sbi);
-
-	err = erofs_importer_init(&importer);
-	if (err)
-		goto exit;
-
 #ifndef NDEBUG
 	if (cfg.c_random_pclusterblks)
 		srand(time(NULL));
@@ -1570,7 +1560,7 @@ int main(int argc, char **argv)
 			 * If mapfile is unspecified for tarfs index mode,
 			 * 512-byte block size is enforced here.
 			 */
-			g_sbi.blkszbits = 9;
+			mkfs_blkszbits = 9;
 			tar_index_512b = true;
 		}
 	} else if (source_mode == EROFS_MKFS_SOURCE_REBUILD) {
@@ -1586,46 +1576,15 @@ int main(int argc, char **argv)
 			erofs_err("failed to read superblock of %s", src->devname);
 			goto exit;
 		}
-		g_sbi.blkszbits = src->blkszbits;
+		mkfs_blkszbits = src->blkszbits;
 	}
 
-	if (!incremental_mode) {
-		g_sbi.bmgr = erofs_buffer_init(&g_sbi, 0, NULL);
-		if (!g_sbi.bmgr) {
-			err = -ENOMEM;
-			goto exit;
-		}
-		sb_bh = erofs_reserve_sb(g_sbi.bmgr);
-		if (IS_ERR(sb_bh)) {
-			err = PTR_ERR(sb_bh);
-			goto exit;
-		}
-	} else {
-		union {
-			struct stat st;
-			erofs_blk_t startblk;
-		} u;
-
-		erofs_warn("EXPERIMENTAL incremental build in use. Use at your own risk!");
-		err = erofs_read_superblock(&g_sbi);
-		if (err) {
-			erofs_err("failed to read superblock of %s", g_sbi.devname);
-			goto exit;
-		}
-
-		err = erofs_io_fstat(&g_sbi.bdev, &u.st);
-		if (!err && S_ISREG(u.st.st_mode))
-			u.startblk = DIV_ROUND_UP(u.st.st_size, erofs_blksiz(&g_sbi));
-		else
-			u.startblk = g_sbi.primarydevice_blocks;
-		g_sbi.bmgr = erofs_buffer_init(&g_sbi, u.startblk, NULL);
-		if (!g_sbi.bmgr) {
-			err = -ENOMEM;
-			goto exit;
-		}
-		sb_bh = NULL;
-	}
-	g_sbi.bmgr->dsunit = dsunit;
+	if (!incremental_mode)
+		err = erofs_mkfs_format_fs(&g_sbi, mkfs_blkszbits, dsunit);
+	else
+		err = erofs_mkfs_load_fs(&g_sbi, dsunit);
+	if (err)
+		goto exit;
 
 	/* Use the user-defined UUID or generate one for clean builds */
 	if (valid_fixeduuid)
@@ -1650,13 +1609,20 @@ int main(int argc, char **argv)
 		goto exit;
 	}
 
-	err = z_erofs_compress_init(&g_sbi, sb_bh);
+	err = z_erofs_compress_init(&g_sbi);
 	if (err) {
 		erofs_err("failed to initialize compressor: %s",
 			  erofs_strerror(err));
 		goto exit;
 	}
 
+	importer_params.source = cfg.c_src_path;
+	importer_params.no_datainline = mkfs_no_datainline;
+	importer_params.dot_omitted = mkfs_dot_omitted;
+	err = erofs_importer_init(&importer);
+	if (err)
+		goto exit;
+
 	if (cfg.c_dedupe) {
 		if (!cfg.c_compr_opts[0].alg) {
 			erofs_err("Compression is not enabled.  Turn on chunk-based data deduplication instead.");
@@ -1771,12 +1737,7 @@ int main(int argc, char **argv)
 	erofs_iput(root);
 	root = NULL;
 
-	err = erofs_writesb(&g_sbi, sb_bh);
-	if (err)
-		goto exit;
-
-	/* flush all remaining buffers */
-	err = erofs_bflush(g_sbi.bmgr, NULL);
+	err = erofs_writesb(&g_sbi);
 	if (err)
 		goto exit;
 
-- 
2.43.5



More information about the Linux-erofs mailing list