[PATCH 3/8] generic/742: avoid infinite loop if no fiemap results

Darrick J. Wong
2025-10-15T16:37:30Z

From: Darrick J. Wong <djwong@kernel.org>

The fiemap-fault program employed this program looks for deadlocks
between FIEMAP and file page faults by calling the FIEMAP ioctl with a
buffer pointer that is mmaped file range. Unfortunately, the FIEMAP
loop can enter an infinite loop if FIEMAP reports zero extents because
it never changes the last variable.

This shouldn't happen if the filesystem is working correctly, but it
turns out that there's a bug in libext2fs' punch-range code that causes
punch-alternating to unmap all the double-indirect blocks in the file.
This causes the while loop to run forever because last never increases,
which then means that testing fuse2fs with ext2/ext3 grinds to a halt
because fstests doesn't enforce a per-testcase time limit.

Avoid this situation by bailing out if the loop doesn't make forward
progress.

Cc: <fstests@vger.kernel.org> # v2024.03.31
Fixes: 34cdaf0831ee42 ("generic: add a regression test for fiemap into an mmap range")
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
src/fiemap-fault.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/src/fiemap-fault.c b/src/fiemap-fault.c
index 73260068054ede..2bb474c083986d 100644
--- a/src/fiemap-fault.c
+++ b/src/fiemap-fault.c
@@ -55,17 +55,29 @@ int main(int argc, char *argv[])
sizeof(struct fiemap_extent);

while (last < sz) {
+ size_t old_start;
int i;

- fiemap->fm_start = last;
+ fiemap->fm_start = old_start = last;
fiemap->fm_length = sz - last;

ret = ioctl(fd, FS_IOC_FIEMAP, (unsigned long)fiemap);
if (ret < 0)
err(1, "fiemap failed %d", errno);
+ if (fiemap->fm_mapped_extents == 0) {
+ fprintf(stderr, "%s: fiemap returned 0 extents!\n",
+ argv[0]);
+ return 1;
+ }
for (i = 0; i < fiemap->fm_mapped_extents; i++)
last = fiemap->fm_extents[i].fe_logical +
fiemap->fm_extents[i].fe_length;
+
+ if (last <= old_start) {
+ fprintf(stderr, "%s: fiemap made no progress!\n",
+ argv[0]);
+ return 1;
+ }
}

munmap(buf, sz);