Commit 0242f642 authored by Jens Axboe's avatar Jens Axboe

io-wq: fix queue stalling race

We need to set the stalled bit early, before we drop the lock for adding
us to the stall hash queue. If not, then we can race with new work being
queued between adding us to the stall hash and io_worker_handle_work()
marking us stalled.
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent b8ce1b9d
...@@ -436,8 +436,7 @@ static bool io_worker_can_run_work(struct io_worker *worker, ...@@ -436,8 +436,7 @@ static bool io_worker_can_run_work(struct io_worker *worker,
} }
static struct io_wq_work *io_get_next_work(struct io_wqe *wqe, static struct io_wq_work *io_get_next_work(struct io_wqe *wqe,
struct io_worker *worker, struct io_worker *worker)
bool *stalled)
__must_hold(wqe->lock) __must_hold(wqe->lock)
{ {
struct io_wq_work_node *node, *prev; struct io_wq_work_node *node, *prev;
...@@ -475,10 +474,14 @@ static struct io_wq_work *io_get_next_work(struct io_wqe *wqe, ...@@ -475,10 +474,14 @@ static struct io_wq_work *io_get_next_work(struct io_wqe *wqe,
} }
if (stall_hash != -1U) { if (stall_hash != -1U) {
/*
* Set this before dropping the lock to avoid racing with new
* work being added and clearing the stalled bit.
*/
wqe->flags |= IO_WQE_FLAG_STALLED;
raw_spin_unlock(&wqe->lock); raw_spin_unlock(&wqe->lock);
io_wait_on_hash(wqe, stall_hash); io_wait_on_hash(wqe, stall_hash);
raw_spin_lock(&wqe->lock); raw_spin_lock(&wqe->lock);
*stalled = true;
} }
return NULL; return NULL;
...@@ -518,7 +521,6 @@ static void io_worker_handle_work(struct io_worker *worker) ...@@ -518,7 +521,6 @@ static void io_worker_handle_work(struct io_worker *worker)
do { do {
struct io_wq_work *work; struct io_wq_work *work;
bool stalled;
get_next: get_next:
/* /*
* If we got some work, mark us as busy. If we didn't, but * If we got some work, mark us as busy. If we didn't, but
...@@ -527,12 +529,9 @@ static void io_worker_handle_work(struct io_worker *worker) ...@@ -527,12 +529,9 @@ static void io_worker_handle_work(struct io_worker *worker)
* can't make progress, any work completion or insertion will * can't make progress, any work completion or insertion will
* clear the stalled flag. * clear the stalled flag.
*/ */
stalled = false; work = io_get_next_work(wqe, worker);
work = io_get_next_work(wqe, worker, &stalled);
if (work) if (work)
__io_worker_busy(wqe, worker, work); __io_worker_busy(wqe, worker, work);
else if (stalled)
wqe->flags |= IO_WQE_FLAG_STALLED;
raw_spin_unlock(&wqe->lock); raw_spin_unlock(&wqe->lock);
if (!work) if (!work)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment