Linux io-uring development
 help / color / mirror / Atom feed
* [PATCH] io_uring/rw: fix missing ERESTARTSYS conversion in read paths
@ 2026-07-20 11:41 Yitang Yang
  2026-07-21 16:32 ` Jens Axboe
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Yitang Yang @ 2026-07-20 11:41 UTC (permalink / raw)
  To: axboe; +Cc: krisman, io-uring, Yitang Yang

Both read and write may receive internal restart error codes from
the filesystem layer and should be converted to -EINTR. However,
when multishot read support was added, the error code normalization
was lost for both io_read() and io_read_mshot().

Extract the conversion into io_fixup_restart_res() and apply it
in all three locations: io_rw_done(), io_read(), and io_read_mshot().

Fixes: a08d195b586a ("io_uring/rw: split io_read() into a helper")
Signed-off-by: Yitang Yang <yi1tang.yang@gmail.com>
---
 io_uring/rw.c | 38 ++++++++++++++++++++++++--------------
 1 file changed, 24 insertions(+), 14 deletions(-)

diff --git a/io_uring/rw.c b/io_uring/rw.c
index 63b6519e498c..e505479e3773 100644
--- a/io_uring/rw.c
+++ b/io_uring/rw.c
@@ -615,6 +615,24 @@ static void io_complete_rw_iopoll(struct kiocb *kiocb, long res)
 	smp_store_release(&req->iopoll_completed, 1);
 }
 
+static inline ssize_t io_fixup_restart_res(ssize_t ret)
+{
+	switch (ret) {
+	case -ERESTARTSYS:
+	case -ERESTARTNOINTR:
+	case -ERESTARTNOHAND:
+	case -ERESTART_RESTARTBLOCK:
+		/*
+		 * We can't just restart the syscall, since previously
+		 * submitted sqes may already be in progress. Just fail
+		 * this IO with EINTR.
+		 */
+		return -EINTR;
+	default:
+		return ret;
+	}
+}
+
 static inline void io_rw_done(struct io_kiocb *req, ssize_t ret)
 {
 	struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw);
@@ -625,19 +643,7 @@ static inline void io_rw_done(struct io_kiocb *req, ssize_t ret)
 
 	/* transform internal restart error codes */
 	if (unlikely(ret < 0)) {
-		switch (ret) {
-		case -ERESTARTSYS:
-		case -ERESTARTNOINTR:
-		case -ERESTARTNOHAND:
-		case -ERESTART_RESTARTBLOCK:
-			/*
-			 * We can't just restart the syscall, since previously
-			 * submitted sqes may already be in progress. Just fail
-			 * this IO with EINTR.
-			 */
-			ret = -EINTR;
-			break;
-		}
+		ret = io_fixup_restart_res(ret);
 	}
 
 	if (req->flags & REQ_F_IOPOLL)
@@ -1034,6 +1040,8 @@ int io_read(struct io_kiocb *req, unsigned int issue_flags)
 
 	if (req->flags & REQ_F_BUFFERS_COMMIT)
 		io_kbuf_recycle(req, sel.buf_list, issue_flags);
+
+	ret = io_fixup_restart_res(ret);
 	return ret;
 }
 
@@ -1068,8 +1076,10 @@ int io_read_mshot(struct io_kiocb *req, unsigned int issue_flags)
 		return IOU_RETRY;
 	} else if (ret <= 0) {
 		io_kbuf_recycle(req, sel.buf_list, issue_flags);
-		if (ret < 0)
+		if (ret < 0) {
+			ret = io_fixup_restart_res(ret);
 			req_set_fail(req);
+		}
 	} else if (!(req->flags & REQ_F_APOLL_MULTISHOT)) {
 		cflags = io_put_kbuf(req, ret, sel.buf_list);
 	} else {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH] io_uring/rw: fix missing ERESTARTSYS conversion in read paths
  2026-07-20 11:41 [PATCH] io_uring/rw: fix missing ERESTARTSYS conversion in read paths Yitang Yang
@ 2026-07-21 16:32 ` Jens Axboe
  2026-07-22  3:08   ` Yitang Yang
  2026-07-22 10:32 ` Jens Axboe
  2026-07-22 12:45 ` [PATCH v2] io_uring/rw: fix missing ERESTARTSYS conversion in read paths Yitang Yang
  2 siblings, 1 reply; 10+ messages in thread
From: Jens Axboe @ 2026-07-21 16:32 UTC (permalink / raw)
  To: Yitang Yang; +Cc: krisman, io-uring

On 7/20/26 5:41 AM, Yitang Yang wrote:
> Both read and write may receive internal restart error codes from
> the filesystem layer and should be converted to -EINTR. However,
> when multishot read support was added, the error code normalization
> was lost for both io_read() and io_read_mshot().
> 
> Extract the conversion into io_fixup_restart_res() and apply it
> in all three locations: io_rw_done(), io_read(), and io_read_mshot().

How was this found? Reason I ask is that I wonder if this is even
necessary in the first place. If you found this because of an issue
you ran into, then that answers that question clearly (yes we need it).
But if this some LLM find, then that's an entirely different story.

-- 
Jens Axboe


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] io_uring/rw: fix missing ERESTARTSYS conversion in read paths
  2026-07-21 16:32 ` Jens Axboe
