mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-08 14:23:19 +00:00
io_uring-5.14-2021-08-07
-----BEGIN PGP SIGNATURE----- iQJEBAABCAAuFiEEwPw5LcreJtl1+l5K99NY+ylx4KYFAmEOuKcQHGF4Ym9lQGtl cm5lbC5kawAKCRD301j7KXHgpk4WD/9XQIUM2WmJrWCdrGJ64hgWyOFMg7Zhzbwn 1swI2yMRcAHVOphP3Iyavxn7JHk+AKRcRgnjsKBdIn1WykkRwoIGfYGhTaO2zD7E T6r8BH/qLkwJcbhA9KNmhA3gf/zEnJgvc6JOVMtSvAdO6FTSfrh1aQneb/xjr0hx Yuy4dUtx6AmXjUZ0lh4XCud8IOzOrvjF9cZHVq/Q+DP+m/MnlpZOVws9Ge0XeAgN t7I9NouiyHNt5Z1SIQITbPvAGjY6/z/j2FOuECxgfdo7VpNUgK+V3byaXLFwLjLf X7DI9G1pf0fNPOrJktS7WarLVX4NKw8nt1Og5iOhFp7MoBl6SMWWY/2YOESk172g k0KGnPeoF+NZGnCyWLs6cEk6X0KQODAwWLhiYUuDcP3C/3H9BNNIR3IkfRhhOoJZ 1aTvMjYRa0uD/fRnHydEfMlLl9PyjnmVFD8WLwI70zUO0GpuhlfLIq0rWgtsOG35 s/CJVDH4VoDnMsx5Pg+oXsywiKDhhVLP2y4D35B2ivFrrLy+pAfXI8t7+IVP5Xm4 sMmVqEtZLBvYBxrbsO81cWI5Ddcc4/z+F/I5DfACdi26GZC/Pn1/L3Le+i4zLypz CEY8vSM9+qgApxElaWrNOPtOFWV/XUll3lRLNIT9QncqtdmDdkofBdSv9lNj+wRt pVhBn/B6NQ== =FAeG -----END PGP SIGNATURE----- Merge tag 'io_uring-5.14-2021-08-07' of git://git.kernel.dk/linux-block Pull io_uring from Jens Axboe: "A few io-wq related fixes: - Fix potential nr_worker race and missing max_workers check from one path (Hao) - Fix race between worker exiting and new work queue (me)" * tag 'io_uring-5.14-2021-08-07' of git://git.kernel.dk/linux-block: io-wq: fix lack of acct->nr_workers < acct->max_workers judgement io-wq: fix no lock protection of acct->nr_worker io-wq: fix race between worker exiting and activating free worker
This commit is contained in:
commit
85a90500f9
71
fs/io-wq.c
71
fs/io-wq.c
@ -130,6 +130,7 @@ struct io_cb_cancel_data {
|
||||
};
|
||||
|
||||
static void create_io_worker(struct io_wq *wq, struct io_wqe *wqe, int index);
|
||||
static void io_wqe_dec_running(struct io_worker *worker);
|
||||
|
||||
static bool io_worker_get(struct io_worker *worker)
|
||||
{
|
||||
@ -168,26 +169,21 @@ static void io_worker_exit(struct io_worker *worker)
|
||||
{
|
||||
struct io_wqe *wqe = worker->wqe;
|
||||
struct io_wqe_acct *acct = io_wqe_get_acct(worker);
|
||||
unsigned flags;
|
||||
|
||||
if (refcount_dec_and_test(&worker->ref))
|
||||
complete(&worker->ref_done);
|
||||
wait_for_completion(&worker->ref_done);
|
||||
|
||||
preempt_disable();
|
||||
current->flags &= ~PF_IO_WORKER;
|
||||
flags = worker->flags;
|
||||
worker->flags = 0;
|
||||
if (flags & IO_WORKER_F_RUNNING)
|
||||
atomic_dec(&acct->nr_running);
|
||||
worker->flags = 0;
|
||||
preempt_enable();
|
||||
|
||||
raw_spin_lock_irq(&wqe->lock);
|
||||
if (flags & IO_WORKER_F_FREE)
|
||||
if (worker->flags & IO_WORKER_F_FREE)
|
||||
hlist_nulls_del_rcu(&worker->nulls_node);
|
||||
list_del_rcu(&worker->all_list);
|
||||
acct->nr_workers--;
|
||||
preempt_disable();
|
||||
io_wqe_dec_running(worker);
|
||||
worker->flags = 0;
|
||||
current->flags &= ~PF_IO_WORKER;
|
||||
preempt_enable();
|
||||
raw_spin_unlock_irq(&wqe->lock);
|
||||
|
||||
kfree_rcu(worker, rcu);
|
||||
@ -214,15 +210,19 @@ static bool io_wqe_activate_free_worker(struct io_wqe *wqe)
|
||||
struct hlist_nulls_node *n;
|
||||
struct io_worker *worker;
|
||||
|
||||
n = rcu_dereference(hlist_nulls_first_rcu(&wqe->free_list));
|
||||
if (is_a_nulls(n))
|
||||
return false;
|
||||
|
||||
worker = hlist_nulls_entry(n, struct io_worker, nulls_node);
|
||||
if (io_worker_get(worker)) {
|
||||
wake_up_process(worker->task);
|
||||
/*
|
||||
* Iterate free_list and see if we can find an idle worker to
|
||||
* activate. If a given worker is on the free_list but in the process
|
||||
* of exiting, keep trying.
|
||||
*/
|
||||
hlist_nulls_for_each_entry_rcu(worker, n, &wqe->free_list, nulls_node) {
|
||||
if (!io_worker_get(worker))
|
||||
continue;
|
||||
if (wake_up_process(worker->task)) {
|
||||
io_worker_release(worker);
|
||||
return true;
|
||||
}
|
||||
io_worker_release(worker);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -247,10 +247,19 @@ static void io_wqe_wake_worker(struct io_wqe *wqe, struct io_wqe_acct *acct)
|
||||
ret = io_wqe_activate_free_worker(wqe);
|
||||
rcu_read_unlock();
|
||||
|
||||
if (!ret && acct->nr_workers < acct->max_workers) {
|
||||
atomic_inc(&acct->nr_running);
|
||||
atomic_inc(&wqe->wq->worker_refs);
|
||||
create_io_worker(wqe->wq, wqe, acct->index);
|
||||
if (!ret) {
|
||||
bool do_create = false;
|
||||
|
||||
raw_spin_lock_irq(&wqe->lock);
|
||||
if (acct->nr_workers < acct->max_workers) {
|
||||
atomic_inc(&acct->nr_running);
|
||||
atomic_inc(&wqe->wq->worker_refs);
|
||||
acct->nr_workers++;
|
||||
do_create = true;
|
||||
}
|
||||
raw_spin_unlock_irq(&wqe->lock);
|
||||
if (do_create)
|
||||
create_io_worker(wqe->wq, wqe, acct->index);
|
||||
}
|
||||
}
|
||||
|
||||
@ -271,9 +280,17 @@ static void create_worker_cb(struct callback_head *cb)
|
||||
{
|
||||
struct create_worker_data *cwd;
|
||||
struct io_wq *wq;
|
||||
struct io_wqe *wqe;
|
||||
struct io_wqe_acct *acct;
|
||||
|
||||
cwd = container_of(cb, struct create_worker_data, work);
|
||||
wq = cwd->wqe->wq;
|
||||
wqe = cwd->wqe;
|
||||
wq = wqe->wq;
|
||||
acct = &wqe->acct[cwd->index];
|
||||
raw_spin_lock_irq(&wqe->lock);
|
||||
if (acct->nr_workers < acct->max_workers)
|
||||
acct->nr_workers++;
|
||||
raw_spin_unlock_irq(&wqe->lock);
|
||||
create_io_worker(wq, cwd->wqe, cwd->index);
|
||||
kfree(cwd);
|
||||
}
|
||||
@ -635,6 +652,9 @@ static void create_io_worker(struct io_wq *wq, struct io_wqe *wqe, int index)
|
||||
kfree(worker);
|
||||
fail:
|
||||
atomic_dec(&acct->nr_running);
|
||||
raw_spin_lock_irq(&wqe->lock);
|
||||
acct->nr_workers--;
|
||||
raw_spin_unlock_irq(&wqe->lock);
|
||||
io_worker_ref_put(wq);
|
||||
return;
|
||||
}
|
||||
@ -650,9 +670,8 @@ static void create_io_worker(struct io_wq *wq, struct io_wqe *wqe, int index)
|
||||
worker->flags |= IO_WORKER_F_FREE;
|
||||
if (index == IO_WQ_ACCT_BOUND)
|
||||
worker->flags |= IO_WORKER_F_BOUND;
|
||||
if (!acct->nr_workers && (worker->flags & IO_WORKER_F_BOUND))
|
||||
if ((acct->nr_workers == 1) && (worker->flags & IO_WORKER_F_BOUND))
|
||||
worker->flags |= IO_WORKER_F_FIXED;
|
||||
acct->nr_workers++;
|
||||
raw_spin_unlock_irq(&wqe->lock);
|
||||
wake_up_new_task(tsk);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user