Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

io_uring/io-wq: add check free worker before create new worker

After commit 0b2b066f8a85 ("io_uring/io-wq: only create a new worker
if it can make progress"), in our produce environment, we still
observe that part of io_worker threads keeps creating and destroying.
After analysis, it was confirmed that this was due to a more complex
scenario involving a large number of fsync operations, which can be
abstracted as frequent write + fsync operations on multiple files in
a single uring instance. Since write is a hash operation while fsync
is not, and fsync is likely to be suspended during execution, the
action of checking the hash value in
io_wqe_dec_running cannot handle such scenarios.
Similarly, if hash-based work and non-hash-based work are sent at the
same time, similar issues are likely to occur.
Returning to the starting point of the issue, when a new work
arrives, io_wq_enqueue may wake up free worker A, while
io_wq_dec_running may create worker B. Ultimately, only one of A and
B can obtain and process the task, leaving the other in an idle
state. In the end, the issue is caused by inconsistent logic in the
checks performed by io_wq_enqueue and io_wq_dec_running.
Therefore, the problem can be resolved by checking for available
workers in io_wq_dec_running.

Signed-off-by: Fengnan Chang <changfengnan@bytedance.com>
Reviewed-by: Diangang Li <lidiangang@bytedance.com>
Link: https://lore.kernel.org/r/20250813120214.18729-1-changfengnan@bytedance.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>

authored by

Fengnan Chang and committed by
Jens Axboe
9d83e1f0 41b70df5

+8
+8
io_uring/io-wq.c
··· 357 357 worker = container_of(cb, struct io_worker, create_work); 358 358 wq = worker->wq; 359 359 acct = worker->acct; 360 + 361 + rcu_read_lock(); 362 + do_create = !io_acct_activate_free_worker(acct); 363 + rcu_read_unlock(); 364 + if (!do_create) 365 + goto no_need_create; 366 + 360 367 raw_spin_lock(&acct->workers_lock); 361 368 362 369 if (acct->nr_workers < acct->max_workers) { ··· 374 367 if (do_create) { 375 368 create_io_worker(wq, acct); 376 369 } else { 370 + no_need_create: 377 371 atomic_dec(&acct->nr_running); 378 372 io_worker_ref_put(wq); 379 373 }