@ 2026-07-22  3:08   ` Yitang Yang
  2026-07-22 10:28     ` Jens Axboe
  0 siblings, 1 reply; 10+ messages in thread
From: Yitang Yang @ 2026-07-22  3:08 UTC (permalink / raw)
  To: Jens Axboe; +Cc: krisman, io-uring

I found this while trying to combine io_uring read multishot with
userfaultfd. I wrote a reproducer here:
https://gist.github.com/wokron/7f75026e02792844b0bbf26b7e79c9ef

Running it with "sudo ./userfaultfd-uring -n 16 -p 10000" on
my machine consistently produces "io_uring_cqe error: Unknown error 512".

Jens Axboe <axboe@kernel.dk> 于2026年7月22日周三 00:32写道:
>
> On 7/20/26 5:41 AM, Yitang Yang wrote:
> > Both read and write may receive internal restart error codes from
> > the filesystem layer and should be converted to -EINTR. However,
> > when multishot read support was added, the error code normalization
> > was lost for both io_read() and io_read_mshot().
> >
> > Extract the conversion into io_fixup_restart_res() and apply it
> > in all three locations: io_rw_done(), io_read(), and io_read_mshot().
>
> How was this found? Reason I ask is that I wonder if this is even
> necessary in the first place. If you found this because of an issue
> you ran into, then that answers that question clearly (yes we need it).
> But if this some LLM find, then that's an entirely different story.
>
> --
> Jens Axboe
>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] io_uring/rw: fix missing ERESTARTSYS conversion in read paths
  2026-07-22  3:08   ` Yitang Yang
@ 2026-07-22 10:28     ` Jens Axboe
  0 siblings, 0 replies; 10+ messages in thread
From: Jens Axboe @ 2026-07-22 10:28 UTC (permalink / raw)
  To: Yitang Yang; +Cc: krisman, io-uring

On 7/21/26 9:08 PM, Yitang Yang wrote:
> I found this while trying to combine io_uring read multishot with
> userfaultfd. I wrote a reproducer here:
> https://gist.github.com/wokron/7f75026e02792844b0bbf26b7e79c9ef
> 
> Running it with "sudo ./userfaultfd-uring -n 16 -p 10000" on
> my machine consistently produces "io_uring_cqe error: Unknown error 512".

Perfect, that's a much more useful find then! I'll take a closer look at
your patch.

-- 
Jens Axboe

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] io_uring/rw: fix missing ERESTARTSYS conversion in read paths
  2026-07-20 11:41 [PATCH] io_uring/rw: fix missing ERESTARTSYS conversion in read paths Yitang Yang
  2026-07-21 16:32 ` Jens Axboe
@ 2026-07-22 10:32 ` Jens Axboe
  2026-07-22 12:36   ` Yitang Yang
  2026-07-22 12:45 ` [PATCH v2] io_uring/rw: fix missing ERESTARTSYS conversion in read paths Yitang Yang
  2 siblings, 1 reply; 10+ messages in thread
