All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sadman Fahmid via B4 Relay <devnull+sadmanf.meta.com@kernel.org>
To: linux-erofs@lists.ozlabs.org
Cc: Gao Xiang <xiang@kernel.org>, Chao Yu <chao@kernel.org>,
	 Sadman Fahmid <sadmanf@meta.com>
Subject: [PATCH v2] erofs-utils: lib: fail instead of hanging on short reads in erofs_io_xcopy()
Date: Wed, 07 Oct 2026 15:15:26 -0400	[thread overview]
Message-ID: <20261007-round1-v2-1-3ffc17bb9028@meta.com> (raw)
In-Reply-To: <20261006-round1-v1-0-f46b13e11de5@meta.com>

From: Sadman Fahmid <sadmanf@meta.com>

erofs_io_xcopy() falls back to a read/pwrite loop for whatever
copy_file_range() and sendfile() did not copy.  If the source reaches
EOF before `len` bytes have been copied, erofs_io_read() returns 0,
`len` never shrinks and mkfs spins forever instead of reporting the
error.

This is easy to hit with a damaged source, e.g. rebuilding with
`mkfs.erofs --clean=data out.img src.img` where src.img is truncated
in the middle of a file's data, or when a source file shrinks while
mkfs runs.  Return -EIO instead.

While at it, keep calling copy_file_range() until it has copied the
whole range or fails.  A single call may copy less than requested
(e.g. the kernel caps each call at MAX_RW_COUNT, just under 2 GiB,
while callers pass chunks of up to 4 GiB), and the remainder was
previously copied by sendfile() instead of being reflinked.

Signed-off-by: Sadman Fahmid <sadmanf@meta.com>
---
Changes in v2:
- Use min_t(s64, len, sizeof(buf)) and int read/write result
  variables, as suggested by Gao Xiang. Each request is bounded
  to 32 KiB.
- Resend only the short-read fix. Gao Xiang already applied
  the fd-leak fix (patch 2 from v1).
- Link to v1:
  https://lore.kernel.org/r/20261006-round1-v1-0-f46b13e11de5@meta.com
---
 lib/io.c | 29 ++++++++++++++++-------------
 1 file changed, 16 insertions(+), 13 deletions(-)

diff --git a/lib/io.c b/lib/io.c
index 5c5449f..ea3bcbf 100644
--- a/lib/io.c
+++ b/lib/io.c
@@ -642,9 +642,13 @@ int erofs_io_xcopy(struct erofs_vfile *vout, off_t pos,
 		off_t ret __maybe_unused;
 
 #ifdef HAVE_COPY_FILE_RANGE
-		ret = copy_file_range(vin->fd, NULL, vout->fd, &pos, len, 0);
-		if (ret > 0)
+		while (len) {
+			ret = copy_file_range(vin->fd, NULL, vout->fd, &pos,
+					      len, 0);
+			if (ret <= 0)
+				break;
 			len -= ret;
+		}
 #endif
 #if defined(HAVE_SYS_SENDFILE_H) && defined(HAVE_SENDFILE)
 		if (len && !noseek) {
@@ -660,21 +664,20 @@ 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));
+		int nread = min_t(s64, len, sizeof(buf));
+		int ret;
 
-		ret = erofs_io_read(vin, buf, ret);
+		nread = erofs_io_read(vin, buf, nread);
+		if (nread <= 0)
+			return nread < 0 ? nread : -EIO;
+		ret = erofs_io_pwrite(vout, buf, pos, nread);
 		if (ret < 0)
 			return ret;
-		if (ret > 0) {
-			ret = erofs_io_pwrite(vout, buf, pos, ret);
-			if (ret < 0)
-				return ret;
-			pos += ret;
-		}
-		len -= ret;
-	} while (len);
+		pos += nread;
+		len -= nread;
+	}
 	return 0;
 }
 

---
base-commit: 1c230a485f25837cb51d6fc79332f30758d9006c
change-id: 20261006-round1-ae8882b2efc7

Best regards,
-- 
Sadman Fahmid <sadmanf@meta.com>




WARNING: multiple messages have this Message-ID (diff)
From: Sadman Fahmid <sadmanf@meta.com>
To: linux-erofs@lists.ozlabs.org
Cc: Gao Xiang <xiang@kernel.org>, Chao Yu <chao@kernel.org>,
	 Sadman Fahmid <sadmanf@meta.com>
Subject: [PATCH v2] erofs-utils: lib: fail instead of hanging on short reads in erofs_io_xcopy()
Date: Wed, 07 Oct 2026 15:15:26 -0400	[thread overview]
Message-ID: <20261007-round1-v2-1-3ffc17bb9028@meta.com> (raw)
In-Reply-To: <20261006-round1-v1-0-f46b13e11de5@meta.com>

