[PATCH] erofs-utils: lib: fix infinite loop on EOF in erofs_io_xcopy
Lucas Karpinski
lkarpinski at nvidia.com
Sat Mar 21 02:31:18 AEDT 2026
On 2026-03-19 8:20 p.m., Ajay Rajera wrote:
> erofs_io_xcopy() has a fallback do-while loop for when the
> kernel fast-paths (copy_file_range/sendfile) do not handle all
> the data. The loop does:
>
> ret = erofs_io_read(vin, buf, ret);
> if (ret < 0)
> return ret;
> if (ret > 0) { ... pos += ret; }
> len -= ret;
> } while (len);
>
> When erofs_io_read() returns 0 (EOF -- source exhausted before
> all bytes were copied), only the ret < 0 and ret > 0 branches
> were handled. Since ret == 0, `len -= ret` is a no-op and
> `while (len)` stays true, causing the loop to spin forever at
> 100% CPU with no error and no progress.
>
> This can be triggered when building an EROFS image from an input
> file that is shorter than expected -- e.g. a truncated source
> file, a pipe/FIFO that closes early, or a file being modified
> concurrently during mkfs.
>
> Fix it by treating a zero return as an error (-ENODATA) so the
> caller fails cleanly instead of hanging indefinitely.
>
> Also fix the long-standing 'pading' -> 'padding' typo in the
> short-read diagnostic message of erofs_dev_read().
>
> Signed-off-by: Ajay Rajera <newajay.11r at gmail.com>
> ---
> lib/io.c | 15 ++++++++-------
> 1 file changed, 8 insertions(+), 7 deletions(-)
>
> diff --git a/lib/io.c b/lib/io.c
> index 0c5eb2c..583f52d 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);
> }
> @@ -665,14 +665,15 @@ int erofs_io_xcopy(struct erofs_vfile *vout, off_t pos,
> int ret = min_t(unsigned int, len, sizeof(buf));
>
> ret = erofs_io_read(vin, buf, ret);
> - if (ret < 0)
> + if (ret <= 0) {
> + if (!ret)
> + return -ENODATA;
> return ret;
> - if (ret > 0) {
> - ret = erofs_io_pwrite(vout, buf, pos, ret);
Change looks good to me, just minor nits.
Don't need the nested if and I think EIO would be better choice here
based on your description. We would expect to see 0 from erofs_io_read
when there is an issue with our input file, mostly caused by IO issues.
if (ret < 0)
return ret;
else if (!ret)
return -EIO;
ret = erofs_io_pwrite(vout, buf, pos, ret);
Regards,
Lucas Karpinski
More information about the Linux-erofs
mailing list