summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Huang <mmpgouride@gmail.com>2024-08-27 18:14:48 +0300
committerKent Overstreet <kent.overstreet@linux.dev>2024-09-28 05:32:23 +0300
commite057a290ef715d2765560778625e1660b7352994 (patch)
treea4bad53c297e41293809b9b685de8bc2111c5a92
parentd50d7a5fa4df3190b6b6c6d6551b631fda4a4ed2 (diff)
downloadlinux-e057a290ef715d2765560778625e1660b7352994.tar.xz
bcachefs: Fix lost wake up
If the reader acquires the read lock and then the writer enters the slow path, while the reader proceeds to the unlock path, the following scenario can occur without the change: writer: pcpu_read_count(lock) return 1 (so __do_six_trylock will return 0) reader: this_cpu_dec(*lock->readers) reader: smp_mb() reader: state = atomic_read(&lock->state) (there is no waiting flag set) writer: six_set_bitmask() then the writer will sleep forever. Signed-off-by: Alan Huang <mmpgouride@gmail.com> Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r--fs/bcachefs/six.c12
1 files changed, 9 insertions, 3 deletions
diff --git a/fs/bcachefs/six.c b/fs/bcachefs/six.c
index 3a494c5d1247..b3583c50ef04 100644
--- a/fs/bcachefs/six.c
+++ b/fs/bcachefs/six.c
@@ -169,11 +169,17 @@ static int __do_six_trylock(struct six_lock *lock, enum six_lock_type type,
ret = -1 - SIX_LOCK_write;
}
} else if (type == SIX_LOCK_write && lock->readers) {
- if (try) {
+ if (try)
atomic_add(SIX_LOCK_HELD_write, &lock->state);
- smp_mb__after_atomic();
- }
+ /*
+ * Make sure atomic_add happens before pcpu_read_count and
+ * six_set_bitmask in slow path happens before pcpu_read_count.
+ *
+ * Paired with the smp_mb() in read lock fast path (per-cpu mode)
+ * and the one before atomic_read in read unlock path.
+ */
+ smp_mb();
ret = !pcpu_read_count(lock);
if (try && !ret) {