[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