[PATCH] erofs-utils: lib: fix infinite loop on EOF in erofs_io_xcopy
Ajay Rajera
newajay.11r at gmail.com
Sat Mar 21 05:54:47 AEDT 2026
Hi, Thanks for the review.
Okay, I understand it now.
I've just sent out a v2 patch incorporating your suggested changes.
Best regards,
Ajay Rajera
On Fri, 20 Mar 2026 at 21:01, Lucas Karpinski <lkarpinski at nvidia.com> wrote:
>
> 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