[PATCH v3] erofs-utils: lib: fix infinite loop on EOF in erofs_io_xcopy

Ajay Rajera newajay.11r at gmail.com
Sat Mar 28 11:39:00 AEDT 2026


erofs_io_xcopy() has a fallback loop for when the kernel fast paths
(copy_file_range/sendfile) do not handle all the data.

When erofs_io_read() returned 0 (source exhausted before all bytes
were copied), the old logic checked `ret < 0` and `ret > 0`,
ignoring `0`. Since `len -= 0` is a no-op, the loop would spin
forever at 100% CPU with no progress.

v2 fixed the loop but unconditionally trapped a 0-byte read by
returning -EIO. However, if copy_file_range completely exhausts
the bytes, `len` becomes 0. The do-while loop was then forced to
execute once, making a 0-byte read, which returned 0. v2 falsely
trapped this success as an -EIO error, causing mkfs.erofs to fail
in CI.

Fix this regression by replacing `do-while(len)` with a standard
`while(len)` loop. This safely bypasses the block if `len` is 0
(avoiding fake -EIO errors), while correctly catching premature
EOFs with -EIO.

Also fix the 'pading' -> 'padding' typo in erofs_dev_read().

Signed-off-by: Ajay Rajera <newajay.11r at gmail.com>
---
v3: Replace do-while loop to avoid 0-byte read -EIO regression.
v2: Return -EIO instead of -ENODATA, use cleaner if/else.
---
 lib/io.c | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/lib/io.c b/lib/io.c
index 0c5eb2c..ae6a600 100644
--- a/lib/io.c
+++ b/lib/io.c
@@ -430,7 +430,7 @@ ssize_t erofs_dev_read(struct erofs_sb_info *sbi, int device_id,
 	if (read < 0)
 		return read;
 	if (read < len) {
-		erofs_info("reach EOF of device @ %llu, pading with zeroes",
+		erofs_info("reach EOF of device @ %llu, padding with zeroes",
 			   offset | 0ULL);
 		memset(buf + read, 0, len - read);
 	}
@@ -660,21 +660,22 @@ int erofs_io_xcopy(struct erofs_vfile *vout, off_t pos,
 #endif
 	}
 
-	do {
+	while (len) {
 		char buf[32768];
 		int ret = min_t(unsigned int, len, sizeof(buf));
 
 		ret = erofs_io_read(vin, buf, ret);
 		if (ret < 0)
 			return ret;
-		if (ret > 0) {
-			ret = erofs_io_pwrite(vout, buf, pos, ret);
-			if (ret < 0)
-				return ret;
-			pos += ret;
-		}
+		if (ret == 0)
+			return -EIO;
+
+		ret = erofs_io_pwrite(vout, buf, pos, ret);
+		if (ret < 0)
+			return ret;
+		pos += ret;
 		len -= ret;
-	} while (len);
+	}
 	return 0;
 }
 
-- 
2.51.0.windows.1



More information about the Linux-erofs mailing list