From: netdev-bot+sashiko@kernel.org
To: juanlu@fastmail.com
Cc: dw@davidwei.uk, netdev@vger.kernel.org, io-uring@vger.kernel.org,
linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org,
kuba@kernel.org, asml.silence@gmail.com, pabeni@redhat.com,
shuah@kernel.org
Subject: Re: [net-next,v6,4/6] selftests: net: add multithread client support to iou-zcrx
Date: Wed, 02 Sep 2026 23:38:15 +0000 [thread overview]
Message-ID: <178839229576.3394541.5652719733200698350@kernel.org> (raw)
In-Reply-To: <20260831-iou-zcrx-v6-4-02d1d012f0fd@fastmail.com>
Thank you for your contribution! Sashiko AI review found 4 potential
issue(s) to consider:
Critical: 0 · High: 0 · Medium: 2 (1) · Low: 2
- [Medium] run_client() creates cfg_num_threads * cfg_num_threads worker
threads/TCP connections instead of cfg_num_threads, contradicting both…
- [Medium] At this commit the multi-connection client has no counterpart
on the receive side of the same binary: run_server() (iou-zcrx.c:339)…
- [Low] The new -t option is parsed with strtoul() into the signed int
cfg_num_threads (iou-zcrx.c:499) with no syntax, range, or non-zero…
- [Low] At this commit no case in iou-zcrx.py (the only in-tree consumer
of the iou-zcrx binary) passes -t, so the newly added multithreaded…
Pre-existing issues:
- [Medium] client_worker() (iou-zcrx.c:384) walks `payload[sent]` for
cfg_send_size bytes, but payload is allocated with a fixed size of…
--
selftests: net: add multithread client support to iou-zcrx
This adds pthreads to the iou-zcrx client so several connections can be
made at once, and a new -t option to pick how many threads are used
(default 1). The Makefile now links iou-zcrx against -lpthread.
A few questions about the new client code below.
> diff --git a/tools/testing/selftests/drivers/net/hw/iou-zcrx.c b/tools/testing/selftests/drivers/net/hw/iou-zcrx.c
> index 9b62fd0703e61..f793a6c04e412 100644
> --- a/tools/testing/selftests/drivers/net/hw/iou-zcrx.c
> +++ b/tools/testing/selftests/drivers/net/hw/iou-zcrx.c
[ ... ]
> @@ -85,6 +86,7 @@ static int cfg_send_size = SEND_SIZE;
> static struct sockaddr_in6 cfg_addr;
> static unsigned int cfg_rx_buf_len;
> static bool cfg_dry_run;
> +static int cfg_num_threads = 1;
>
> static char *payload;
>
> @@ -379,7 +381,7 @@ static void run_server(void)
> error(1, 0, "test failed\n");
> }
>
> -static void run_client(void)
> +static void *client_worker(void *arg)
> {
> ssize_t to_send = cfg_send_size;
> ssize_t sent = 0;
[Severity: Medium]
This is a pre-existing issue and is not introduced by this patch, since the
code was only renamed from run_client() to client_worker() here, but can
client_worker() read past the end of payload[]?
payload is allocated with a fixed size in main():
if (posix_memalign((void **)&payload, page_size, SEND_SIZE))
while the loop in client_worker() walks cfg_send_size bytes:
ssize_t to_send = cfg_send_size;
...
while (to_send) {
void *src = &payload[sent];
chunk = min_t(ssize_t, cfg_payload_len, to_send);
res = send(fd, src, chunk, 0);
and cfg_send_size comes straight from -z with no comparison against
SEND_SIZE:
case 'z':
cfg_send_size = strtoul(optarg, NULL, 0);
With -z larger than SEND_SIZE (512 * 4096), does &payload[sent] end up past
the allocation, and are those out-of-bounds bytes then handed to send()?
process_recvzc() looks to have the mirror-image indexing on
payload[ctx->received + i]. No in-tree caller currently passes such a
value (iou-zcrx.py uses -z 16384), and this patch only increases the number
of threads that would perform the same read.
> @@ -405,12 +407,36 @@ static void run_client(void)
> }
>
> close(fd);
> + return NULL;
> +}
> +
> +static void run_client(void)
> +{
> + int total_conns = cfg_num_threads * cfg_num_threads;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[Severity: Medium]
Is squaring the thread count here intentional? The changelog says:
Introduce the -t option to control the number of threads (default 1)
and the usage string added by this patch says -t<num_threads>, but
total_conns is cfg_num_threads * cfg_num_threads and is then used as the
calloc() element count and as the bound of both the pthread_create() and
pthread_join() loops in run_client().
So -t 2 gives 4 threads and 4 connections, -t 4 gives 16, and -t 8 gives
64; only the default of 1 matches the documented meaning. Each worker
opens its own socket, so thread stacks and file descriptors also grow
quadratically with a value the help text presents as a plain thread count.
There is no comment explaining the squaring, and the later server patch in
this series treats -t as a literal thread/queue count:
ctxs = calloc(cfg_num_threads, sizeof(*ctxs));
...
pthread_barrier_init(&setup_done, NULL, cfg_num_threads + 1);
At the end of the series (4a6d87a68298) run_client() still has
total_conns = cfg_num_threads * cfg_num_threads and the usage string still
reads -t<num_threads>, so the two halves of the same option keep disagreeing.
Could the squaring be dropped, or the option documented as the per-side
value it actually is?
> + pthread_t *threads;
> + int i, ret;
> +
> + threads = calloc(total_conns, sizeof(*threads));
> + if (!threads)
> + error(1, 0, "calloc()");
> +
> + for (i = 0; i < total_conns; i++) {
> + ret = pthread_create(&threads[i], NULL, client_worker, NULL);
> + if (ret)
> + error(1, ret, "pthread_create()");
> + }
[Severity: Medium]
At this commit, can the server side of the same binary service more than
one of these connections?
run_server() builds a single struct thread_ctx and posts exactly one accept:
add_accept(&ctx, fd);
and process_accept() aborts on the second completion:
if (ctx->connfd)
error(1, 0, "Unexpected second connection");
Verification also uses a single ctx->received cursor into the global
payload, which only tracks one stream. With -t greater than 1, do the
extra connections sit in the backlog while the server exits on the first
stream's EOF, leaving the remaining client_worker() threads to fail in
send() or block until the server timeout?
The receive side gains multi-connection support in the next patch of this
series ("selftests: net: add multithread server support to iou-zcrx"),
where run_server() spawns cfg_num_threads workers, accepts until
accepted < total_conns, dispatches each connfd into ctxs[idx].connfds[],
and drops the "Unexpected second connection" abort. Would it be worth
ordering the server patch first so the tree is never in a state where
-t > 1 cannot complete?
> +
> + for (i = 0; i < total_conns; i++)
> + pthread_join(threads[i], NULL);
> +
> + free(threads);
> }
[Severity: Low]
This isn't a bug, but at this commit no case in iou-zcrx.py passes -t, so
the new pthread_create()/pthread_join() loops in run_client() only ever run
with the default cfg_num_threads == 1 and the multithreaded path is not
exercised by the shipped suite. Coverage arrives later in the series: at
4a6d87a68298 test_zcrx builds both command lines with -t {cfg.num_threads},
and the rss_multiqueue variant sets cfg.num_threads = 2.
>
> static void usage(const char *filepath)
> {
> error(1, 0, "Usage: %s (-4|-6) (-s|-c) -h<server_ip> -p<port> "
> - "-l<payload_size> -i<ifname> -q<rxq_id>", filepath);
> + "-l<payload_size> -i<ifname> -q<rxq_id> -t<num_threads>",
> + filepath);
> }
[ ... ]
> @@ -469,6 +495,9 @@ static void parse_opts(int argc, char **argv)
> case 'd':
> cfg_dry_run = true;
> break;
> + case 't':
> + cfg_num_threads = strtoul(optarg, NULL, 0);
> + break;
[Severity: Low]
This isn't a bug, but -t is stored with strtoul() into the signed int
cfg_num_threads with no non-zero or range check, and run_client() then
evaluates cfg_num_threads * cfg_num_threads in int arithmetic before using
it as a calloc() count and loop bound.
-t 0 and -t 65536 (65536 * 65536 wraps to 0 in int) both create no threads
and let the client exit successfully without sending anything, -t 4294967295
narrows to -1, values at or above 46341 overflow the signed multiplication,
and -t 1000 asks for a million threads.
Note the rest of the file parses its numeric options the same unvalidated
way (-p, -l, -q, -o, -z, -x), so a small sanity check on -t alone would
still be an improvement if the squaring stays.
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260831-iou-zcrx-v6-0-02d1d012f0fd%40fastmail.com
next prev parent reply other threads:[~2026-09-02 23:38 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-31 17:34 [PATCH net-next v6 0/6] selftests: net: make iou-zcrx tests multithreaded Juanlu Herrero
2026-08-31 17:34 ` [PATCH net-next v6 1/6] selftests: net: fix get_refill_ring_size() to use its local variable Juanlu Herrero
2026-08-31 18:09 ` David Wei
2026-08-31 17:34 ` [PATCH net-next v6 2/6] selftests: net: remove unused variable in process_recvzc() Juanlu Herrero
2026-08-31 18:09 ` David Wei
2026-08-31 17:34 ` [PATCH net-next v6 3/6] selftests: net: refactor server state into struct thread_ctx Juanlu Herrero
2026-08-31 17:34 ` [PATCH net-next v6 4/6] selftests: net: add multithread client support to iou-zcrx Juanlu Herrero
2026-09-02 23:38 ` netdev-bot+sashiko [this message]
2026-08-31 17:34 ` [PATCH net-next v6 5/6] selftests: net: add multithread server " Juanlu Herrero
2026-08-31 18:08 ` David Wei
2026-09-02 23:38 ` [net-next,v6,5/6] " netdev-bot+sashiko
2026-09-03 11:06 ` Paolo Abeni
2026-09-03 20:47 ` Juanlu Herrero
2026-08-31 17:34 ` [PATCH net-next v6 6/6] selftests: net: add rss_multiqueue test variant " Juanlu Herrero
2026-09-02 23:38 ` [net-next,v6,6/6] " netdev-bot+sashiko
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=178839229576.3394541.5652719733200698350@kernel.org \
--to=netdev-bot+sashiko@kernel.org \
--cc=asml.silence@gmail.com \
--cc=dw@davidwei.uk \
--cc=io-uring@vger.kernel.org \
--cc=juanlu@fastmail.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=shuah@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox