Skip to content

Commit 0b2b066

Browse files
committed
io_uring/io-wq: only create a new worker if it can make progress
Hashed work is serialized by io-wq, intended to be used for cases like serializing buffered writes to a regular file, where the file system will serialize the workers anyway with a mutex or similar. Since they would be forcibly serialized and blocked, it's more efficient for io-wq to handle these individually rather than issue them in parallel. If a worker is currently handling a hashed work item and gets blocked, don't create a new worker if the next work item is also hashed and mapped to the same bucket. That new worker would not be able to make any progress anyway. Reported-by: Fengnan Chang <[email protected]> Reported-by: Diangang Li <[email protected]> Link: https://lore.kernel.org/io-uring/[email protected]/ Signed-off-by: Jens Axboe <[email protected]>
1 parent 8343cae commit 0b2b066

File tree

1 file changed

+28
-0
lines changed

1 file changed

+28
-0
lines changed

io_uring/io-wq.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,30 @@ static bool io_queue_worker_create(struct io_worker *worker,
419419
return false;
420420
}
421421

422+
/* Defer if current and next work are both hashed to the same chain */
423+
static bool io_wq_hash_defer(struct io_wq_work *work, struct io_wq_acct *acct)
424+
{
425+
unsigned int hash, work_flags;
426+
struct io_wq_work *next;
427+
428+
lockdep_assert_held(&acct->lock);
429+
430+
work_flags = atomic_read(&work->flags);
431+
if (!__io_wq_is_hashed(work_flags))
432+
return false;
433+
434+
/* should not happen, io_acct_run_queue() said we had work */
435+
if (wq_list_empty(&acct->work_list))
436+
return true;
437+
438+
hash = __io_get_work_hash(work_flags);
439+
next = container_of(acct->work_list.first, struct io_wq_work, list);
440+
work_flags = atomic_read(&next->flags);
441+
if (!__io_wq_is_hashed(work_flags))
442+
return false;
443+
return hash == __io_get_work_hash(work_flags);
444+
}
445+
422446
static void io_wq_dec_running(struct io_worker *worker)
423447
{
424448
struct io_wq_acct *acct = io_wq_get_acct(worker);
@@ -433,6 +457,10 @@ static void io_wq_dec_running(struct io_worker *worker)
433457
return;
434458
if (!io_acct_run_queue(acct))
435459
return;
460+
if (io_wq_hash_defer(worker->cur_work, acct)) {
461+
raw_spin_unlock(&acct->lock);
462+
return;
463+
}
436464

437465
raw_spin_unlock(&acct->lock);
438466
atomic_inc(&acct->nr_running);

0 commit comments

Comments
 (0)