Linux-EROFS Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 1/4] erofs-utils: record algorithm id in in-memory compression extents
@ 2026-09-15  6:21 Gao Xiang
  2026-09-15  6:21 ` [PATCH v2 2/4] erofs-utils: lib: improve ztailinline fallback Gao Xiang
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Gao Xiang @ 2026-09-15  6:21 UTC (permalink / raw)
  To: linux-erofs; +Cc: Gao Xiang

In order to enable the rebuild mode for compressed inodes.

Signed-off-by: Gao Xiang <xiang@kernel.org>
---
 include/erofs/dedupe.h |  1 +
 lib/compress.c         | 13 ++++++++++---
 lib/dedupe.c           |  3 +++
 3 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/include/erofs/dedupe.h b/include/erofs/dedupe.h
index 14dd7dc..dbcb37c 100644
--- a/include/erofs/dedupe.h
+++ b/include/erofs/dedupe.h
@@ -18,6 +18,7 @@ struct z_erofs_inmem_extent {
 	unsigned int length;
 	unsigned short device_id;
 	bool raw, partial, inlined;
+	char algofmt;
 };
 
 struct z_erofs_dedupe_ctx {
diff --git a/lib/compress.c b/lib/compress.c
index ae09e86..3e8f9b6 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -189,7 +189,9 @@ static void z_erofs_write_full_indexes(struct z_erofs_index_writer *ctx,
 		DBG_BUGON(!e->raw && !inode->idata_size && !inode->fragment_size);
 		DBG_BUGON(e->partial);
 		type = e->raw ? Z_EROFS_LCLUSTER_TYPE_PLAIN :
-			Z_EROFS_LCLUSTER_TYPE_HEAD1;
+			(e->algofmt == inode->z_algorithmtype[0] ?
+				Z_EROFS_LCLUSTER_TYPE_HEAD1 :
+				Z_EROFS_LCLUSTER_TYPE_HEAD2);
 		di.di_advise = cpu_to_le16(type);
 
 		if (inode->datalayout == EROFS_INODE_COMPRESSED_FULL && !e->plen) {
@@ -238,7 +240,9 @@ static void z_erofs_write_full_indexes(struct z_erofs_index_writer *ctx,
 			di.di_u.delta[1] = cpu_to_le16(d1);
 		} else {
 			type = e->raw ? Z_EROFS_LCLUSTER_TYPE_PLAIN :
-				Z_EROFS_LCLUSTER_TYPE_HEAD1;
+				(e->algofmt == inode->z_algorithmtype[0] ?
+					Z_EROFS_LCLUSTER_TYPE_HEAD1 :
+					Z_EROFS_LCLUSTER_TYPE_HEAD2);
 
 			if (inode->datalayout == EROFS_INODE_COMPRESSED_FULL &&
 			    !e->plen) {
@@ -700,6 +704,7 @@ frag_packing:
 		e->inlined = true;
 		e->plen = blksz;
 		e->raw = false;
+		e->algofmt = inode->z_algorithmtype[0];
 	} else {
 		unsigned int padding;
 
@@ -755,6 +760,7 @@ frag_packing:
 		}
 		ctx->poff += e->plen;
 		e->raw = false;
+		e->algofmt = inode->z_algorithmtype[0];
 		may_inline = false;
 		may_packing = false;
 	}
@@ -1233,7 +1239,7 @@ static void z_erofs_write_extents(struct erofs_inode *inode,
 			plen = inode->fragmentoff;
 			pstart = inode->fragmentoff >> 32;
 		} else {
-			fmt = ei->e.raw ? 0 : inode->z_algorithmtype[0] + 1;
+			fmt = ei->e.raw ? 0 : ei->e.algofmt + 1;
 			plen |= fmt << Z_EROFS_EXTENT_PLEN_FMT_BIT;
 			if (ei->e.partial)
 				plen |= Z_EROFS_EXTENT_PLEN_PARTIAL;
@@ -1350,6 +1356,7 @@ int z_erofs_compress_segment(struct z_erofs_compress_sctx *ctx,
 			.raw = false,
 			.partial = false,
 			.pstart = ctx->pstart,
+			.algofmt = inode->z_algorithmtype[0],
 		};
 		init_list_head(&ei->list);
 		z_erofs_commit_extent(ctx, ei);
diff --git a/lib/dedupe.c b/lib/dedupe.c
index 5166f26..ec9e2bb 100644
--- a/lib/dedupe.c
+++ b/lib/dedupe.c
@@ -77,6 +77,7 @@ struct z_erofs_dedupe_item {
 
 	int		original_length;
 	bool		partial, raw;
+	char		algofmt;
 	u8		extra_data[];
 };
 
@@ -144,6 +145,7 @@ int z_erofs_dedupe_match(struct z_erofs_dedupe_ctx *ctx)
 		ctx->e.inlined = false;
 		ctx->e.pstart = e->pstart;
 		ctx->e.plen = e->plen;
+		ctx->e.algofmt = e->algofmt;
 		return 0;
 	}
 	return -ENOENT;
@@ -183,6 +185,7 @@ int z_erofs_dedupe_insert(struct z_erofs_inmem_extent *e,
 	di->plen = e->plen;
 	di->partial = e->partial;
 	di->raw = e->raw;
+	di->algofmt = e->algofmt;
 	di->chain = dedupe_subtree;
 	dedupe_subtree = di;
 	list_add_tail(&di->list, p);
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH v2 2/4] erofs-utils: lib: improve ztailinline fallback
  2026-09-15  6:21 [PATCH v2 1/4] erofs-utils: record algorithm id in in-memory compression extents Gao Xiang
@ 2026-09-15  6:21 ` Gao Xiang
  2026-09-15  6:21 ` [PATCH v2 3/4] erofs-utils: lib: switch to use per-inode big pcluster flag Gao Xiang
  2026-09-15  6:21 ` [PATCH v2 4/4] erofs-utils: mkfs: support rebuild mode for compressed inodes Gao Xiang
  2 siblings, 0 replies; 4+ messages in thread
