Skip to content

Commit 3d4e4fa

Browse files
Hao Xuaxboe
authored andcommitted
io-wq: fix no lock protection of acct->nr_worker
There is an acct->nr_worker visit without lock protection. Think about the case: two callers call io_wqe_wake_worker(), one is the original context and the other one is an io-worker(by calling io_wqe_enqueue(wqe, linked)), on two cpus paralelly, this may cause nr_worker to be larger than max_worker. Let's fix it by adding lock for it, and let's do nr_workers++ before create_io_worker. There may be a edge cause that the first caller fails to create an io-worker, but the second caller doesn't know it and then quit creating io-worker as well: say nr_worker = max_worker - 1 cpu 0 cpu 1 io_wqe_wake_worker() io_wqe_wake_worker() nr_worker < max_worker nr_worker++ create_io_worker() nr_worker == max_worker failed return return But the chance of this case is very slim. Fixes: 685fe7f ("io-wq: eliminate the need for a manager thread") Signed-off-by: Hao Xu <[email protected]> [axboe: fix unconditional create_io_worker() call] Signed-off-by: Jens Axboe <[email protected]>
1 parent 83d6c39 commit 3d4e4fa

File tree

1 file changed

+17
-6
lines changed

1 file changed

+17
-6
lines changed

fs/io-wq.c

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -247,10 +247,19 @@ static void io_wqe_wake_worker(struct io_wqe *wqe, struct io_wqe_acct *acct)
247247
ret = io_wqe_activate_free_worker(wqe);
248248
rcu_read_unlock();
249249

250-
if (!ret && acct->nr_workers < acct->max_workers) {
251-
atomic_inc(&acct->nr_running);
252-
atomic_inc(&wqe->wq->worker_refs);
253-
create_io_worker(wqe->wq, wqe, acct->index);
250+
if (!ret) {
251+
bool do_create = false;
252+
253+
raw_spin_lock_irq(&wqe->lock);
254+
if (acct->nr_workers < acct->max_workers) {
255+
atomic_inc(&acct->nr_running);
256+
atomic_inc(&wqe->wq->worker_refs);
257+
acct->nr_workers++;
258+
do_create = true;
259+
}
260+
raw_spin_unlock_irq(&wqe->lock);
261+
if (do_create)
262+
create_io_worker(wqe->wq, wqe, acct->index);
254263
}
255264
}
256265

@@ -635,6 +644,9 @@ static void create_io_worker(struct io_wq *wq, struct io_wqe *wqe, int index)
635644
kfree(worker);
636645
fail:
637646
atomic_dec(&acct->nr_running);
647+
raw_spin_lock_irq(&wqe->lock);
648+
acct->nr_workers--;
649+
raw_spin_unlock_irq(&wqe->lock);
638650
io_worker_ref_put(wq);
639651
return;
640652
}
@@ -650,9 +662,8 @@ static void create_io_worker(struct io_wq *wq, struct io_wqe *wqe, int index)
650662
worker->flags |= IO_WORKER_F_FREE;
651663
if (index == IO_WQ_ACCT_BOUND)
652664
worker->flags |= IO_WORKER_F_BOUND;
653-
if (!acct->nr_workers && (worker->flags & IO_WORKER_F_BOUND))
665+
if ((acct->nr_workers == 1) && (worker->flags & IO_WORKER_F_BOUND))
654666
worker->flags |= IO_WORKER_F_FIXED;
655-
acct->nr_workers++;
656667
raw_spin_unlock_irq(&wqe->lock);
657668
wake_up_new_task(tsk);
658669
}

0 commit comments

Comments
 (0)