Skip to content

Instantly share code, notes, and snippets.

@heatd
Created April 20, 2024 21:51
Show Gist options
  • Save heatd/739d1775ec380d0247d63362ff8a3208 to your computer and use it in GitHub Desktop.
Save heatd/739d1775ec380d0247d63362ff8a3208 to your computer and use it in GitHub Desktop.
From 7fd3eae6b5b1872c683b4559865e9657a8196987 Mon Sep 17 00:00:00 2001
From: Pedro Falcato <pedro.falcato@gmail.com>
Date: Sat, 20 Apr 2024 22:48:16 +0100
Subject: [PATCH] mm: Re-set WAITERS after wakeup
Make sure WAITERS is set after wakeup. This avoids nasty races like:
T0 | T1 | T2
Wakes up because of WAITERS && !WRITEBACK | |
| Grab q lock | Waiting for q lock
| See waiters unset |
| Q clear, unset WAITERS |
| Release Q lock |
Start writeback (WRITEBACK=1) | |
| | Grab q lock
| | WRITEBACK = 1
| | back to sleep in the q, WAITERS = 0
Signed-off-by: Pedro Falcato <pedro.falcato@gmail.com>
---
kernel/kernel/mm/page.cpp | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/kernel/kernel/mm/page.cpp b/kernel/kernel/mm/page.cpp
index 33b6091a..5c76d1ad 100644
--- a/kernel/kernel/mm/page.cpp
+++ b/kernel/kernel/mm/page.cpp
@@ -232,6 +232,24 @@ int page_wait_bit(struct page *p, unsigned int bit, bool interruptible) NO_THREA
flags = spin_lock_irqsave(&wq->lock);
__wait_queue_remove(wq, &token);
set_current_state(state);
+ /* clang-format off */
+ /* Re-set WAITERS. WAITERS is serialized by the queue lock. This makes sure that we cannot
+ * have a case where we sleep and check_cond under the lock without it set, which can happen if e.g:
+ * T0 | T1 | T2
+ * Wakes up because of WAITERS && !WRITEBACK | |
+ * | Grab q lock | Waiting for q lock
+ * | See waiters unset |
+ * | Q clear, unset WAITERS |
+ * | Release Q lock |
+ * Start writeback (WRITEBACK=1) | |
+ * | | Grab q lock
+ * | | WRITEBACK = 1
+ * | | back to sleep in the q, WAITERS = 0
+ *
+ * In this case, T2 hangs. This can also happen for page locks and other bits.
+ */
+ /* clang-format on */
+ page_set_waiters(p);
// XXX: wait_queue_remove zeroes token.context. Why?
token.context = &winfo;
__wait_queue_add(wq, &token);
--
2.44.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment