]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.14-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 15 Nov 2021 14:27:33 +0000 (15:27 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 15 Nov 2021 14:27:33 +0000 (15:27 +0100)
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

queue-5.14/io-wq-ensure-that-hash-wait-lock-is-irq-disabling.patch [new file with mode: 0644]
queue-5.14/io-wq-fix-queue-stalling-race.patch [new file with mode: 0644]
queue-5.14/io-wq-serialize-hash-clear-with-wakeup.patch [new file with mode: 0644]
queue-5.14/series

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 (file)
index 0000000..406ee07
--- /dev/null
@@ -0,0 +1,43 @@
+From foo@baz Mon Nov 15 03:27:04 PM CET 2021
+From: Jens Axboe <axboe@kernel.dk>
+Date: Tue, 31 Aug 2021 06:57:25 -0600
+Subject: io-wq: ensure that hash wait lock is IRQ disabling
+
+From: Jens Axboe <axboe@kernel.dk>
+
+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 <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..861343c
--- /dev/null
@@ -0,0 +1,70 @@
+From foo@baz Mon Nov 15 03:27:04 PM CET 2021
+From: Jens Axboe <axboe@kernel.dk>
+Date: Tue, 31 Aug 2021 13:53:00 -0600
+Subject: io-wq: fix queue stalling race
+
+From: Jens Axboe <axboe@kernel.dk>
+
+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 <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..253eae6
--- /dev/null
@@ -0,0 +1,90 @@
+From foo@baz Mon Nov 15 03:27:04 PM CET 2021
+From: Jens Axboe <axboe@kernel.dk>
+Date: Sun, 14 Nov 2021 07:36:47 -0700
+Subject: io-wq: serialize hash clear with wakeup
+
+From: Jens Axboe <axboe@kernel.dk>
+
+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 <daniel@mariadb.org>
+Fixes: e941894eae31 ("io-wq: make buffered file write hashed work map per-ctx")
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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;
index a1063bb77dfa544570ec8434aec54a7f05b3dfef..a4b2eefa2660da6ba35169a83baa001940b2f7d2 100644 (file)
@@ -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