From: Gao Xiang @ 2026-09-15  6:21 UTC (permalink / raw)
  To: linux-erofs; +Cc: Gao Xiang

Currently, on-disk metadata is dumped in the end,so there is no need
to limit the ztailinline fallback to the last lcluster since we could
adjust the last in-memory extents.

Drop `eof_tailraw` and decompress the inline data instead when
falling back.

Signed-off-by: Gao Xiang <xiang@kernel.org>
---
 include/erofs/internal.h |  4 ---
 lib/compress.c           | 56 +++++++++++++++++++++++++++-------------
 lib/inode.c              | 10 ++++---
 lib/liberofs_compress.h  |  2 +-
 4 files changed, 45 insertions(+), 27 deletions(-)

diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 3ca5553..d905077 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -285,10 +285,6 @@ struct erofs_inode {
 
 	void *idata;
 
-	/* (ztailpacking) in order to recover uncompressed EOF data */
-	void *eof_tailraw;
-	unsigned int eof_tailrawsize;
-
 	union {
 		void *chunkindexes;
 		struct {
diff --git a/lib/compress.c b/lib/compress.c
index 3e8f9b6..ef79eaa 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -26,6 +26,7 @@
 #include "liberofs_compress.h"
 #include "liberofs_fragments.h"
 #include "liberofs_metabox.h"
+#include "erofs/decompress.h"
 
 #define Z_EROFS_DESTBUF_SZ	(Z_EROFS_PCLUSTER_MAX_SIZE + EROFS_MAX_BLOCK_SIZE * 2)
 
@@ -688,15 +689,6 @@ frag_packing:
 		ictx->fragemitted = true;
 	/* tailpcluster should be less than 1 block */
 	} else if (may_inline && len == e->length && compressedsize < blksz) {
-		if (ctx->clusterofs + len <= blksz) {
-			inode->eof_tailraw = malloc(len);
-			if (!inode->eof_tailraw)
-				return -ENOMEM;
-
-			memcpy(inode->eof_tailraw, ctx->queue + ctx->head, len);
-			inode->eof_tailrawsize = len;
-		}
-
 		ret = z_erofs_fill_inline_data(inode, dst,
 				compressedsize, false);
 		if (ret < 0)
@@ -1267,25 +1259,53 @@ static void z_erofs_write_extents(struct erofs_inode *inode,
 	DBG_BUGON(metacur - metabuf != inode->extent_isize);
 }
 
-void z_erofs_drop_inline_pcluster(struct erofs_inode *inode)
+int z_erofs_drop_inline_pcluster(struct erofs_inode *inode)
 {
+	struct erofs_sb_info *sbi = inode->sbi;
 	struct z_erofs_metadata_ctx *ctx = inode->compressmeta;
 	struct z_erofs_extent_item *ei;
+	char raw[EROFS_MAX_BLOCK_SIZE];
+	unsigned int rawsz, encsz;
+	int err;
 
 	inode->z_advise &= ~Z_EROFS_ADVISE_INLINE_PCLUSTER;
-	if (!inode->eof_tailraw)
-		return;
-	DBG_BUGON(inode->idata_type == EROFS_IDATA_TYPE_RAW);
+	if (inode->idata_type == EROFS_IDATA_TYPE_RAW ||
+	    (inode->z_advise & Z_EROFS_ADVISE_INTERLACED_PCLUSTER))
+		return 0;
 
 	ei = list_last_entry(&ctx->extents, struct z_erofs_extent_item, list);
 	DBG_BUGON(ei->e.raw);
-	ei->e.raw = true;
+
+	rawsz = ei->e.length;
+	if (rawsz > erofs_blksiz(sbi))
+		return 0;
+	encsz = inode->idata_size;
+
+	erofs_err("ballooning tail inline data of %s from %u to %u bytes",
+		  inode->i_srcpath, encsz, rawsz);
+	err = z_erofs_decompress(&(struct z_erofs_decompress_req) {
+		.sbi = sbi,
+		.in = inode->idata,
+		.out = raw,
+		.decodedskip = 0,
+		.interlaced_offset = 0,
+		.inputsize = encsz,
+		.decodedlength = rawsz,
+		.alg = ei->e.algofmt,
+		.partial_decoding = false,
+	});
+	if (err < 0)
+		return err;
 	free(inode->idata);
-	/* replace idata with prepared uncompressed data */
-	inode->idata = inode->eof_tailraw;
-	inode->idata_size = inode->eof_tailrawsize;
+	inode->idata_size = 0;
+	inode->idata = malloc(rawsz);
+	if (!inode->idata)
+		return -ENOMEM;
+	memcpy(inode->idata, raw, rawsz);
+	inode->idata_size = rawsz;
 	inode->idata_type = EROFS_IDATA_TYPE_RAW;
-	inode->eof_tailraw = NULL;
+	ei->e.raw = true;
+	return 0;
 }
 
 int z_erofs_compress_segment(struct z_erofs_compress_sctx *ctx,
diff --git a/lib/inode.c b/lib/inode.c
index 62958d1..1e497a0 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -150,7 +150,6 @@ unsigned int erofs_iput(struct erofs_inode *inode)
 		free(d);
 
 	z_erofs_free_metadata(inode);
-	free(inode->eof_tailraw);
 	erofs_remove_ihash(inode);
 	if (!erofs_is_special_identifier(inode->i_srcpath))
 		free(inode->i_srcpath);
@@ -1050,10 +1049,13 @@ static int erofs_prepare_inode_buffer(struct erofs_importer *im,
 	if (bh == ERR_PTR(-ENOSPC)) {
 		int ret;
 
-		if (is_inode_layout_compression(inode))
-			z_erofs_drop_inline_pcluster(inode);
-		else
+		if (is_inode_layout_compression(inode)) {
+			ret = z_erofs_drop_inline_pcluster(inode);
+			if (ret)
+				return ret;
+		} else {
 			inode->datalayout = EROFS_INODE_FLAT_PLAIN;
+		}
 noinline:
 		/* expend an extra block for tail-end data */
 		ret = erofs_prepare_tail_block(inode);
diff --git a/lib/liberofs_compress.h b/lib/liberofs_compress.h
index 50b3804..43227a2 100644
--- a/lib/liberofs_compress.h
+++ b/lib/liberofs_compress.h
@@ -14,7 +14,7 @@
 
 struct z_erofs_compress_ictx;
 
-void z_erofs_drop_inline_pcluster(struct erofs_inode *inode);
+int z_erofs_drop_inline_pcluster(struct erofs_inode *inode);
 void *erofs_prepare_compressed_file(struct erofs_importer *im,
 				    struct erofs_inode *inode);
 void erofs_bind_compressed_file_with_fd(struct z_erofs_compress_ictx *ictx,
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH v2 3/4] erofs-utils: lib: switch to use per-inode big pcluster flag
  2026-09-15  6:21 [PATCH v2 1/4] erofs-utils: record algorithm id in in-memory compression extents Gao Xiang
  2026-09-15  6:21 ` [PATCH v2 2/4] erofs-utils: lib: improve ztailinline fallback Gao Xiang
@ 2026-09-15  6:21 ` Gao Xiang
  2026-09-15  6:21 ` [PATCH v2 4/4] erofs-utils: mkfs: support rebuild mode for compressed inodes Gao Xiang
  2 siblings, 0 replies; 4+ messages in thread
From: Gao Xiang @ 2026-09-15  6:21 UTC (permalink / raw)
  To: linux-erofs; +Cc: Gao Xiang

Some inodes can be non-big-pclusters but the filesystem can have big
pcluster inodes.

Signed-off-by: Gao Xiang <xiang@kernel.org>
---
 lib/compress.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/lib/compress.c b/lib/compress.c
index ef79eaa..cda138f 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -168,6 +168,7 @@ static void z_erofs_write_full_indexes(struct z_erofs_index_writer *ctx,
 {
 	struct erofs_inode *inode = ctx->inode;
 	struct erofs_sb_info *sbi = inode->sbi;
+	bool big_pcluster = inode->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1;
 	unsigned int clusterofs = ctx->clusterofs;
 	unsigned int count = e->length;
 	unsigned int bbits = sbi->blkszbits;
@@ -213,8 +214,7 @@ static void z_erofs_write_full_indexes(struct z_erofs_index_writer *ctx,
 
 	do {
 		advise = 0;
-		/* XXX: big pcluster feature should be per-inode */
-		if (d0 == 1 && erofs_sb_has_big_pcluster(sbi)) {
+		if (d0 == 1 && big_pcluster) {
 			type = Z_EROFS_LCLUSTER_TYPE_NONHEAD;
 			di.di_u.delta[0] = cpu_to_le16((e->plen >> bbits) |
 						       Z_EROFS_LI_D0_CBLKCNT);
@@ -931,7 +931,7 @@ int z_erofs_convert_to_compact_format(struct erofs_inode *inode,
 	unsigned int compacted_4b_initial, compacted_4b_end;
 	unsigned int compacted_2b;
 	bool dummy_head;
-	bool big_pcluster = erofs_sb_has_big_pcluster(sbi);
+	bool big_pcluster = inode->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1;
 	erofs_blk_t blkaddr;
 
 	if (logical_clusterbits < sbi->blkszbits)
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH v2 4/4] erofs-utils: mkfs: support rebuild mode for compressed inodes
  2026-09-15  6:21 [PATCH v2 1/4] erofs-utils: record algorithm id in in-memory compression extents Gao Xiang
  2026-09-15  6:21 ` [PATCH v2 2/4] erofs-utils: lib: improve ztailinline fallback Gao Xiang
  2026-09-15  6:21 ` [PATCH v2 3/4] erofs-utils: lib: switch to use per-inode big pcluster flag Gao Xiang
@ 2026-09-15  6:21 ` Gao Xiang
  2 siblings, 0 replies; 4+ messages in thread
From: Gao Xiang @ 2026-09-15  6:21 UTC (permalink / raw)
  To: linux-erofs; +Cc: Gao Xiang, Jonathan Calmels

Add support for generating a meta-only multidev manifest image with
an overlayfs-like merged tree from multiple compressed EROFS images:

 $ mkfs.erofs -zlz4 -Enoinline_data layerA.erofs layerA/
 $ mkfs.erofs -zlz4 -Enoinline_data layerB.erofs layerB/
 $ mkfs.erofs -zlz4 fsmeta.erofs layerA.erofs layerB.erofs
 # mount -t erofs \
	-odevice=layerA.erofs,device=layerB.erofs
	fsmeta.erofs mnt/

Note that `-Efragments` is not yet supported: it needs further
userspace development.

Cc: Jonathan Calmels <jcalmels@nvidia.com>
Signed-off-by: Gao Xiang <xiang@kernel.org>
---
 lib/compress.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++-
 lib/inode.c    |  18 +++++--
 lib/rebuild.c  |  27 +++++++++-
 3 files changed, 178 insertions(+), 6 deletions(-)

diff --git a/lib/compress.c b/lib/compress.c
index cda138f..08ea5a5 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -1269,11 +1269,36 @@ int z_erofs_drop_inline_pcluster(struct erofs_inode *inode)
 	int err;
 
 	inode->z_advise &= ~Z_EROFS_ADVISE_INLINE_PCLUSTER;
+	ei = list_last_entry(&ctx->extents, struct z_erofs_extent_item, list);
+	if (!inode->bh_data) {
+		struct erofs_buffer_head *bh;
+
+		bh = erofs_balloc(sbi->bmgr, DATA, 0, 0);
+		if (IS_ERR(bh))
+			return PTR_ERR(bh);
+
+		bh->op = &erofs_skip_write_bhops;
+		inode->bh_data = bh;
+		err = erofs_mapbh(NULL, bh->block);
+		if (err < 0) {
+			DBG_BUGON(1);
+			return err;
+		}
+		inode->lazy_tailblock = false;
+		inode->bh_data = bh;
+		ei->e.device_id = 0;
+		ei->e.pstart = erofs_btell(bh, false);
+		if (inode->datalayout == EROFS_INODE_COMPRESSED_COMPACT) {
+			inode->datalayout = EROFS_INODE_COMPRESSED_FULL;
+			inode->z_advise &= ~Z_EROFS_ADVISE_COMPACTED_2B;
+			inode->extent_isize = EROFS_FULL_INDEXES_SZ(inode);
+		}
+	}
+
 	if (inode->idata_type == EROFS_IDATA_TYPE_RAW ||
 	    (inode->z_advise & Z_EROFS_ADVISE_INTERLACED_PCLUSTER))
 		return 0;
 
-	ei = list_last_entry(&ctx->extents, struct z_erofs_extent_item, list);
 	DBG_BUGON(ei->e.raw);
 
 	rawsz = ei->e.length;
@@ -2455,3 +2480,115 @@ int z_erofs_compress_exit(struct erofs_sb_info *sbi)
 	free(sbi->zmgr);
 	return 0;
 }
+
+int z_erofs_rebuild_load_metadata(struct erofs_sb_info *dst_sbi,
+				  struct erofs_inode *inode)
+{
+	struct erofs_sb_info *sbi = inode->sbi;
+	struct erofs_map_blocks map = {
+		.buf = __EROFS_BUF_INITIALIZER,
+		.m_la = 0,
+	};
+	struct z_erofs_extent_item *ei, *n;
+	erofs_off_t pend = EROFS_NULL_ADDR;
+	bool consecutive = true;
+	LIST_HEAD(extents);
+	int err, device_id = -1;
+
+	while (map.m_la < inode->i_size) {
+		struct erofs_map_dev mdev;
+		bool raw;
+
+		err = erofs_map_blocks(inode, &map, EROFS_GET_BLOCKS_FIEMAP);
+		if (err)
+			goto err_out;
+
+		mdev = (struct erofs_map_dev) {
+			.m_deviceid = map.m_deviceid,
+			.m_pa = map.m_pa,
+		};
+		err = erofs_map_dev(sbi, &mdev);
+		if (err)
+			goto err_out;
+
+		raw = (map.m_algorithmformat >= Z_EROFS_COMPRESSION_MAX);
+
+		ei = malloc(sizeof(*ei));
+		if (!ei) {
+			err = -ENOMEM;
+			goto err_out;
+		}
+
+		if (map.m_flags & __EROFS_MAP_FRAGMENT) {
+			DBG_BUGON(!(inode->z_advise &
+					Z_EROFS_ADVISE_FRAGMENT_PCLUSTER));
+			err = -EOPNOTSUPP;
+			goto err_free_ei;
+//			inode->fragment_size = map.m_llen;
+//			DBG_BUGON(inode->fragmentoff != map.m_pa);
+		} else if (map.m_flags & EROFS_MAP_META) {
+			DBG_BUGON(inode->idata_size != map.m_plen);
+			inode->idata = malloc(inode->idata_size);
+			if (!inode->idata) {
+				err = -ENOMEM;
+				goto err_free_ei;
+			}
+			err = erofs_dev_read(sbi, 0, inode->idata, mdev.m_pa,
+					     inode->idata_size);
+			if (err)
+				goto err_free_ei;
+			ei->e = (struct z_erofs_inmem_extent) {
+				.length = map.m_llen,
+				.plen = erofs_blksiz(sbi),
+				.pstart = (pend != EROFS_NULL_ADDR ? pend : 0),
+				.device_id = inode->dev,	/* FIXME! */
+				.raw = raw,
+				.inlined = true,
+			};
+
+			inode->idata_type = (raw ? EROFS_IDATA_TYPE_RAW :
+				EROFS_IDATA_TYPE_COMPRESSED_DEFAULT);
+			DBG_BUGON(map.m_la + map.m_llen != inode->i_size);
+		} else {
+			ei->e = (struct z_erofs_inmem_extent) {
+				.length = map.m_llen,
+				.plen = map.m_plen,
+				.pstart = mdev.m_pa,
+				.device_id = inode->dev,	/* FIXME! */
+				.partial = map.m_flags & EROFS_MAP_PARTIAL_REF,
+				.raw = raw,
+				.inlined = false,
+			};
+			if (pend != EROFS_NULL_ADDR && (pend != ei->e.pstart ||
+			                                device_id != ei->e.device_id))
+				consecutive = false;
+			pend = ei->e.pstart + ei->e.plen;
+			device_id = ei->e.device_id;
+		}
+
+		if (!raw) {
+			ei->e.algofmt = map.m_algorithmformat;
+			if (!(dst_sbi->available_compr_algs & (1 << ei->e.algofmt))) {
+				err = -EOPNOTSUPP;
+				goto err_free_ei;
+			}
+		}
+		init_list_head(&ei->list);
+		list_add_tail(&ei->list, &extents);
+		map.m_la += map.m_llen;
+	}
+	inode->z_lclusterbits = sbi->blkszbits;
+	err = z_erofs_prepare_layout(inode, &extents, consecutive, false);
+	if (err)
+		goto err_out;
+	return 0;
+
+err_free_ei:
+	free(ei);
+err_out:
+	list_for_each_entry_safe(ei, n, &extents, list) {
+		list_del(&ei->list);
+		free(ei);
+	}
+	return err;
+}
diff --git a/lib/inode.c b/lib/inode.c
index 1e497a0..ec96556 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -998,6 +998,16 @@ static bool erofs_inode_need_48bit(struct erofs_inode *inode)
 	return false;
 }
 
+static unsigned int erofs_inode_meta_size(struct erofs_inode *inode)
+{
+	unsigned int inodesize;
+
+	inodesize = inode->inode_isize + inode->xattr_isize;
+	if (inode->extent_isize)
+		inodesize = roundup(inodesize, 8) + inode->extent_isize;
+	return inodesize;
+}
+
 static int erofs_prepare_inode_buffer(struct erofs_importer *im,
 				      struct erofs_inode *inode)
 {
@@ -1017,9 +1027,7 @@ static int erofs_prepare_inode_buffer(struct erofs_importer *im,
 			inode->inode_isize =
 				sizeof(struct erofs_inode_extended);
 	}
-	inodesize = inode->inode_isize + inode->xattr_isize;
-	if (inode->extent_isize)
-		inodesize = roundup(inodesize, 8) + inode->extent_isize;
+	inodesize = erofs_inode_meta_size(inode);
 
 	if (!erofs_is_special_identifier(inode->i_srcpath) && sbi->mxgr)
 		inode->in_metabox = true;
@@ -1053,6 +1061,7 @@ static int erofs_prepare_inode_buffer(struct erofs_importer *im,
 			ret = z_erofs_drop_inline_pcluster(inode);
 			if (ret)
 				return ret;
+			inodesize = erofs_inode_meta_size(inode);
 		} else {
 			inode->datalayout = EROFS_INODE_FLAT_PLAIN;
 		}
@@ -1069,7 +1078,8 @@ noinline:
 		return PTR_ERR(bh);
 	} else if (inode->idata_size) {
 		if (is_inode_layout_compression(inode)) {
-			DBG_BUGON(!params->ztailpacking);
+			DBG_BUGON(!erofs_sb_has_ztailpacking(sbi) &&
+				  !params->ztailpacking);
 			erofs_dbg("Inline %scompressed data (%u bytes) to %s",
 				  inode->idata_type == EROFS_IDATA_TYPE_RAW ? "un": "",
 				  inode->idata_size, inode->i_srcpath);
diff --git a/lib/rebuild.c b/lib/rebuild.c
index 38ced3c..14f91ee 100644
--- a/lib/rebuild.c
+++ b/lib/rebuild.c
@@ -152,7 +152,7 @@ struct erofs_dentry *erofs_rebuild_get_dentry(struct erofs_inode *pwd,
 	return d;
 }
 
-static int erofs_rebuild_write_blob_index(struct erofs_sb_info *dst_sb,
+static int erofs_rebuild_load_chunk_index(struct erofs_sb_info *dst_sb,
 					  struct erofs_inode *inode)
 {
 	int ret;
@@ -222,6 +222,17 @@ err:
 	return ret;
 }
 
+static int erofs_rebuild_write_blob_index(struct erofs_sb_info *dst_sb,
+					  struct erofs_inode *inode)
+{
+	int z_erofs_rebuild_load_metadata(struct erofs_sb_info *dst_sb,
+					  struct erofs_inode *inode);
+
+	if (is_inode_layout_compression(inode))
+		return z_erofs_rebuild_load_metadata(dst_sb, inode);
+	return erofs_rebuild_load_chunk_index(dst_sb, inode);
+}
+
 static int erofs_rebuild_write_full_data(struct erofs_inode *inode)
 {
 	struct erofs_sb_info *src_sbi = inode->sbi;
@@ -497,6 +508,7 @@ out:
 int erofs_rebuild_load_tree(struct erofs_inode *root, struct erofs_sb_info *sbi,
 			    enum erofs_rebuild_datamode mode)
 {
+	struct erofs_sb_info *dst_sbi = root->sbi;
 	struct erofs_inode inode = {};
 	struct erofs_rebuild_dir_context ctx;
 	char uuid_str[37];
@@ -514,6 +526,19 @@ int erofs_rebuild_load_tree(struct erofs_inode *root, struct erofs_sb_info *sbi,
 		return ret;
 	}
 
+	if (mode == EROFS_REBUILD_DATA_BLOB_INDEX) {
+		if (erofs_sb_has_ztailpacking(sbi))
+			erofs_sb_set_ztailpacking(dst_sbi);
+		if (erofs_sb_has_dedupe(sbi))
+			erofs_sb_set_dedupe(dst_sbi);
+		if (erofs_sb_has_big_pcluster(sbi) &&
+		    !erofs_sb_has_big_pcluster(dst_sbi)) {
+			erofs_err("failed to load tree from image %d with big pclusters",
+				  sbi->dev);
+			return -EOPNOTSUPP;
+		}
+	}
+
 	inode.nid = sbi->root_nid;
 	inode.sbi = sbi;
 	ret = erofs_read_inode_from_disk(&inode);
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-09-15  6:23 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-15  6:21 [PATCH v2 1/4] erofs-utils: record algorithm id in in-memory compression extents Gao Xiang
2026-09-15  6:21 ` [PATCH v2 2/4] erofs-utils: lib: improve ztailinline fallback Gao Xiang
2026-09-15  6:21 ` [PATCH v2 3/4] erofs-utils: lib: switch to use per-inode big pcluster flag Gao Xiang
2026-09-15  6:21 ` [PATCH v2 4/4] erofs-utils: mkfs: support rebuild mode for compressed inodes Gao Xiang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox