1 // SPDX-License-Identifier: GPL-2.0
4 #include "nocow_locking.h"
7 #include <linux/closure.h>
9 bool bch2_bucket_nocow_is_locked(struct bucket_nocow_lock_table *t, struct bpos bucket)
11 u64 dev_bucket = bucket_to_u64(bucket);
12 struct nocow_lock_bucket *l = bucket_nocow_lock(t, dev_bucket);
15 for (i = 0; i < ARRAY_SIZE(l->b); i++)
16 if (l->b[i] == dev_bucket && atomic_read(&l->l[i]))
21 #define sign(v) (v < 0 ? -1 : v > 0 ? 1 : 0)
23 void bch2_bucket_nocow_unlock(struct bucket_nocow_lock_table *t, struct bpos bucket, int flags)
25 u64 dev_bucket = bucket_to_u64(bucket);
26 struct nocow_lock_bucket *l = bucket_nocow_lock(t, dev_bucket);
27 int lock_val = flags ? 1 : -1;
30 for (i = 0; i < ARRAY_SIZE(l->b); i++)
31 if (l->b[i] == dev_bucket) {
32 BUG_ON(sign(atomic_read(&l->l[i])) != lock_val);
34 if (!atomic_sub_return(lock_val, &l->l[i]))
35 closure_wake_up(&l->wait);
42 bool __bch2_bucket_nocow_trylock(struct nocow_lock_bucket *l,
43 u64 dev_bucket, int flags)
45 int v, lock_val = flags ? 1 : -1;
50 for (i = 0; i < ARRAY_SIZE(l->b); i++)
51 if (l->b[i] == dev_bucket)
54 for (i = 0; i < ARRAY_SIZE(l->b); i++)
55 if (!atomic_read(&l->l[i])) {
60 spin_unlock(&l->lock);
63 v = atomic_read(&l->l[i]);
64 if (lock_val > 0 ? v < 0 : v > 0)
67 atomic_add(lock_val, &l->l[i]);
68 spin_unlock(&l->lock);
72 void __bch2_bucket_nocow_lock(struct bucket_nocow_lock_table *t,
73 struct nocow_lock_bucket *l,
74 u64 dev_bucket, int flags)
76 if (!__bch2_bucket_nocow_trylock(l, dev_bucket, flags)) {
77 struct bch_fs *c = container_of(t, struct bch_fs, nocow_locks);
78 u64 start_time = local_clock();
80 __closure_wait_event(&l->wait, __bch2_bucket_nocow_trylock(l, dev_bucket, flags));
81 bch2_time_stats_update(&c->times[BCH_TIME_nocow_lock_contended], start_time);
85 void bch2_nocow_locks_to_text(struct printbuf *out, struct bucket_nocow_lock_table *t)
87 unsigned i, nr_zero = 0;
88 struct nocow_lock_bucket *l;
90 for (l = t->l; l < t->l + ARRAY_SIZE(t->l); l++) {
93 for (i = 0; i < ARRAY_SIZE(l->l); i++)
94 v |= atomic_read(&l->l[i]);
102 prt_printf(out, "(%u empty entries)\n", nr_zero);
105 for (i = 0; i < ARRAY_SIZE(l->l); i++)
106 if (atomic_read(&l->l[i]))
107 prt_printf(out, "%llu: %i ", l->b[i], atomic_read(&l->l[i]));
112 prt_printf(out, "(%u empty entries)\n", nr_zero);
115 int bch2_fs_nocow_locking_init(struct bch_fs *c)
119 for (i = 0; i < ARRAY_SIZE(c->nocow_locks.l); i++)
120 spin_lock_init(&c->nocow_locks.l[i].lock);