bcachefs: six locks: Fix lost wakeup
authorKent Overstreet <kent.overstreet@linux.dev>
Tue, 14 Nov 2023 23:52:22 +0000 (18:52 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Wed, 15 Nov 2023 04:44:44 +0000 (23:44 -0500)
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>
fs/bcachefs/six.c

index b775cf0fb7cbf211a3f388cf78de0de6f33c581c..97790445e67ad2923fc4a0413d2c824cf506455e 100644 (file)
@@ -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);