[PATCH v2] pipe: avoid an extra kmap round trip for short copies

From: Li Qiang

Date: Sat Oct 31 2026 - 06:17:45 EST


anon_pipe_write() requests PAGE_SIZE bytes when copying into a new
pipe page, even when fewer bytes remain in the source iterator.
The iterator copy is already clamped to the available data, so no
data is copied twice. However, after consuming a non-empty iterator
with less than PAGE_SIZE bytes, copy_page_from_iter() enters its loop
once more and performs an extra kmap_local_page()/kunmap_local() pair
before the zero-byte copy makes it stop.

Limit the requested copy size to the remaining iterator count so that
the loop exits after copying the available data. This is a performance
optimization; the copy semantics are unchanged.

UnixBench pipe results on Hygon C86 7490 (Hygon 4):

| Threads | Before | After | Improvement |
|---------|--------|-------|-------------|
| 1 | 835 | 854 | +2.28% |
| 256 | 179293 | 182895 | +2.01% |

Signed-off-by: Li Qiang <liqiang01@xxxxxxxxxx>
---
Thanks, Christian, for the clarification, and Mateusz for taking a look
and supporting the change.

As Christian pointed out, the iterator copy is already clamped to the
available data; this change only avoids an extra kmap round trip. I have
updated the subject and commit message accordingly.

Changes in v2:
- Reword the subject and commit message to describe this as a performance
optimization, with no data copied twice.
- Explain the extra kmap_local_page()/kunmap_local() pair avoided.
- No code changes from v1.

fs/pipe.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/fs/pipe.c b/fs/pipe.c
index 292425a834dd..da5583f7f37d 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -595,7 +595,9 @@ anon_pipe_write(struct kiocb *iocb, struct iov_iter *from)
break;
}

- copied = copy_page_from_iter(page, 0, PAGE_SIZE, from);
+ copied = copy_page_from_iter(page, 0,
+ min_t(size_t, PAGE_SIZE,
+ iov_iter_count(from)), from);
if (unlikely(copied < PAGE_SIZE && iov_iter_count(from))) {
anon_pipe_put_page(pipe, page);
if (!ret)

base-commit: 47324d3a5b3abd781295044d01d92d09f184e872
--
2.43.0