From: Jens Axboe @ 2026-07-22 10:32 UTC (permalink / raw)
  To: Yitang Yang; +Cc: krisman, io-uring

On 7/20/26 5:41 AM, Yitang Yang wrote:
> Both read and write may receive internal restart error codes from
> the filesystem layer and should be converted to -EINTR. However,
> when multishot read support was added, the error code normalization
> was lost for both io_read() and io_read_mshot().
> 
> Extract the conversion into io_fixup_restart_res() and apply it
> in all three locations: io_rw_done(), io_read(), and io_read_mshot().

Functionally this looks good, just a few cosmetic nits below.

> Fixes: a08d195b586a ("io_uring/rw: split io_read() into a helper")
> Signed-off-by: Yitang Yang <yi1tang.yang@gmail.com>

And this one needs a Cc: stable@vger.kernel.org

> @@ -625,19 +643,7 @@ static inline void io_rw_done(struct io_kiocb *req, ssize_t ret)
>  
>  	/* transform internal restart error codes */
>  	if (unlikely(ret < 0)) {
> -		switch (ret) {
> -		case -ERESTARTSYS:
> -		case -ERESTARTNOINTR:
> -		case -ERESTARTNOHAND:
> -		case -ERESTART_RESTARTBLOCK:
> -			/*
> -			 * We can't just restart the syscall, since previously
> -			 * submitted sqes may already be in progress. Just fail
> -			 * this IO with EINTR.
> -			 */
> -			ret = -EINTR;
> -			break;
> -		}
> +		ret = io_fixup_restart_res(ret);
>  	}

No need for braces anymore on the 'if' statement, just drop those.

> @@ -1034,6 +1040,8 @@ int io_read(struct io_kiocb *req, unsigned int issue_flags)
>  
>  	if (req->flags & REQ_F_BUFFERS_COMMIT)
>  		io_kbuf_recycle(req, sel.buf_list, issue_flags);
> +
> +	ret = io_fixup_restart_res(ret);
>  	return ret;
>  }

return io_fixup_restart_res(ret);

