aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGao Xiang <hsiangkao@linux.alibaba.com>2023-09-21 11:24:17 +0800
committerGao Xiang <hsiangkao@linux.alibaba.com>2023-09-21 11:32:02 +0800
commit06707199af110224b1af6e2990bd775b9ef179f8 (patch)
tree8dedb87afa3eb981e785211dd3fca8d46a6bb315
parent86ac79f05ada667c3b00bc9c46ea017bd07d9672 (diff)
downloaderofs-utils-06707199af110224b1af6e2990bd775b9ef179f8.tar.gz
erofs-utils: fix the previous pcluster CBLKCNT missing for big pcluster dedupe
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. Link: https://lore.kernel.org/r/20230921032417.82739-1-hsiangkao@linux.alibaba.com Fixes: f3f9a2ce3137 ("erofs-utils: mkfs: introduce global compressed data deduplication") Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
-rw-r--r--lib/compress.c25
1 files 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",