aboutsummaryrefslogtreecommitdiff
path: root/fs/bcachefs/six.c
diff options
context:
space:
mode:
authorGravatar Kent Overstreet <kent.overstreet@linux.dev> 2022-10-15 00:34:38 -0400
committerGravatar Kent Overstreet <kent.overstreet@linux.dev> 2023-10-22 17:09:41 -0400
commite4b7254c754b676a6f4d607fd92cd71d221ff130 (patch)
treefb1316ac3a0b89173514151e27580cd823366c38 /fs/bcachefs/six.c
parentsix locks: Enable lockdep (diff)
downloadlinux-e4b7254c754b676a6f4d607fd92cd71d221ff130.tar.gz
linux-e4b7254c754b676a6f4d607fd92cd71d221ff130.tar.bz2
linux-e4b7254c754b676a6f4d607fd92cd71d221ff130.zip
six locks: Fix a lost wakeup
There was a lost wakeup between a read unlock in percpu mode and a write lock. The unlock path unlocks, then executes a barrier, then checks for waiters; correspondingly, the lock side should set the wait bit and execute a barrier, then attempt to take the lock. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Diffstat (limited to 'fs/bcachefs/six.c')
-rw-r--r--fs/bcachefs/six.c11
1 files changed, 8 insertions, 3 deletions
diff --git a/fs/bcachefs/six.c b/fs/bcachefs/six.c
index 01ff210ff18c..abdc2414f58b 100644
--- a/fs/bcachefs/six.c
+++ b/fs/bcachefs/six.c
@@ -198,6 +198,14 @@ retry:
atomic64_add(__SIX_VAL(write_locking, 1),
&lock->state.counter);
smp_mb__after_atomic();
+ } else if (!(lock->state.waiters & (1 << SIX_LOCK_write))) {
+ atomic64_add(__SIX_VAL(waiters, 1 << SIX_LOCK_write),
+ &lock->state.counter);
+ /*
+ * pairs with barrier after unlock and before checking
+ * for readers in unlock path
+ */
+ smp_mb__after_atomic();
}
ret = !pcpu_read_count(lock);
@@ -212,9 +220,6 @@ retry:
if (ret || try)
v -= __SIX_VAL(write_locking, 1);
- if (!ret && !try && !(lock->state.waiters & (1 << SIX_LOCK_write)))
- v += __SIX_VAL(waiters, 1 << SIX_LOCK_write);
-
if (try && !ret) {
old.v = atomic64_add_return(v, &lock->state.counter);
six_lock_wakeup(lock, old, SIX_LOCK_read);