[PATCH] erofs-utils: mkfs: also handle last compacted 2B pack in z_erofs_drop_inline_pcluster

Zhiguo Niu <[email protected]>
Newsgroups org.ozlabs.lists.linux-erofs
Message-ID <[email protected]>
With ztailpacking enabled, the current process assumes that a compacted_4b_end
always exists in the compacted pack. However, in some specific files, the
compacted pack may not have a compacted_4b_end. This leads to an incorrect
modification of the last compacted_2B entry, resulting in incorrect modification
of its clusterofs. In subsequent fsck operations, incorrect parameters will
affect the decompression of the penultimate pcluster.

This patch determines whether the last entry of the current compacted pack
belongs to compacted 2B or 4B and then updates the correct bits accordingly.

Fixes: a7c1f0575ef8 ("erofs-utils: lib: refine tailpcluster compression approach")
Signed-off-by: Zhiguo Niu <[email protected]>
---
 lib/compress.c | 38 +++++++++++++++++++++++++++-----------
 1 file changed, 27 insertions(+), 11 deletions(-)

diff --git a/lib/compress.c b/lib/compress.c
index 62d2672..0eb464b 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -1223,19 +1223,35 @@ void z_erofs_drop_inline_pcluster(struct erofs_inode *inode)
 
 		di->di_advise = cpu_to_le16(type);
 	} else if (inode->datalayout == EROFS_INODE_COMPRESSED_COMPACT) {
-		/* handle the last compacted 4B pack */
+		/* handle the last compacted pack */
 		unsigned int eofs, base, pos, v, lo;
 		u8 *out;
-
-		eofs = inode->extent_isize -
-			(4 << (BLK_ROUND_UP(sbi, inode->i_size) & 1));
-		base = round_down(eofs, 8);
-		pos = 16 /* encodebits */ * ((eofs - base) / 4);
-		out = inode->compressmeta + base;
-		lo = erofs_blkoff(sbi, get_unaligned_le32(out + pos / 8));
-		v = (type << sbi->blkszbits) | lo;
-		out[pos / 8] = v & 0xff;
-		out[pos / 8 + 1] = v >> 8;
+		unsigned int compacted_4b_initial, compacted_2b, compacted_4b_end;
+		unsigned int totalidx = BLK_ROUND_UP(sbi, inode->i_size);
+		const erofs_off_t ebase = sizeof(struct z_erofs_map_header) +
+			round_up(erofs_iloc(inode) + inode->inode_isize +
+					inode->xattr_isize, 8);
+
+		compacted_4b_initial = ((32 - ebase % 32) / 4) & 7;
+		compacted_2b = 0;
+		if ((le16_to_cpu(h->h_advise) & Z_EROFS_ADVISE_COMPACTED_2B) &&
+			compacted_4b_initial < totalidx)
+			compacted_2b = rounddown(totalidx - compacted_4b_initial, 16);
+		compacted_4b_end = totalidx - compacted_4b_initial - compacted_2b;
+		if (!compacted_2b || compacted_4b_end) {
+			eofs = inode->extent_isize - (4 << (totalidx & 1));
+			base = round_down(eofs, 8);
+			pos = 16 /* encodebits */ * ((eofs - base) / 4);
+			out = inode->compressmeta + base;
+			lo = erofs_blkoff(sbi, get_unaligned_le32(out + pos / 8));
+			v = (type << sbi->blkszbits) | lo;
+			out[pos / 8] = v & 0xff;
+			out[pos / 8 + 1] = v >> 8;
+		} else {
+			eofs = inode->extent_isize - (4 + 1);
+			out = inode->compressmeta + eofs;
+			*out = (*out & 0x3f) | (type << 6);
+		}
 	} else {
 		DBG_BUGON(1);
 		return;
-- 
1.9.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.