[PATCH] erofs-utils: mkfs: introduce `--fsalignblks` option

Gao Xiang hsiangkao at linux.alibaba.com
Wed Jun 11 02:56:33 AEST 2025


Sometimes, we'd like the filesystem image aligned with a specific value.

For example, specifying 8 with 512-byte filesystem blocks aligns the
filesystem size to 4096 bytes instead of 512 bytes.

Signed-off-by: Gao Xiang <hsiangkao at linux.alibaba.com>
---
 include/erofs/blobchunk.h |  1 -
 include/erofs/internal.h  |  6 ++--
 lib/blobchunk.c           | 56 ++-----------------------------
 lib/super.c               | 69 ++++++++++++++++++++++++++++++++++++---
 man/mkfs.erofs.1          |  4 +++
 mkfs/main.c               | 30 +++++++++++++----
 6 files changed, 99 insertions(+), 67 deletions(-)

diff --git a/include/erofs/blobchunk.h b/include/erofs/blobchunk.h
index ebe2efe..619155f 100644
--- a/include/erofs/blobchunk.h
+++ b/include/erofs/blobchunk.h
@@ -24,7 +24,6 @@ int tarerofs_write_chunkes(struct erofs_inode *inode, erofs_off_t data_offset);
 int erofs_mkfs_dump_blobs(struct erofs_sb_info *sbi);
 void erofs_blob_exit(void);
 int erofs_blob_init(const char *blobfile_path, erofs_off_t chunksize);
-int erofs_mkfs_init_devices(struct erofs_sb_info *sbi, unsigned int devices);
 
 #ifdef __cplusplus
 }
diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index e89a1e4..5e86943 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -144,6 +144,7 @@ struct erofs_sb_info {
 	struct erofs_bufmgr *bmgr;
 	struct z_erofs_mgr *zmgr;
 	struct erofs_packed_inode *packedinode;
+	struct erofs_buffer_head *bh_devt;
 	bool useqpl;
 };
 
@@ -412,9 +413,10 @@ struct erofs_map_dev {
 /* 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,
-		  erofs_blk_t *blocks);
+int erofs_writesb(struct erofs_sb_info *sbi, struct erofs_buffer_head *sb_bh);
 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);
 
 /* namei.c */
diff --git a/lib/blobchunk.c b/lib/blobchunk.c
index 4fc6c77..8c55277 100644
--- a/lib/blobchunk.c
+++ b/lib/blobchunk.c
@@ -31,8 +31,6 @@ static struct hashmap blob_hashmap;
 static int blobfile = -1;
 static erofs_blk_t remapped_base;
 static erofs_off_t datablob_size;
-static bool multidev;
-static struct erofs_buffer_head *bh_devt;
 struct erofs_blobchunk erofs_holechunk = {
 	.blkaddr = EROFS_NULL_ADDR,
 };
@@ -493,30 +491,8 @@ int erofs_mkfs_dump_blobs(struct erofs_sb_info *sbi)
 			datablob_size = length;
 	}
 
-	if (sbi->extra_devices) {
-		unsigned int i, ret;
-		erofs_blk_t nblocks;
-
-		nblocks = erofs_mapbh(sbi->bmgr, NULL);
-		pos_out = erofs_btell(bh_devt, false);
-		i = 0;
-		do {
-			struct erofs_deviceslot dis = {
-				.mapped_blkaddr = cpu_to_le32(nblocks),
-				.blocks = cpu_to_le32(sbi->devs[i].blocks),
-			};
-
-			memcpy(dis.tag, sbi->devs[i].tag, sizeof(dis.tag));
-			ret = erofs_dev_write(sbi, &dis, pos_out, sizeof(dis));
-			if (ret)
-				return ret;
-			pos_out += sizeof(dis);
-			nblocks += sbi->devs[i].blocks;
-		} while (++i < sbi->extra_devices);
-		bh_devt->op = &erofs_drop_directly_bhops;
-		erofs_bdrop(bh_devt, false);
+	if (sbi->extra_devices)
 		return 0;
-	}
 
 	bh = erofs_balloc(sbi->bmgr, DATA, datablob_size, 0);
 	if (IS_ERR(bh))
@@ -612,40 +588,14 @@ static int erofs_insert_zerochunk(erofs_off_t chunksize)
 
 int erofs_blob_init(const char *blobfile_path, erofs_off_t chunksize)
 {
-	if (!blobfile_path) {
+	if (!blobfile_path)
 		blobfile = erofs_tmpfile();
-		multidev = false;
-	} else {
+	else
 		blobfile = open(blobfile_path, O_WRONLY | O_CREAT |
 						O_TRUNC | O_BINARY, 0666);
-		multidev = true;
-	}
 	if (blobfile < 0)
 		return -errno;
 
 	hashmap_init(&blob_hashmap, erofs_blob_hashmap_cmp, 0);
 	return erofs_insert_zerochunk(chunksize);
 }