-- 
Jens Axboe

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] io_uring/rw: fix missing ERESTARTSYS conversion in read paths
  2026-07-22 10:32 ` Jens Axboe
@ 2026-07-22 12:36   ` Yitang Yang
  2026-07-22 13:37     ` Jens Axboe
  0 siblings, 1 reply; 10+ messages in thread
From: Yitang Yang @ 2026-07-22 12:36 UTC (permalink / raw)
  To: Jens Axboe; +Cc: krisman, io-uring

Thanks! I'll send a v2.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v2] io_uring/rw: fix missing ERESTARTSYS conversion in read paths
  2026-07-20 11:41 [PATCH] io_uring/rw: fix missing ERESTARTSYS conversion in read paths Yitang Yang
  2026-07-21 16:32 ` Jens Axboe
  2026-07-22 10:32 ` Jens Axboe
@ 2026-07-22 12:45 ` Yitang Yang
  2026-07-22 13:37   ` Jens Axboe
  2 siblings, 1 reply; 10+ messages in thread
From: Yitang Yang @ 2026-07-22 12:45 UTC (permalink / raw)
  To: Jens Axboe; +Cc: Gabriel Krisman Bertazi, io-uring, Yitang Yang, stable

Both read and write may receive internal restart error codes from
the filesystem layer and should be converted to -EINTR. However,
when multishot read support was added, the error code normalization
was lost for both io_read() and io_read_mshot().

Extract the conversion into io_fixup_restart_res() and apply it
in all three locations: io_rw_done(), io_read(), and io_read_mshot().

Fixes: a08d195b586a ("io_uring/rw: split io_read() into a helper")
Cc: stable@vger.kernel.org
Signed-off-by: Yitang Yang <yi1tang.yang@gmail.com>
---
 io_uring/rw.c | 42 +++++++++++++++++++++++++-----------------
 1 file changed, 25 insertions(+), 17 deletions(-)

diff --git a/io_uring/rw.c b/io_uring/rw.c
index 63b6519e498c..95038cfda615 100644
--- a/io_uring/rw.c
+++ b/io_uring/rw.c
@@ -615,6 +615,24 @@ static void io_complete_rw_iopoll(struct kiocb *kiocb, long res)
 	smp_store_release(&req->iopoll_completed, 1);
 }
 
+static inline ssize_t io_fixup_restart_res(ssize_t ret)
+{
+	switch (ret) {
+	case -ERESTARTSYS:
+	case -ERESTARTNOINTR:
+	case -ERESTARTNOHAND:
+	case -ERESTART_RESTARTBLOCK:
+		/*
+		 * We can't just restart the syscall, since previously
+		 * submitted sqes may already be in progress. Just fail
+		 * this IO with EINTR.
+		 */
+		return -EINTR;
+	default:
+		return ret;
+	}
+}
+
 static inline void io_rw_done(struct io_kiocb *req, ssize_t ret)
 {
 	struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw);
@@ -624,21 +642,8 @@ static inline void io_rw_done(struct io_kiocb *req, ssize_t ret)
 		return;
 
 	/* transform internal restart error codes */
-	if (unlikely(ret < 0)) {
-		switch (ret) {
-		case -ERESTARTSYS:
-		case -ERESTARTNOINTR:
-		case -ERESTARTNOHAND:
-		case -ERESTART_RESTARTBLOCK:
-			/*
-			 * We can't just restart the syscall, since previously
-			 * submitted sqes may already be in progress. Just fail
-			 * this IO with EINTR.
-			 */
-			ret = -EINTR;
-			break;
-		}
-	}
+	if (unlikely(ret < 0))
+		ret = io_fixup_restart_res(ret);
 
 	if (req->flags & REQ_F_IOPOLL)
 		io_complete_rw_iopoll(&rw->kiocb, ret);
@@ -1034,7 +1039,8 @@ int io_read(struct io_kiocb *req, unsigned int issue_flags)
 
 	if (req->flags & REQ_F_BUFFERS_COMMIT)
 		io_kbuf_recycle(req, sel.buf_list, issue_flags);
-	return ret;
+
+	return io_fixup_restart_res(ret);
 }
 
 int io_read_mshot(struct io_kiocb *req, unsigned int issue_flags)
@@ -1068,8 +1074,10 @@ int io_read_mshot(struct io_kiocb *req, unsigned int issue_flags)
 		return IOU_RETRY;
 	} else if (ret <= 0) {
 		io_kbuf_recycle(req, sel.buf_list, issue_flags);
-		if (ret < 0)
+		if (ret < 0) {
+			ret = io_fixup_restart_res(ret);
 			req_set_fail(req);
+		}
 	} else if (!(req->flags & REQ_F_APOLL_MULTISHOT)) {
 		cflags = io_put_kbuf(req, ret, sel.buf_list);
 	} else {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH v2] io_uring/rw: fix missing ERESTARTSYS conversion in read paths
  2026-07-22 12:45 ` [PATCH v2] io_uring/rw: fix missing ERESTARTSYS conversion in read paths Yitang Yang
@ 2026-07-22 13:37   ` Jens Axboe
  0 siblings, 0 replies; 10+ messages in thread
From: Jens Axboe @ 2026-07-22 13:37 UTC (permalink / raw)
  To: Yitang Yang; +Cc: Gabriel Krisman Bertazi, io-uring, stable


On Wed, 22 Jul 2026 20:45:51 +0800, Yitang Yang wrote:
> Both read and write may receive internal restart error codes from
> the filesystem layer and should be converted to -EINTR. However,
> when multishot read support was added, the error code normalization
> was lost for both io_read() and io_read_mshot().
> 
> Extract the conversion into io_fixup_restart_res() and apply it
> in all three locations: io_rw_done(), io_read(), and io_read_mshot().
> 
> [...]

Applied, thanks!

[1/1] io_uring/rw: fix missing ERESTARTSYS conversion in read paths
      commit: ab05caca123c6d0b41850b7c05b246e4dca4a770

Best regards,
-- 
Jens Axboe




^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] io_uring/rw: fix missing ERESTARTSYS conversion in read paths
  2026-07-22 12:36   ` Yitang Yang
