From db38b6f015a4e964856175380ec1f86c76625892 Mon Sep 17 00:00:00 2001 From: xuchenchen Date: Fri, 14 Nov 2025 16:37:39 +0800 Subject: [PATCH] libext2fs: fix ind_punch recursive block computation --- ...nd_punch-recursive-block-computation.patch | 111 ++++++++++++++++++ e2fsprogs.spec | 6 +- 2 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 0023-fix-ind_punch-recursive-block-computation.patch diff --git a/0023-fix-ind_punch-recursive-block-computation.patch b/0023-fix-ind_punch-recursive-block-computation.patch new file mode 100644 index 0000000..6639fc8 --- /dev/null +++ b/0023-fix-ind_punch-recursive-block-computation.patch @@ -0,0 +1,111 @@ +From c49656b16a7dd7e5fa6e2b754e02287bc0cf4908 Mon Sep 17 00:00:00 2001 +From: "Darrick J. Wong" +Date: Wed, 8 Oct 2025 12:04:49 -0700 +Subject: [PATCH] libext2fs: fix ind_punch recursive block computation + +generic/742 writes a large file and calls punch-alternating to punch out +every other block in the file. Unfortunately, there's a bug in +ind_punch that causes it to turn a request to punch out file block 2060 +into punching out every file block *starting* at block 2060. The +emptying out of the block mapping causes a FIEMAP call in that test to +loop forever, which causes fuse4fs testing of ext3 to halt. + +ext2fs_punch_ind recursively calls ind_punch on each level of the +indirect map to unmap file blocks. The start and count parameters to +ind_punch are (I think) the file range to punch given a particular block +and level within the indirect map, but shifted down by the start of the +logical file range mapped by that level in the indirect tree. To call +ind_punch for the next level down, we need to compute the new range. +But first, a diversion back to the failing testcase: + +Note that file block 2060 is the first block mapped by the second +double-indirect block in the file: + +(0-11):935-946, (IND):947, (12-1035):948-1971, (DIND):1972, (IND):1973, +(1036-2059):1974-2997, (IND):2998, (2060-3083):2999-4022, (IND):4023, +(3084-4107):4024-5047, (IND):5048, (4108-5131):5049-6072, (IND):6073, +(5132-6155):6074-7097, (IND):7098, (6156-7179):7099-8122, (IND):8123, +(7180-8203):8124-9147, (IND):9148, (8204-9227):9149-10172, (IND):10173, +(9228-9999):10174-10945 TOTAL: 10011 + +At this point, enabling PUNCH_DEBUG produces the following: + +FUSE4FS (sda): tid=72529 fuse4fs_punch_range: ino=53 mode=0x3 offset=0x80c000 len=0x1000 start=0x80c end=0x80d +Main loop level 0, start 2060 count 1 max 12 num 12 +Main loop level 1, start 2048 count 1 max 1024 num 1 +Main loop level 2, start 1024 count 1 max 1048576 num 1 +Entering ind_punch, level 2, start 1024, count 1, max 1 +Reading indirect block 1972 +start 1024 offset 0 start2 1024 count 1 count2 1 +Entering ind_punch, level 1, start 1024, count 1, max 1024 +Reading indirect block 2998 +start 1024 offset 1024 start2 0 count 1 count2 1 +Entering ind_punch, level 0, start 0, count 18446744073709550593, max 1024 + +This is wrong, because we want to punch *one* block, not some gigantic +number of blocks! This huge value is actually -1023, which is the +result of the expression (count - offset). Ooops, that's why we unmap +every block in this indirect block! + +Note the suspicious 7th argument to the nested ind_punch call: + + count - offset + +This doesn't smell right, because we're subtracting a position from a +length. The end of the range for the next level down should be the +difference between the end and the start of the range in the current +level after accounting for our current position within that level. In +other words, the smaller of end - start and end - offset. + +Cc: # v1.42 +Fixes: 3adb9374fb9273 ("libext2fs: Add new function ext2fs_punch()") +Signed-off-by: "Darrick J. Wong" +--- + lib/ext2fs/punch.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/lib/ext2fs/punch.c b/lib/ext2fs/punch.c +index 19b6a3782..c48e74ef7 100644 +--- a/lib/ext2fs/punch.c ++++ b/lib/ext2fs/punch.c +@@ -54,6 +54,7 @@ static errcode_t ind_punch(ext2_filsys fs, struct ext2_inode *inode, + blk_t b; + int i; + blk64_t offset, incr; ++ const blk64_t end = start + count; + int freed = 0; + + #ifdef PUNCH_DEBUG +@@ -62,13 +63,14 @@ static errcode_t ind_punch(ext2_filsys fs, struct ext2_inode *inode, + #endif + incr = 1ULL << ((EXT2_BLOCK_SIZE_BITS(fs->super) - 2) * level); + for (i = 0, offset = 0; i < max; i++, p++, offset += incr) { +- if (offset >= start + count) ++ if (offset >= end) + break; + if (*p == 0 || (offset+incr) <= start) + continue; + b = *p; + if (level > 0) { + blk_t start2; ++ blk_t count2; + #ifdef PUNCH_DEBUG + printf("Reading indirect block %u\n", b); + #endif +@@ -76,9 +78,15 @@ static errcode_t ind_punch(ext2_filsys fs, struct ext2_inode *inode, + if (retval) + return retval; + start2 = (start > offset) ? start - offset : 0; ++ count2 = end - ((start > offset) ? start : offset); ++#ifdef PUNCH_DEBUG ++ printf("start %llu offset %llu count %llu end %llu " ++ "incr %llu start2 %u count2 %u\n", start, ++ offset, count, end, incr, start2, count2); ++#endif + retval = ind_punch(fs, inode, block_buf + fs->blocksize, + (blk_t *) block_buf, level - 1, +- start2, count - offset, ++ start2, count2, + fs->blocksize >> 2); + if (retval) + return retval; diff --git a/e2fsprogs.spec b/e2fsprogs.spec index a1a71af..73bce5e 100644 --- a/e2fsprogs.spec +++ b/e2fsprogs.spec @@ -1,6 +1,6 @@ Name: e2fsprogs Version: 1.47.0 -Release: 10 +Release: 11 Summary: Second extended file system management tools License: GPLv2+ and LGPLv2 and MIT URL: http://e2fsprogs.sourceforge.net/ @@ -29,6 +29,7 @@ Patch19: 0019-e2fsck-fix-acl-block-leak-when-process-orphan-list.patch Patch20: 0020-e2fsck-fix-handling-of-a-invalid-symlink-in-an-inlin.patch Patch21: 0021-e2fsprogs-modify-dumpe2fs-to-report-free-block-range.patch Patch22: 0022-resize2fs-use-Direct-I-O-when-reading-the-superblock.patch +Patch23: 0023-fix-ind_punch-recursive-block-computation.patch BuildRequires: gcc pkgconfig texinfo BuildRequires: fuse-devel libblkid-devel libuuid-devel @@ -169,6 +170,9 @@ exit 0 %{_mandir}/man8/* %changelog +* Fri Nov 14 2025 xuchenchen - 1.47.0-11 +- libext2fs: fix ind_punch recursive block computation + * Thu Jul 24 2025 zhangjian - 1.47.0-10 - backport bugfix from upstream -- Gitee