-
-int erofs_mkfs_init_devices(struct erofs_sb_info *sbi, unsigned int devices)
-{
-	if (!devices)
-		return 0;
-
-	sbi->devs = calloc(devices, sizeof(sbi->devs[0]));
-	if (!sbi->devs)
-		return -ENOMEM;
-
-	bh_devt = erofs_balloc(sbi->bmgr, DEVT,
-		sizeof(struct erofs_deviceslot) * devices, 0);
-	if (IS_ERR(bh_devt)) {
-		free(sbi->devs);
-		return PTR_ERR(bh_devt);
-	}
-	erofs_mapbh(NULL, bh_devt->block);
-	bh_devt->op = &erofs_skip_write_bhops;
-	sbi->devt_slotoff = erofs_btell(bh_devt, false) / EROFS_DEVT_SLOT_SIZE;
-	sbi->extra_devices = devices;
-	erofs_sb_set_device_table(sbi);
-	return 0;
-}
diff --git a/lib/super.c b/lib/super.c
index 6c8fa52..1541838 100644
--- a/lib/super.c
+++ b/lib/super.c
@@ -155,8 +155,7 @@ void erofs_put_super(struct erofs_sb_info *sbi)
 	}
 }
 
-int erofs_writesb(struct erofs_sb_info *sbi, struct erofs_buffer_head *sb_bh,
-		  erofs_blk_t *blocks)
+int erofs_writesb(struct erofs_sb_info *sbi, struct erofs_buffer_head *sb_bh)
 {
 	struct erofs_super_block sb = {
 		.magic     = cpu_to_le32(EROFS_SUPER_MAGIC_V1),
@@ -180,8 +179,7 @@ int erofs_writesb(struct erofs_sb_info *sbi, struct erofs_buffer_head *sb_bh,
 	char *buf;
 	int ret;
 
-	*blocks         = erofs_mapbh(sbi->bmgr, NULL);
-	sb.blocks       = cpu_to_le32(*blocks);
+	sb.blocks       = cpu_to_le32(sbi->primarydevice_blocks);
 	memcpy(sb.uuid, sbi->uuid, sizeof(sb.uuid));
 	memcpy(sb.volume_name, sbi->volume_name, sizeof(sb.volume_name));
 
@@ -283,3 +281,66 @@ int erofs_enable_sb_chksum(struct erofs_sb_info *sbi, u32 *crc)
 
 	return 0;
 }
+
+int erofs_mkfs_init_devices(struct erofs_sb_info *sbi, unsigned int devices)
+{
+	struct erofs_buffer_head *bh;
+
+	if (!devices)
+		return 0;
+
+	sbi->devs = calloc(devices, sizeof(sbi->devs[0]));
+	if (!sbi->devs)
+		return -ENOMEM;
+
+	bh = erofs_balloc(sbi->bmgr, DEVT,
+			  sizeof(struct erofs_deviceslot) * devices, 0);
+	if (IS_ERR(bh)) {
+		free(sbi->devs);
+		sbi->devs = NULL;
+		return PTR_ERR(bh);
+	}
+	erofs_mapbh(NULL, bh->block);
+	bh->op = &erofs_skip_write_bhops;
+	sbi->bh_devt = bh;
+	sbi->devt_slotoff = erofs_btell(bh, false) / EROFS_DEVT_SLOT_SIZE;
+	sbi->extra_devices = devices;
+	erofs_sb_set_device_table(sbi);
+	return 0;
+}
+
+int erofs_write_device_table(struct erofs_sb_info *sbi)
+{
+	erofs_blk_t nblocks = sbi->primarydevice_blocks;
+	struct erofs_buffer_head *bh = sbi->bh_devt;
+	erofs_off_t pos;
+	unsigned int i, ret;
+
+	if (!sbi->extra_devices)
+		goto out;
+	if (!bh)
+		return -EINVAL;
+
+	pos = erofs_btell(bh, false);
+	i = 0;
+	do {
+		struct erofs_deviceslot dis = {
+			.mapped_blkaddr = cpu_to_le32(nblocks),
+			.blocks = cpu_to_le32(sbi->devs[i].blocks),
+		};
+
+		memcpy(dis.tag, sbi->devs[i].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);
+
+	bh->op = &erofs_drop_directly_bhops;
+	erofs_bdrop(bh, false);
+	sbi->bh_devt = NULL;
+out:
+	sbi->total_blocks = nblocks;
+	return 0;
+}
diff --git a/man/mkfs.erofs.1 b/man/mkfs.erofs.1
index ae8411d..48202b6 100644
--- a/man/mkfs.erofs.1
+++ b/man/mkfs.erofs.1
@@ -192,6 +192,10 @@ Set all file UIDs to \fIUID\fR.
 .BI "\-\-force-gid=" GID
 Set all file GIDs to \fIGID\fR.
 .TP
+.BI "\-\-fsalignblks=" #
+Specify the alignment of the primary device size (usually the filesystem size)
+in blocks.
+.TP
 .BI "\-\-gid-offset=" GIDOFFSET
 Add \fIGIDOFFSET\fR to all file GIDs.
 When this option is used together with
diff --git a/mkfs/main.c b/mkfs/main.c
index 79de7a1..16de894 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -89,6 +89,7 @@ static struct option long_options[] = {
 #ifdef EROFS_MT_ENABLED
 	{"async-queue-limit", required_argument, NULL, 530},
 #endif
+	{"fsalignblks", required_argument, NULL, 531},
 	{0, 0, 0, 0},
 };
 
@@ -180,6 +181,7 @@ static void usage(int argc, char **argv)
 #endif
 		" --force-uid=#         set all file uids to # (# = UID)\n"
 		" --force-gid=#         set all file gids to # (# = GID)\n"
+		" --fsalignblks=#       specify the alignment of the primary device size in blocks\n"
 		" --uid-offset=#        add offset # to all file uids (# = id offset)\n"
 		" --gid-offset=#        add offset # to all file gids (# = id offset)\n"
 		" --hard-dereference    dereference hardlinks, add links as separate inodes\n"
@@ -250,6 +252,7 @@ static LIST_HEAD(rebuild_src_list);
 static u8 fixeduuid[16];
 static bool valid_fixeduuid;
 static unsigned int dsunit;
+static unsigned int fsalignblks = 1;
 
 static int erofs_mkfs_feat_set_legacy_compress(bool en, const char *val,
 					       unsigned int vallen)
@@ -896,6 +899,13 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
 			}
 			break;
 #endif
+		case 531:
+			fsalignblks = strtoul(optarg, &endptr, 0);
+			if (*endptr != '\0') {
+				erofs_err("invalid fsalignblks %s", optarg);
+				return -EINVAL;
+			}
+			break;
 		case 'V':
 			version();
 			exit(0);
@@ -1183,7 +1193,7 @@ static int erofs_mkfs_rebuild_load_trees(struct erofs_inode *root)
 	return 0;
 }
 
-static void erofs_mkfs_showsummaries(erofs_blk_t nblocks)
+static void erofs_mkfs_showsummaries(void)
 {
 	char uuid_str[37] = {};
 	char *incr = incremental_mode ? "new" : "total";
@@ -1194,11 +1204,12 @@ static void erofs_mkfs_showsummaries(erofs_blk_t nblocks)
 	erofs_uuid_unparse_lower(g_sbi.uuid, uuid_str);
 
 	fprintf(stdout, "------\nFilesystem UUID: %s\n"
-		"Filesystem total blocks: %u (of %u-byte blocks)\n"
+		"Filesystem total blocks: %llu (of %u-byte blocks)\n"
 		"Filesystem total inodes: %llu\n"
 		"Filesystem %s metadata blocks: %u\n"
 		"Filesystem %s deduplicated bytes (of source files): %llu\n",
-		uuid_str, nblocks, 1U << g_sbi.blkszbits, g_sbi.inos | 0ULL,
+		uuid_str, g_sbi.total_blocks | 0ULL, 1U << g_sbi.blkszbits,
+		g_sbi.inos | 0ULL,
 		incr, erofs_total_metablocks(g_sbi.bmgr),
 		incr, g_sbi.saved_by_deduplication | 0ULL);
 }
@@ -1208,7 +1219,6 @@ int main(int argc, char **argv)
 	int err = 0;
 	struct erofs_buffer_head *sb_bh;
 	struct erofs_inode *root = NULL;
-	erofs_blk_t nblocks = 0;
 	struct timeval t;
 	FILE *blklst = NULL;
 	u32 crc;
@@ -1478,6 +1488,12 @@ int main(int argc, char **argv)
 			goto exit;
 	}
 