erofs_io_xcopy() falls back to a read/pwrite loop for whatever
copy_file_range() and sendfile() did not copy.  If the source reaches
EOF before `len` bytes have been copied, erofs_io_read() returns 0,
`len` never shrinks and mkfs spins forever instead of reporting the
error.

This is easy to hit with a damaged source, e.g. rebuilding with
`mkfs.erofs --clean=data out.img src.img` where src.img is truncated
in the middle of a file's data, or when a source file shrinks while
mkfs runs.  Return -EIO instead.

While at it, keep calling copy_file_range() until it has copied the
whole range or fails.  A single call may copy less than requested
(e.g. the kernel caps each call at MAX_RW_COUNT, just under 2 GiB,
while callers pass chunks of up to 4 GiB), and the remainder was
previously copied by sendfile() instead of being reflinked.

Signed-off-by: Sadman Fahmid <sadmanf@meta.com>
---
Changes in v2:
- Use min_t(s64, len, sizeof(buf)) and int read/write result
  variables, as suggested by Gao Xiang. Each request is bounded
  to 32 KiB.
- Resend only the short-read fix. Gao Xiang already applied
  the fd-leak fix (patch 2 from v1).
- Link to v1:
  https://lore.kernel.org/r/20261006-round1-v1-0-f46b13e11de5@meta.com
---
 lib/io.c | 29 ++++++++++++++++-------------
 1 file changed, 16 insertions(+), 13 deletions(-)

diff --git a/lib/io.c b/lib/io.c
index 5c5449f..ea3bcbf 100644
--- a/lib/io.c
+++ b/lib/io.c
@@ -642,9 +642,13 @@ int erofs_io_xcopy(struct erofs_vfile *vout, off_t pos,
 		off_t ret __maybe_unused;
 
 #ifdef HAVE_COPY_FILE_RANGE
-		ret = copy_file_range(vin->fd, NULL, vout->fd, &pos, len, 0);
-		if (ret > 0)
+		while (len) {
+			ret = copy_file_range(vin->fd, NULL, vout->fd, &pos,
+					      len, 0);
+			if (ret <= 0)
+				break;
 			len -= ret;
+		}
 #endif
 #if defined(HAVE_SYS_SENDFILE_H) && defined(HAVE_SENDFILE)
 		if (len && !noseek) {
@@ -660,21 +664,20 @@ 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));
+		int nread = min_t(s64, len, sizeof(buf));
+		int ret;
 
-		ret = erofs_io_read(vin, buf, ret);
+		nread = erofs_io_read(vin, buf, nread);
+		if (nread <= 0)
+			return nread < 0 ? nread : -EIO;
+		ret = erofs_io_pwrite(vout, buf, pos, nread);
 		if (ret < 0)
 			return ret;
-		if (ret > 0) {
-			ret = erofs_io_pwrite(vout, buf, pos, ret);
-			if (ret < 0)
-				return ret;
-			pos += ret;
-		}
-		len -= ret;
-	} while (len);
+		pos += nread;
+		len -= nread;
+	}
 	return 0;
 }
 

---
base-commit: 1c230a485f25837cb51d6fc79332f30758d9006c
change-id: 20261006-round1-ae8882b2efc7

Best regards,
-- 
Sadman Fahmid <sadmanf@meta.com>


  parent reply	other threads:[~2026-10-07 19:15 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-06 18:04 [PATCH RESEND 0/2] erofs-utils: lib: fix a short-read hang and an fd leak Sadman Fahmid via B4 Relay
2026-10-06 18:04 ` Sadman Fahmid
2026-10-06 18:04 ` [PATCH RESEND 1/2] erofs-utils: lib: fail instead of hanging on short reads in erofs_io_xcopy() Sadman Fahmid via B4 Relay
2026-10-06 18:04   ` Sadman Fahmid
2026-10-06 20:51   ` [PATCH RESEND 1/2] erofs-utils: lib: fail instead of hanging on short reads in erofs_io_xcopy()y Gao Xiang
2026-10-06 18:04 ` [PATCH RESEND 2/2] erofs-utils: lib: close source fd on early errors in erofs_mkfs_begin_nondirectory() Sadman Fahmid via B4 Relay
2026-10-06 18:04   ` Sadman Fahmid
2026-10-06 20:57   ` Gao Xiang
2026-10-07 19:15 ` Sadman Fahmid via B4 Relay [this message]
2026-10-07 19:15   ` [PATCH v2] erofs-utils: lib: fail instead of hanging on short reads in erofs_io_xcopy() Sadman Fahmid
2026-10-07 20:15   ` Gao Xiang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261007-round1-v2-1-3ffc17bb9028@meta.com \
    --to=devnull+sadmanf.meta.com@kernel.org \
    --cc=chao@kernel.org \
    --cc=linux-erofs@lists.ozlabs.org \
    --cc=sadmanf@meta.com \
    --cc=xiang@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.