aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@linux.dev>2023-11-14 18:52:22 -0500
committerKent Overstreet <kent.overstreet@linux.dev>2023-11-14 23:44:44 -0500
commit61b85cb0d773115d9a4b20c3e67286844cf73f34 (patch)
treef7d611b4c3442a847f3461aaa895cafeca113946
parent62d73dfc44d54c97e0df6b947f0bccf6c4b8030e (diff)
downloadqueue-61b85cb0d773115d9a4b20c3e67286844cf73f34.tar.gz
bcachefs: six locks: Fix lost wakeup
In percpu reader mode, trylock() for read had a lost wakeup: on failure to get the lock, we may have caused a writer to fail to get the lock, because we temporarily elevated the reader count. We need to check for waiters after decrementing the read count - not before. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r--fs/bcachefs/six.c7
1 files changed, 5 insertions, 2 deletions
diff --git a/fs/bcachefs/six.c b/fs/bcachefs/six.c
index b775cf0fb7cbf2..97790445e67ad2 100644
--- a/fs/bcachefs/six.c
+++ b/fs/bcachefs/six.c
@@ -163,8 +163,11 @@ static int __do_six_trylock(struct six_lock *lock, enum six_lock_type type,
this_cpu_sub(*lock->readers, !ret);
preempt_enable();
- if (!ret && (old & SIX_LOCK_WAITING_write))
- ret = -1 - SIX_LOCK_write;
+ if (!ret) {
+ smp_mb();
+ if (atomic_read(&lock->state) & SIX_LOCK_WAITING_write)
+ ret = -1 - SIX_LOCK_write;
+ }
} else if (type == SIX_LOCK_write && lock->readers) {
if (try) {
atomic_add(SIX_LOCK_HELD_write, &lock->state);