Skip to content

Commit 4c628e9

Browse files
axboejosephhz
authored andcommitted
io-wq: wait for io_wq_create() to setup necessary workers
commit b60fda6 upstream We currently have a race where if setup is really slow, we can be calling io_wq_destroy() before we're done setting up. This will cause the caller to get stuck waiting for the manager to set things up, but the manager already exited. Fix this by doing a sync setup of the manager. This also fixes the case where if we failed creating workers, we'd also get stuck. In practice this race window was really small, as we already wait for the manager to start. Hence someone would have to call io_wq_destroy() after the task has started, but before it started the first loop. The reported test case forked tons of these, which is why it became an issue. Reported-by: syzbot+0f1cc17f85154f400465@syzkaller.appspotmail.com Fixes: 771b53d ("io-wq: small threadpool implementation for io_uring") Signed-off-by: Jens Axboe <axboe@kernel.dk> Signed-off-by: Xiaoguang Wang <xiaoguang.wang@linux.alibaba.com> Acked-by: Joseph Qi <joseph.qi@linux.alibaba.com>
1 parent 3b8ddc9 commit 4c628e9

File tree

1 file changed

+35
-15
lines changed

1 file changed

+35
-15
lines changed

fs/io-wq.c

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ enum {
3434
enum {
3535
IO_WQ_BIT_EXIT = 0, /* wq exiting */
3636
IO_WQ_BIT_CANCEL = 1, /* cancel work on list */
37+
IO_WQ_BIT_ERROR = 2, /* error on setup */
3738
};
3839

3940
enum {
@@ -574,14 +575,14 @@ void io_wq_worker_sleeping(struct task_struct *tsk)
574575
spin_unlock_irq(&wqe->lock);
575576
}
576577

577-
static void create_io_worker(struct io_wq *wq, struct io_wqe *wqe, int index)
578+
static bool create_io_worker(struct io_wq *wq, struct io_wqe *wqe, int index)
578579
{
579580
struct io_wqe_acct *acct =&wqe->acct[index];
580581
struct io_worker *worker;
581582

582583
worker = kcalloc_node(1, sizeof(*worker), GFP_KERNEL, wqe->node);
583584
if (!worker)
584-
return;
585+
return false;
585586

586587
refcount_set(&worker->ref, 1);
587588
worker->nulls_node.pprev = NULL;
@@ -592,7 +593,7 @@ static void create_io_worker(struct io_wq *wq, struct io_wqe *wqe, int index)
592593
"io_wqe_worker-%d/%d", index, wqe->node);
593594
if (IS_ERR(worker->task)) {
594595
kfree(worker);
595-
return;
596+
return false;
596597
}
597598

598599
spin_lock_irq(&wqe->lock);
@@ -609,16 +610,14 @@ static void create_io_worker(struct io_wq *wq, struct io_wqe *wqe, int index)
609610
atomic_inc(&wq->user->processes);
610611

611612
wake_up_process(worker->task);
613+
return true;
612614
}
613615

614616
static inline bool io_wqe_need_worker(struct io_wqe *wqe, int index)
615617
__must_hold(wqe->lock)
616618
{
617619
struct io_wqe_acct *acct = &wqe->acct[index];
618620

619-
/* always ensure we have one bounded worker */
620-
if (index == IO_WQ_ACCT_BOUND && !acct->nr_workers)
621-
return true;
622621
/* if we have available workers or no work, no need */
623622
if (!hlist_nulls_empty(&wqe->free_list.head) || !io_wqe_run_queue(wqe))
624623
return false;
@@ -631,10 +630,19 @@ static inline bool io_wqe_need_worker(struct io_wqe *wqe, int index)
631630
static int io_wq_manager(void *data)
632631
{
633632
struct io_wq *wq = data;
633+
int i;
634634

635-
while (!kthread_should_stop()) {
636-
int i;
635+
/* create fixed workers */
636+
refcount_set(&wq->refs, wq->nr_wqes);
637+
for (i = 0; i < wq->nr_wqes; i++) {
638+
if (create_io_worker(wq, wq->wqes[i], IO_WQ_ACCT_BOUND))
639+
continue;
640+
goto err;
641+
}
637642

643+
complete(&wq->done);
644+
645+
while (!kthread_should_stop()) {
638646
for (i = 0; i < wq->nr_wqes; i++) {
639647
struct io_wqe *wqe = wq->wqes[i];
640648
bool fork_worker[2] = { false, false };
@@ -655,6 +663,12 @@ static int io_wq_manager(void *data)
655663
}
656664

657665
return 0;
666+
err:
667+
set_bit(IO_WQ_BIT_ERROR, &wq->state);
668+
set_bit(IO_WQ_BIT_EXIT, &wq->state);
669+
if (refcount_sub_and_test(wq->nr_wqes - i, &wq->refs))
670+
complete(&wq->done);
671+
return 0;
658672
}
659673

660674
static bool io_wq_can_queue(struct io_wqe *wqe, struct io_wqe_acct *acct,
@@ -1006,7 +1020,6 @@ struct io_wq *io_wq_create(unsigned bounded, struct io_wq_data *data)
10061020
wq->creds = data->creds;
10071021

10081022
i = 0;
1009-
refcount_set(&wq->refs, wq->nr_wqes);
10101023
for_each_online_node(node) {
10111024
struct io_wqe *wqe;
10121025

@@ -1045,14 +1058,22 @@ struct io_wq *io_wq_create(unsigned bounded, struct io_wq_data *data)
10451058
wq->manager = kthread_create(io_wq_manager, wq, "io_wq_manager");
10461059
if (!IS_ERR(wq->manager)) {
10471060
wake_up_process(wq->manager);
1061+
wait_for_completion(&wq->done);
1062+
if (test_bit(IO_WQ_BIT_ERROR, &wq->state)) {
1063+
ret = -ENOMEM;
1064+
goto err;
1065+
}
1066+
reinit_completion(&wq->done);
10481067
return wq;
10491068
}
10501069

10511070
ret = PTR_ERR(wq->manager);
1052-
wq->manager = NULL;
1053-
err:
10541071
complete(&wq->done);
1055-
io_wq_destroy(wq);
1072+
err:
1073+
for (i = 0; i < wq->nr_wqes; i++)
1074+
kfree(wq->wqes[i]);
1075+
kfree(wq->wqes);
1076+
kfree(wq);
10561077
return ERR_PTR(ret);
10571078
}
10581079

@@ -1066,10 +1087,9 @@ void io_wq_destroy(struct io_wq *wq)
10661087
{
10671088
int i;
10681089

1069-
if (wq->manager) {
1070-
set_bit(IO_WQ_BIT_EXIT, &wq->state);
1090+
set_bit(IO_WQ_BIT_EXIT, &wq->state);
1091+
if (wq->manager)
10711092
kthread_stop(wq->manager);
1072-
}
10731093

10741094
rcu_read_lock();
10751095
for (i = 0; i < wq->nr_wqes; i++) {

0 commit comments

Comments
 (0)