[LTP] [PATCH] splice08: Keep calling splice() until all bytes are spliced

Wake Liu wakel@google.com
Fri Oct 30 04:13:28 CET 2026


splice() may transfer fewer bytes than requested, but the test fails
as soon as a single call does not splice the whole buffer.

/dev/zero and /dev/full use copy_splice_read(), which limits the
transfer to the number of pages it gets from alloc_pages_bulk(). Since
kernel commit 187ad460b841 ("mm/page_alloc: avoid page allocator
recursion with pagesets.lock held"), the bulk allocator allocates only
one page per call when page_owner is enabled. On kernels booted with
page_owner=on, every request larger than a page is therefore cut to
PAGE_SIZE bytes and the test fails:

  TPASS: splice(...) returned 4096
  TFAIL: Only part 4096 bytes of 5045 were spliced

A short count is valid splice() behavior, not a kernel bug, so keep
calling splice() until the whole buffer is in the pipe and fail only
if it stops making progress before that.

Signed-off-by: Wake Liu <wakel@google.com>
---
 testcases/kernel/syscalls/splice/splice08.c | 27 ++++++++++++++-------
 1 file changed, 18 insertions(+), 9 deletions(-)

diff --git a/testcases/kernel/syscalls/splice/splice08.c b/testcases/kernel/syscalls/splice/splice08.c
index bd635ee7e..2af1c88b6 100644
--- a/testcases/kernel/syscalls/splice/splice08.c
+++ b/testcases/kernel/syscalls/splice/splice08.c
@@ -23,21 +23,30 @@ static void test_splice(unsigned int bytes, int dev_fd)
 {
 	int pipefd[2];
 	char buf[bytes];
-	size_t i;
+	size_t i, spliced = 0;
 	int fail = 0;
 
 	memset(buf, 0xff, sizeof(buf));
 
 	SAFE_PIPE(pipefd);
 
-	TST_EXP_POSITIVE(splice(dev_fd, NULL, pipefd[1], NULL, sizeof(buf), 0));
-
-	if (!TST_PASS)
-		goto ret;
-
-	if ((size_t)TST_RET != sizeof(buf)) {
-		tst_res(TFAIL, "Only part %lu bytes of %u were spliced",
-			TST_RET, bytes);
+	/*
+	 * splice() may transfer less than requested, e.g. with page_owner=on
+	 * copy_splice_read() gets only a single page per call, so keep
+	 * splicing until all bytes are in the pipe.
+	 */
+	do {
+		TST_EXP_POSITIVE(splice(dev_fd, NULL, pipefd[1], NULL,
+					sizeof(buf) - spliced, 0));
+		if (!TST_PASS)
+			goto ret;
+
+		spliced += TST_RET;
+	} while (TST_RET && spliced < sizeof(buf));
+
+	if (spliced != sizeof(buf)) {
+		tst_res(TFAIL, "Only part %zu bytes of %u were spliced",
+			spliced, bytes);
 		goto ret;
 	}
 
-- 
2.56.0.307.g5fe7bd680c-goog



More information about the ltp mailing list