[PATCH] erofs-utils: fix the previous pcluster CBLKCNT missing for big pcluster dedupe

Gao Xiang hsiangkao at linux.alibaba.com
Thu Sep 21 13:24:17 AEST 2023


Similar to 876bec09e48a ("erofs-utils: lib: fix missing CBLKCNT for
big pcluster dedupe"), the previous CBLKCNT cannot be dropped due to
the extent shortening process.

It may cause data corruption on specific data patterns only if both
big pcluster and dedupe features are enabled.

Fixes: f3f9a2ce3137 ("erofs-utils: mkfs: introduce global compressed data deduplication")
Signed-off-by: Gao Xiang <hsiangkao at linux.alibaba.com>
---
 lib/compress.c | 25 ++++++++++++++++++-------
 1 file changed, 18 insertions(+), 7 deletions(-)

diff --git a/lib/compress.c b/lib/compress.c
index 81f277a..f6dc12a 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -170,6 +170,7 @@ static int z_erofs_compress_dedupe(struct z_erofs_vle_compress_ctx *ctx,
 				   unsigned int *len)
 {
 	struct erofs_inode *inode = ctx->inode;
+	const unsigned int lclustermask = (1 << inode->z_logical_clusterbits) - 1;
 	struct erofs_sb_info *sbi = inode->sbi;
 	int ret = 0;
 
@@ -205,22 +206,32 @@ static int z_erofs_compress_dedupe(struct z_erofs_vle_compress_ctx *ctx,
 		 * decompresssion could be done as another try in practice.
 		 */
 		if (dctx.e.compressedblks > 1 &&
-		    (ctx->clusterofs + ctx->e.length - delta) % erofs_blksiz(sbi) +
-			dctx.e.length < 2 * erofs_blksiz(sbi))
+		    ((ctx->clusterofs + ctx->e.length - delta) & lclustermask) +
+			dctx.e.length < 2 * (lclustermask + 1))
 			break;
 
-		/* fall back to noncompact indexes for deduplication */
-		inode->z_advise &= ~Z_EROFS_ADVISE_COMPACTED_2B;
-		inode->datalayout = EROFS_INODE_COMPRESSED_FULL;
-		erofs_sb_set_dedupe(sbi);
-
 		if (delta) {
 			DBG_BUGON(delta < 0);
 			DBG_BUGON(!ctx->e.length);
+
+			/*
+			 * For big pcluster dedupe, if we decide to shorten the
+			 * previous big pcluster, make sure that the previous
+			 * CBLKCNT is still kept.
+			 */
+			if (ctx->e.compressedblks > 1 &&
+			    (ctx->clusterofs & lclustermask) + ctx->e.length
+				- delta < 2 * (lclustermask + 1))
+				break;
 			ctx->e.partial = true;
 			ctx->e.length -= delta;
 		}
 
+		/* fall back to noncompact indexes for deduplication */
+		inode->z_advise &= ~Z_EROFS_ADVISE_COMPACTED_2B;
+		inode->datalayout = EROFS_INODE_COMPRESSED_FULL;
+		erofs_sb_set_dedupe(sbi);
+
 		sbi->saved_by_deduplication +=
 			dctx.e.compressedblks * erofs_blksiz(sbi);
 		erofs_dbg("Dedupe %u %scompressed data (delta %d) to %u of %u blocks",
-- 
2.24.4



More information about the Linux-erofs mailing list