+	g_sbi.primarydevice_blocks =
+		roundup(erofs_mapbh(g_sbi.bmgr, NULL), fsalignblks);
+	err = erofs_write_device_table(&g_sbi);
+	if (err)
+		goto exit;
+
 	/* flush all buffers except for the superblock */
 	err = erofs_bflush(g_sbi.bmgr, NULL);
 	if (err)
@@ -1487,7 +1503,7 @@ int main(int argc, char **argv)
 	erofs_iput(root);
 	root = NULL;
 
-	err = erofs_writesb(&g_sbi, sb_bh, &nblocks);
+	err = erofs_writesb(&g_sbi, sb_bh);
 	if (err)
 		goto exit;
 
@@ -1496,7 +1512,7 @@ int main(int argc, char **argv)
 	if (err)
 		goto exit;
 
-	err = erofs_dev_resize(&g_sbi, nblocks);
+	err = erofs_dev_resize(&g_sbi, g_sbi.primarydevice_blocks);
 
 	if (!err && erofs_sb_has_sb_chksum(&g_sbi)) {
 		err = erofs_enable_sb_chksum(&g_sbi, &crc);
@@ -1534,7 +1550,7 @@ exit:
 		return 1;
 	}
 	erofs_update_progressinfo("Build completed.\n");
-	erofs_mkfs_showsummaries(nblocks);
+	erofs_mkfs_showsummaries();
 	erofs_put_super(&g_sbi);
 	return 0;
 }
-- 
2.43.5



More information about the Linux-erofs mailing list