@ 2026-07-22 13:37     ` Jens Axboe
  2026-07-23 12:46       ` [PATCH liburing] test: add rw-restart-ret regression test Yitang Yang
  0 siblings, 1 reply; 10+ messages in thread
From: Jens Axboe @ 2026-07-22 13:37 UTC (permalink / raw)
  To: Yitang Yang; +Cc: krisman, io-uring

On 7/22/26 6:36 AM, Yitang Yang wrote:
> Thanks! I'll send a v2.

Thanks, applied it - can you send your test case as a liburing test/
addition as well?

-- 
Jens Axboe


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH liburing] test: add rw-restart-ret regression test
  2026-07-22 13:37     ` Jens Axboe
@ 2026-07-23 12:46       ` Yitang Yang
  0 siblings, 0 replies; 10+ messages in thread
From: Yitang Yang @ 2026-07-23 12:46 UTC (permalink / raw)
  To: Jens Axboe; +Cc: Gabriel Krisman Bertazi, io-uring, Yitang Yang

The filesystem layer may return internal restart codes to io_uring,
which should be converted to -EINTR before being delivered to
userspace. Add a test using userfaultfd with read multishot to
expose the issue and prevent regressions.

Link: https://lore.kernel.org/io-uring/20260720114116.21830-1-yi1tang.yang@gmail.com/
Signed-off-by: Yitang Yang <yi1tang.yang@gmail.com>
---
 test/Makefile         |   1 +
 test/rw-restart-ret.c | 304 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 305 insertions(+)
 create mode 100644 test/rw-restart-ret.c

diff --git a/test/Makefile b/test/Makefile
index d88a4287..e8cdda75 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -244,6 +244,7 @@ test_srcs := \
 	ring-leak.c \
 	ring-query.c \
 	rsrc_tags.c \
+	rw-restart-ret.c \
 	rw_merge_test.c \
 	self.c \
 	recvsend_bundle.c \
