Re: [net-next,v6,5/6] selftests: net: add multithread server support to iou-zcrx
From: Bobby Eshleman <hidden>
Date: 2026-09-09 16:17:04
Also in:
io-uring, linux-kselftest, lkml
On Wed, Sep 02, 2026 at 11:38:17PM +0000, netdev-bot+sashiko@kernel.org wrote:
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
[...]
quoted
@@ -356,29 +444,68 @@ static void run_server(void) if (ret < 0) error(1, 0, "bind()"); - flags |= IORING_SETUP_COOP_TASKRUN; - flags |= IORING_SETUP_SINGLE_ISSUER; - flags |= IORING_SETUP_DEFER_TASKRUN; - flags |= IORING_SETUP_SUBMIT_ALL; - flags |= IORING_SETUP_CQE32; + pthread_barrier_init(&setup_done, NULL, cfg_num_threads + 1); + pthread_barrier_init(&dispatch_done, NULL, cfg_num_threads + 1); + + for (i = 0; i < cfg_num_threads; i++) { + ctxs[i].queue_id = cfg_queue_id + i; + ctxs[i].setup_done = &setup_done; + ctxs[i].dispatch_done = &dispatch_done; + } - io_uring_queue_init(512, &ctx.ring, flags); + for (i = 0; i < cfg_num_threads; i++) { + ret = pthread_create(&threads[i], NULL, + server_worker, &ctxs[i]); + if (ret) + error(1, ret, "pthread_create()"); + } - setup_zcrx(&ctx); if (cfg_dry_run) - return; + goto join; if (listen(fd, 1024) < 0) error(1, 0, "listen()"); - add_accept(&ctx, fd); + pthread_barrier_wait(&setup_done);[Severity: High] Is the listen() intentionally moved before the workers have registered their ifqs? The main thread creates the threads, calls listen(), and only then waits on setup_done, while the workers reach that barrier after io_uring_queue_init_params() plus setup_zcrx(), i.e. after io_uring_register_ifq() has restarted the device RX queue. Before the patch the sequence was serialized in one thread: io_uring_queue_init(512, &ctx.ring, flags); setup_zcrx(&ctx); ... listen(fd, 1024); so the port only became visible once the memory provider was installed. Two existing tests depend on that ordering. wait_port_listen() in net/lib/py/utils.py polls every 5 ms, so it can now return while registration is still in flight: iou-zcrx.py:test_zcrx_large_chunks() { wait_port_listen(cfg.port, proto="tcp") check_iou_rx_buf_len(cfg, rx_buf_len) } check_iou_rx_buf_len() raises "Expected 1 io-uring page pool, found 0", and nk_qlease.py:test_destroy() does queue_get() plus ksft_in("io-uring", queue_info) immediately after wait_port_listen() with no sleep. Beyond the harness races, data delivered into the queue before the provider exists is serviced by the copy fallback rather than zero copy, and the queue restart during registration can drop in-flight frames. Would moving listen() below pthread_barrier_wait(&setup_done) restore the previous guarantee?
Just a heads up that I tested this on BRCM and did find this listen() ordering issue to cause genuine (but flaky) regression for nk_qlease.test_destroy. Moving the listen() to after wait(setup_done) indeed fixed it. Best, Bobby