Skip to content

Commit b3dbbae

Browse files
committed
Merge tag 'io_uring-5.13-2021-05-28' of git://git.kernel.dk/linux-block
Pull io_uring fixes from Jens Axboe: "A few minor fixes: - Fix an issue with hashed wait removal on exit (Zqiang, Pavel) - Fix a recent data race introduced in this series (Marco)" * tag 'io_uring-5.13-2021-05-28' of git://git.kernel.dk/linux-block: io_uring: fix data race to avoid potential NULL-deref io-wq: Fix UAF when wakeup wqe in hash waitqueue io_uring/io-wq: close io-wq full-stop gap
2 parents 567d1fd + b16ef42 commit b3dbbae

File tree

3 files changed

+29
-17
lines changed

3 files changed

+29
-17
lines changed

fs/io-wq.c

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -979,13 +979,16 @@ static bool io_task_work_match(struct callback_head *cb, void *data)
979979
return cwd->wqe->wq == data;
980980
}
981981

982+
void io_wq_exit_start(struct io_wq *wq)
983+
{
984+
set_bit(IO_WQ_BIT_EXIT, &wq->state);
985+
}
986+
982987
static void io_wq_exit_workers(struct io_wq *wq)
983988
{
984989
struct callback_head *cb;
985990
int node;
986991

987-
set_bit(IO_WQ_BIT_EXIT, &wq->state);
988-
989992
if (!wq->task)
990993
return;
991994

@@ -1003,13 +1006,16 @@ static void io_wq_exit_workers(struct io_wq *wq)
10031006
struct io_wqe *wqe = wq->wqes[node];
10041007

10051008
io_wq_for_each_worker(wqe, io_wq_worker_wake, NULL);
1006-
spin_lock_irq(&wq->hash->wait.lock);
1007-
list_del_init(&wq->wqes[node]->wait.entry);
1008-
spin_unlock_irq(&wq->hash->wait.lock);
10091009
}
10101010
rcu_read_unlock();
10111011
io_worker_ref_put(wq);
10121012
wait_for_completion(&wq->worker_done);
1013+
1014+
for_each_node(node) {
1015+
spin_lock_irq(&wq->hash->wait.lock);
1016+
list_del_init(&wq->wqes[node]->wait.entry);
1017+
spin_unlock_irq(&wq->hash->wait.lock);
1018+
}
10131019
put_task_struct(wq->task);
10141020
wq->task = NULL;
10151021
}
@@ -1020,8 +1026,6 @@ static void io_wq_destroy(struct io_wq *wq)
10201026

10211027
cpuhp_state_remove_instance_nocalls(io_wq_online, &wq->cpuhp_node);
10221028

1023-
io_wq_exit_workers(wq);
1024-
10251029
for_each_node(node) {
10261030
struct io_wqe *wqe = wq->wqes[node];
10271031
struct io_cb_cancel_data match = {
@@ -1036,16 +1040,13 @@ static void io_wq_destroy(struct io_wq *wq)
10361040
kfree(wq);
10371041
}
10381042

1039-
void io_wq_put(struct io_wq *wq)
1040-
{
1041-
if (refcount_dec_and_test(&wq->refs))
1042-
io_wq_destroy(wq);
1043-
}
1044-
10451043
void io_wq_put_and_exit(struct io_wq *wq)
10461044
{
1045+
WARN_ON_ONCE(!test_bit(IO_WQ_BIT_EXIT, &wq->state));
1046+
10471047
io_wq_exit_workers(wq);
1048-
io_wq_put(wq);
1048+
if (refcount_dec_and_test(&wq->refs))
1049+
io_wq_destroy(wq);
10491050
}
10501051

10511052
static bool io_wq_worker_affinity(struct io_worker *worker, void *data)

fs/io-wq.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ struct io_wq_data {
122122
};
123123

124124
struct io_wq *io_wq_create(unsigned bounded, struct io_wq_data *data);
125-
void io_wq_put(struct io_wq *wq);
125+
void io_wq_exit_start(struct io_wq *wq);
126126
void io_wq_put_and_exit(struct io_wq *wq);
127127

128128
void io_wq_enqueue(struct io_wq *wq, struct io_wq_work *work);

fs/io_uring.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9039,11 +9039,16 @@ static void io_uring_clean_tctx(struct io_uring_task *tctx)
90399039
struct io_tctx_node *node;
90409040
unsigned long index;
90419041

9042-
tctx->io_wq = NULL;
90439042
xa_for_each(&tctx->xa, index, node)
90449043
io_uring_del_task_file(index);
9045-
if (wq)
9044+
if (wq) {
9045+
/*
9046+
* Must be after io_uring_del_task_file() (removes nodes under
9047+
* uring_lock) to avoid race with io_uring_try_cancel_iowq().
9048+
*/
9049+
tctx->io_wq = NULL;
90469050
io_wq_put_and_exit(wq);
9051+
}
90479052
}
90489053

90499054
static s64 tctx_inflight(struct io_uring_task *tctx, bool tracked)
@@ -9078,6 +9083,9 @@ static void io_uring_cancel_sqpoll(struct io_sq_data *sqd)
90789083

90799084
if (!current->io_uring)
90809085
return;
9086+
if (tctx->io_wq)
9087+
io_wq_exit_start(tctx->io_wq);
9088+
90819089
WARN_ON_ONCE(!sqd || sqd->thread != current);
90829090

90839091
atomic_inc(&tctx->in_idle);
@@ -9112,6 +9120,9 @@ void __io_uring_cancel(struct files_struct *files)
91129120
DEFINE_WAIT(wait);
91139121
s64 inflight;
91149122

9123+
if (tctx->io_wq)
9124+
io_wq_exit_start(tctx->io_wq);
9125+
91159126
/* make sure overflow events are dropped */
91169127
atomic_inc(&tctx->in_idle);
91179128
do {

0 commit comments

Comments
 (0)