summaryrefslogtreecommitdiff
path: root/fs/bcachefs/two_state_shared_lock.c
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@linux.dev>2022-11-04 20:25:57 +0300
committerKent Overstreet <kent.overstreet@linux.dev>2023-10-23 00:09:45 +0300
commita7ecd30c8300624448c4e66cd7a7e7209b96ea61 (patch)
treec282d706dbb238c2078f0d18f93f097d5f58f609 /fs/bcachefs/two_state_shared_lock.c
parenta1ee777bfcceeb916d837321144c782e12082588 (diff)
downloadlinux-a7ecd30c8300624448c4e66cd7a7e7209b96ea61.tar.xz
bcachefs: Factor out two_state_shared_lock
We have a unique lock used for controlling adding to the pagecache: the lock has two states, where both states are shared - the lock may be held multiple times for either state - but not both states at the same time. This is exactly what we need for nocow mode locking, so this patch pulls it out of fs.c into its own file. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Diffstat (limited to 'fs/bcachefs/two_state_shared_lock.c')
-rw-r--r--fs/bcachefs/two_state_shared_lock.c33
1 files changed, 33 insertions, 0 deletions
diff --git a/fs/bcachefs/two_state_shared_lock.c b/fs/bcachefs/two_state_shared_lock.c
new file mode 100644
index 000000000000..dc508d545de0
--- /dev/null
+++ b/fs/bcachefs/two_state_shared_lock.c
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "two_state_shared_lock.h"
+
+void bch2_two_state_unlock(two_state_lock_t *lock, int s)
+{
+ long i = s ? 1 : -1;
+
+ BUG_ON(atomic_long_read(&lock->v) == 0);
+
+ if (atomic_long_sub_return_release(i, &lock->v) == 0)
+ wake_up_all(&lock->wait);
+}
+
+bool bch2_two_state_trylock(two_state_lock_t *lock, int s)
+{
+ long i = s ? 1 : -1;
+ long v = atomic_long_read(&lock->v), old;
+
+ do {
+ old = v;
+
+ if (i > 0 ? v < 0 : v > 0)
+ return false;
+ } while ((v = atomic_long_cmpxchg_acquire(&lock->v,
+ old, old + i)) != old);
+ return true;
+}
+
+void bch2_two_state_lock(two_state_lock_t *lock, int s)
+{
+ wait_event(lock->wait, bch2_two_state_trylock(lock, s));
+}