From: Greg Kroah-Hartman Date: Mon, 15 Nov 2021 14:27:33 +0000 (+0100) Subject: 5.14-stable patches X-Git-Tag: v5.4.160~44 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0d2f456fc194c1b073d8edc4f0abe69b050f258b;p=thirdparty%2Fkernel%2Fstable-queue.git 5.14-stable patches added patches: io-wq-ensure-that-hash-wait-lock-is-irq-disabling.patch io-wq-fix-queue-stalling-race.patch io-wq-serialize-hash-clear-with-wakeup.patch --- diff --git a/queue-5.14/io-wq-ensure-that-hash-wait-lock-is-irq-disabling.patch b/queue-5.14/io-wq-ensure-that-hash-wait-lock-is-irq-disabling.patch new file mode 100644 index 00000000000..406ee07326e --- /dev/null +++ b/queue-5.14/io-wq-ensure-that-hash-wait-lock-is-irq-disabling.patch @@ -0,0 +1,43 @@ +From foo@baz Mon Nov 15 03:27:04 PM CET 2021 +From: Jens Axboe +Date: Tue, 31 Aug 2021 06:57:25 -0600 +Subject: io-wq: ensure that hash wait lock is IRQ disabling + +From: Jens Axboe + +commit 08bdbd39b58474d762242e1fadb7f2eb9ffcca71 upstream. + +A previous commit removed the IRQ safety of the worker and wqe locks, +but that left one spot of the hash wait lock now being done without +already having IRQs disabled. + +Ensure that we use the right locking variant for the hashed waitqueue +lock. + +Fixes: a9a4aa9fbfc5 ("io-wq: wqe and worker locks no longer need to be IRQ safe") +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman +--- + fs/io-wq.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/fs/io-wq.c ++++ b/fs/io-wq.c +@@ -405,7 +405,7 @@ static void io_wait_on_hash(struct io_wq + { + struct io_wq *wq = wqe->wq; + +- spin_lock(&wq->hash->wait.lock); ++ spin_lock_irq(&wq->hash->wait.lock); + if (list_empty(&wqe->wait.entry)) { + __add_wait_queue(&wq->hash->wait, &wqe->wait); + if (!test_bit(hash, &wq->hash->map)) { +@@ -413,7 +413,7 @@ static void io_wait_on_hash(struct io_wq + list_del_init(&wqe->wait.entry); + } + } +- spin_unlock(&wq->hash->wait.lock); ++ spin_unlock_irq(&wq->hash->wait.lock); + } + + /* diff --git a/queue-5.14/io-wq-fix-queue-stalling-race.patch b/queue-5.14/io-wq-fix-queue-stalling-race.patch new file mode 100644 index 00000000000..861343cff1a --- /dev/null +++ b/queue-5.14/io-wq-fix-queue-stalling-race.patch @@ -0,0 +1,70 @@ +From foo@baz Mon Nov 15 03:27:04 PM CET 2021 +From: Jens Axboe +Date: Tue, 31 Aug 2021 13:53:00 -0600 +Subject: io-wq: fix queue stalling race + +From: Jens Axboe + +commit 0242f6426ea78fbe3933b44f8c55ae93ec37f6cc upstream. + +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: Jens Axboe +Signed-off-by: Greg Kroah-Hartman +--- + fs/io-wq.c | 15 +++++++-------- + 1 file changed, 7 insertions(+), 8 deletions(-) + +--- a/fs/io-wq.c ++++ b/fs/io-wq.c +@@ -436,8 +436,7 @@ static bool io_worker_can_run_work(struc + } + + static struct io_wq_work *io_get_next_work(struct io_wqe *wqe, +- struct io_worker *worker, +- bool *stalled) ++ struct io_worker *worker) + __must_hold(wqe->lock) + { + struct io_wq_work_node *node, *prev; +@@ -475,10 +474,14 @@ static struct io_wq_work *io_get_next_wo + } + + 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); + io_wait_on_hash(wqe, stall_hash); + raw_spin_lock(&wqe->lock); +- *stalled = true; + } + + return NULL; +@@ -518,7 +521,6 @@ static void io_worker_handle_work(struct + + do { + struct io_wq_work *work; +- bool stalled; + get_next: + /* + * If we got some work, mark us as busy. If we didn't, but +@@ -527,12 +529,9 @@ get_next: + * can't make progress, any work completion or insertion will + * clear the stalled flag. + */ +- stalled = false; +- work = io_get_next_work(wqe, worker, &stalled); ++ work = io_get_next_work(wqe, worker); + if (work) + __io_worker_busy(wqe, worker, work); +- else if (stalled) +- wqe->flags |= IO_WQE_FLAG_STALLED; + + raw_spin_unlock_irq(&wqe->lock); + if (!work) diff --git a/queue-5.14/io-wq-serialize-hash-clear-with-wakeup.patch b/queue-5.14/io-wq-serialize-hash-clear-with-wakeup.patch new file mode 100644 index 00000000000..253eae6b966 --- /dev/null +++ b/queue-5.14/io-wq-serialize-hash-clear-with-wakeup.patch @@ -0,0 +1,90 @@ +From foo@baz Mon Nov 15 03:27:04 PM CET 2021 +From: Jens Axboe +Date: Sun, 14 Nov 2021 07:36:47 -0700 +Subject: io-wq: serialize hash clear with wakeup + +From: Jens Axboe + +commit d3e3c102d107bb84251455a298cf475f24bab995 upstream. + +We need to ensure that we serialize the stalled and hash bits with the +wait_queue wait handler, or we could be racing with someone modifying +the hashed state after we find it busy, but before we then give up and +wait for it to be cleared. This can cause random delays or stalls when +handling buffered writes for many files, where some of these files cause +hash collisions between the worker threads. + +Cc: stable@vger.kernel.org +Reported-by: Daniel Black +Fixes: e941894eae31 ("io-wq: make buffered file write hashed work map per-ctx") +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman +--- + fs/io-wq.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +--- a/fs/io-wq.c ++++ b/fs/io-wq.c +@@ -401,9 +401,10 @@ static inline unsigned int io_get_work_h + return work->flags >> IO_WQ_HASH_SHIFT; + } + +-static void io_wait_on_hash(struct io_wqe *wqe, unsigned int hash) ++static bool io_wait_on_hash(struct io_wqe *wqe, unsigned int hash) + { + struct io_wq *wq = wqe->wq; ++ bool ret = false; + + spin_lock_irq(&wq->hash->wait.lock); + if (list_empty(&wqe->wait.entry)) { +@@ -411,9 +412,11 @@ static void io_wait_on_hash(struct io_wq + if (!test_bit(hash, &wq->hash->map)) { + __set_current_state(TASK_RUNNING); + list_del_init(&wqe->wait.entry); ++ ret = true; + } + } + spin_unlock_irq(&wq->hash->wait.lock); ++ return ret; + } + + /* +@@ -474,14 +477,21 @@ static struct io_wq_work *io_get_next_wo + } + + if (stall_hash != -1U) { ++ bool unstalled; ++ + /* + * 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); +- io_wait_on_hash(wqe, stall_hash); ++ unstalled = io_wait_on_hash(wqe, stall_hash); + raw_spin_lock(&wqe->lock); ++ if (unstalled) { ++ wqe->flags &= ~IO_WQE_FLAG_STALLED; ++ if (wq_has_sleeper(&wqe->wq->hash->wait)) ++ wake_up(&wqe->wq->hash->wait); ++ } + } + + return NULL; +@@ -562,11 +572,14 @@ get_next: + io_wqe_enqueue(wqe, linked); + + if (hash != -1U && !next_hashed) { ++ /* serialize hash clear with wake_up() */ ++ spin_lock_irq(&wq->hash->wait.lock); + clear_bit(hash, &wq->hash->map); ++ wqe->flags &= ~IO_WQE_FLAG_STALLED; ++ spin_unlock_irq(&wq->hash->wait.lock); + if (wq_has_sleeper(&wq->hash->wait)) + wake_up(&wq->hash->wait); + raw_spin_lock_irq(&wqe->lock); +- wqe->flags &= ~IO_WQE_FLAG_STALLED; + /* skip unnecessary unlock-lock wqe->lock */ + if (!work) + goto get_next; diff --git a/queue-5.14/series b/queue-5.14/series index a1063bb77df..a4b2eefa266 100644 --- a/queue-5.14/series +++ b/queue-5.14/series @@ -808,3 +808,6 @@ bpf-cgroup-assign-cgroup-in-cgroup_sk_alloc-when-cal.patch 9p-net-fix-missing-error-check-in-p9_check_errors.patch mm-filemap.c-remove-bogus-vm_bug_on.patch memcg-prohibit-unconditional-exceeding-the-limit-of-dying-tasks.patch +io-wq-ensure-that-hash-wait-lock-is-irq-disabling.patch +io-wq-fix-queue-stalling-race.patch +io-wq-serialize-hash-clear-with-wakeup.patch