diff --git a/test/rw-restart-ret.c b/test/rw-restart-ret.c
new file mode 100644
index 00000000..e041c365
--- /dev/null
+++ b/test/rw-restart-ret.c
@@ -0,0 +1,304 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Description: test that io_uring correctly converts internal -ERESTARTSYS
+ * to -EINTR on file read paths. Using userfaultfd to expose the issue.
+ */
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/userfaultfd.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/eventfd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include "liburing.h"
+#include "helpers.h"
+
+#define BUF_RING_SIZE	32
+#define BGID		0
+#define EXIT_DATA	1
+
+static size_t num_threads = 16;
+static size_t pages_per_thread = 10000;
+static size_t page_size;
+
+typedef struct {
+	void *data;
+	size_t size;
+	int uffd;
+	int stop_fd;
+	struct io_uring ring;
+	struct io_uring_buf_ring *buf_ring;
+} handler_state;
+
+static int handle_page_fault(handler_state *h, struct uffd_msg *msg)
+{
+	void *fault_addr = (void *)msg->arg.pagefault.address;
+	struct uffdio_zeropage zeropage = {
+		.range = {
+			.start = (unsigned long)fault_addr,
+			.len = page_size,
+		},
+	};
+
+	return ioctl(h->uffd, UFFDIO_ZEROPAGE, &zeropage);
+}
+
+static int init_handler(handler_state *h, void *data, size_t size)
+{
+	int r;
+
+	memset(h, 0, sizeof(*h));
+	h->data = data;
+	h->size = size;
+
+	h->uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK);
+	if (h->uffd == -1) {
+		if (errno == ENOSYS || errno == EPERM)
+			return T_EXIT_SKIP;
+		return -1;
+	}
+
+	struct uffdio_api api = {
+		.api = UFFD_API,
+		.features = 0,
+	};
+	if (ioctl(h->uffd, UFFDIO_API, &api) == -1)
+		goto err_close_uffd;
+
+	struct uffdio_register reg = {
+		.range = {
+			.start = (unsigned long)h->data,
+			.len = h->size,
+		},
+		.mode = UFFDIO_REGISTER_MODE_MISSING,
+	};
+	if (ioctl(h->uffd, UFFDIO_REGISTER, &reg) == -1)
+		goto err_close_uffd;
+
+	h->stop_fd = eventfd(0, EFD_NONBLOCK);
+	if (h->stop_fd == -1)
+		goto err_close_uffd;
+
+	r = io_uring_queue_init(128, &h->ring, 0);
+	if (r < 0)
+		goto err_close_stopfd;
+
+	h->buf_ring = io_uring_setup_buf_ring(&h->ring, BUF_RING_SIZE,
+					       BGID, 0, &r);
+	if (!h->buf_ring) {
+		if (r == -EINVAL || r == -ENOENT) {
+			io_uring_queue_exit(&h->ring);
+			close(h->stop_fd);
+			close(h->uffd);
+			return T_EXIT_SKIP;
+		}
+		goto err_cleanup_ring;
+	}
+
+	return 0;
+
+err_cleanup_ring:
+	io_uring_queue_exit(&h->ring);
+err_close_stopfd:
+	close(h->stop_fd);
+err_close_uffd:
+	close(h->uffd);
+	return -1;
+}
+
+static void destroy_handler(handler_state *h)
+{
+	io_uring_free_buf_ring(&h->ring, h->buf_ring, BUF_RING_SIZE, BGID);
+	io_uring_queue_exit(&h->ring);
+	close(h->stop_fd);
+	close(h->uffd);
+}
+
+static int handler_run(handler_state *h)
+{
+	struct io_uring_sqe *sqe;
+	struct io_uring_cqe *cqe;
+	uint64_t stop_signal = 0;
+
+	struct uffd_msg msgs[BUF_RING_SIZE];
+	int i;
+
+	for (i = 0; i < BUF_RING_SIZE; i++) {
+		io_uring_buf_ring_add(h->buf_ring, msgs + i,
+				      sizeof(struct uffd_msg), i,
+				      BUF_RING_SIZE - 1, i);
+	}
+	io_uring_buf_ring_advance(h->buf_ring, BUF_RING_SIZE);
+
+	sqe = io_uring_get_sqe(&h->ring);
+	io_uring_prep_read_multishot(sqe, h->uffd, 0, 0, BGID);
+
+	sqe = io_uring_get_sqe(&h->ring);
+	io_uring_prep_read(sqe, h->stop_fd, &stop_signal,
+			   sizeof(stop_signal), 0);
+	io_uring_sqe_set_data64(sqe, EXIT_DATA);
+
+	io_uring_submit(&h->ring);
+
+	while (1) {
+		int ret = io_uring_wait_cqe(&h->ring, &cqe);
+		if (ret < 0)
+			exit(T_EXIT_FAIL);
+
+		unsigned head;
+		size_t count = 0;
+
+		io_uring_for_each_cqe(&h->ring, head, cqe) {
+			if (cqe->user_data == EXIT_DATA)
+				return 0;
+
+			/*
+			 * The only acceptable errors for a multishot
+			 * read on userfaultfd are ENOBUFS (buffers
+			 * temporarily exhausted) and EINTR.
+			 */
+			if (cqe->res < 0 &&
+			    cqe->res != -ENOBUFS &&
+			    cqe->res != -EINTR)
+				exit(T_EXIT_FAIL);
+
+			if (cqe->res >= 0) {
+				int bid = cqe->flags >> IORING_CQE_BUFFER_SHIFT;
+				struct uffd_msg *this_msg = &msgs[bid];
+
+				if (handle_page_fault(h, this_msg))
+					exit(T_EXIT_FAIL);
+
+				io_uring_buf_ring_add(h->buf_ring, this_msg,
+						      sizeof(struct uffd_msg),
+						      bid, BUF_RING_SIZE - 1, 0);
+				io_uring_buf_ring_advance(h->buf_ring, 1);
+			}
+
+			if (!(cqe->flags & IORING_CQE_F_MORE)) {
+				sqe = io_uring_get_sqe(&h->ring);
+				io_uring_prep_read_multishot(sqe, h->uffd,
+							     0, 0, BGID);
+				io_uring_submit(&h->ring);
+			}
+
+			count++;
+		}
+		io_uring_cq_advance(&h->ring, count);
+	}
+
+	return 0;
+}
+
+static ssize_t handler_stop(handler_state *h)
+{
+	uint64_t u = 1;
+	return write(h->stop_fd, &u, sizeof(u));
+}
+
+static void *thread_function(void *arg)
+{
+	char *data = (char *)arg;
+	size_t i;
+
+	for (i = 0; i < pages_per_thread; i++)
+		data[i * page_size] = (char)i;
+	return NULL;
+}
+
+static void *fault_thread_func(void *arg)
+{
+	handler_run((handler_state *)arg);
+	return NULL;
+}
+
+static void print_usage(const char *prog)
+{
+	fprintf(stderr,
+		"Usage: %s [-n threads] [-p pages] [-h]\n"
+		"  -n NUM  Number of threads\n"
+		"  -p NUM  Pages per thread\n"
+		"  -h      Show this help\n",
+		prog);
+}
+
+int main(int argc, char **argv)
+{
+	handler_state handler;
+	pthread_t fault_thread;
+	pthread_t *threads;
+	size_t total_size;
+	void *data;
+	int ret, opt;
+	size_t i;
+
+	while ((opt = getopt(argc, argv, "n:p:h")) != -1) {
+		switch (opt) {
+		case 'n':
+			num_threads = strtoul(optarg, NULL, 10);
+			break;
+		case 'p':
+			pages_per_thread = strtoul(optarg, NULL, 10);
+			break;
+		case 'h':
+		default:
+			print_usage(argv[0]);
+			return opt == 'h' ? T_EXIT_SKIP : T_EXIT_FAIL;
+		}
+	}
+
+	page_size = sysconf(_SC_PAGESIZE);
+	total_size = num_threads * pages_per_thread * page_size;
+
+	data = mmap(NULL, total_size, PROT_READ | PROT_WRITE,
+		    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+	if (data == MAP_FAILED)
+		return T_EXIT_FAIL;
+
+	ret = init_handler(&handler, data, total_size);
+	if (ret < 0)
+		goto err_munmap;
+	if (ret == T_EXIT_SKIP) {
+		munmap(data, total_size);
+		return T_EXIT_SKIP;
+	}
+
+	pthread_create(&fault_thread, NULL, fault_thread_func, &handler);
+
+	threads = malloc(num_threads * sizeof(pthread_t));
+	if (!threads) {
+		handler_stop(&handler);
+		pthread_join(fault_thread, NULL);
+		destroy_handler(&handler);
+		munmap(data, total_size);
+		return T_EXIT_FAIL;
+	}
+
+	for (i = 0; i < num_threads; i++) {
+		char *ptr = (char *)data + i * pages_per_thread * page_size;
+		pthread_create(&threads[i], NULL, thread_function, ptr);
+	}
+
+	for (i = 0; i < num_threads; i++)
+		pthread_join(threads[i], NULL);
+
+	handler_stop(&handler);
+	pthread_join(fault_thread, NULL);
+
+	free(threads);
+	destroy_handler(&handler);
+	munmap(data, total_size);
+
+	return T_EXIT_PASS;
+
+err_munmap:
+	munmap(data, total_size);
+	return T_EXIT_FAIL;
+}
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2026-07-23 12:47 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-20 11:41 [PATCH] io_uring/rw: fix missing ERESTARTSYS conversion in read paths Yitang Yang
2026-07-21 16:32 ` Jens Axboe
2026-07-22  3:08   ` Yitang Yang
2026-07-22 10:28     ` Jens Axboe
2026-07-22 10:32 ` Jens Axboe
2026-07-22 12:36   ` Yitang Yang
2026-07-22 13:37     ` Jens Axboe
2026-07-23 12:46       ` [PATCH liburing] test: add rw-restart-ret regression test Yitang Yang
2026-07-22 12:45 ` [PATCH v2] io_uring/rw: fix missing ERESTARTSYS conversion in read paths Yitang Yang
2026-07-22 13:37   ` Jens Axboe

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox