summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorPavel Begunkov <asml.silence@gmail.com>2020-08-23 20:33:10 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2020-09-03 12:29:43 +0300
commit13f35a2c0fd5c6a4fcd8903542b053bcc914fcf5 (patch)
treee611be6427d30c925b2a13aee291dd78da2f6401 /fs
parent96d020ddff6adff267a6900bcfcd46a8993f5152 (diff)
downloadlinux-13f35a2c0fd5c6a4fcd8903542b053bcc914fcf5.tar.xz
io-wq: fix hang after cancelling pending hashed work
commit 204361a77f4018627addd4a06877448f088ddfc0 upstream. Don't forget to update wqe->hash_tail after cancelling a pending work item, if it was hashed. Cc: stable@vger.kernel.org # 5.7+ Reported-by: Dmitry Shulyak <yashulyak@gmail.com> Fixes: 86f3cd1b589a1 ("io-wq: handle hashed writes in chains") Signed-off-by: Pavel Begunkov <asml.silence@gmail.com> Signed-off-by: Jens Axboe <axboe@kernel.dk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/io-wq.c21
1 files changed, 19 insertions, 2 deletions
diff --git a/fs/io-wq.c b/fs/io-wq.c
index 47c5f3aeb460..cb9e5a444fba 100644
--- a/fs/io-wq.c
+++ b/fs/io-wq.c
@@ -929,6 +929,24 @@ static bool io_wq_worker_cancel(struct io_worker *worker, void *data)
return match->nr_running && !match->cancel_all;
}
+static inline void io_wqe_remove_pending(struct io_wqe *wqe,
+ struct io_wq_work *work,
+ struct io_wq_work_node *prev)
+{
+ unsigned int hash = io_get_work_hash(work);
+ struct io_wq_work *prev_work = NULL;
+
+ if (io_wq_is_hashed(work) && work == wqe->hash_tail[hash]) {
+ if (prev)
+ prev_work = container_of(prev, struct io_wq_work, list);
+ if (prev_work && io_get_work_hash(prev_work) == hash)
+ wqe->hash_tail[hash] = prev_work;
+ else
+ wqe->hash_tail[hash] = NULL;
+ }
+ wq_list_del(&wqe->work_list, &work->list, prev);
+}
+
static void io_wqe_cancel_pending_work(struct io_wqe *wqe,
struct io_cb_cancel_data *match)
{
@@ -942,8 +960,7 @@ retry:
work = container_of(node, struct io_wq_work, list);
if (!match->fn(work, match->data))
continue;
-
- wq_list_del(&wqe->work_list, node, prev);
+ io_wqe_remove_pending(wqe, work, prev);
spin_unlock_irqrestore(&wqe->lock, flags);
io_run_cancel(work, wqe);
match->nr_pending++;