]> git.sesse.net Git - bcachefs-tools-debian/blob - libbcachefs/nocow_locking.c
Update bcachefs sources to fd381c355c bcachefs: Fix a null ptr deref in fsck check_ex...
[bcachefs-tools-debian] / libbcachefs / nocow_locking.c
1 // SPDX-License-Identifier: GPL-2.0
2
3 #include "bcachefs.h"
4 #include "nocow_locking.h"
5 #include "util.h"
6
7 #include <linux/closure.h>
8
9 bool bch2_bucket_nocow_is_locked(struct bucket_nocow_lock_table *t, struct bpos bucket)
10 {
11         u64 dev_bucket = bucket_to_u64(bucket);
12         struct nocow_lock_bucket *l = bucket_nocow_lock(t, dev_bucket);
13         unsigned i;
14
15         for (i = 0; i < ARRAY_SIZE(l->b); i++)
16                 if (l->b[i] == dev_bucket && atomic_read(&l->l[i]))
17                         return true;
18         return false;
19 }
20
21 #define sign(v)         (v < 0 ? -1 : v > 0 ? 1 : 0)
22
23 void bch2_bucket_nocow_unlock(struct bucket_nocow_lock_table *t, struct bpos bucket, int flags)
24 {
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;
28         unsigned i;
29
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);
33
34                         if (!atomic_sub_return(lock_val, &l->l[i]))
35                                 closure_wake_up(&l->wait);
36                         return;
37                 }
38
39         BUG();
40 }
41
42 bool __bch2_bucket_nocow_trylock(struct nocow_lock_bucket *l,
43                                  u64 dev_bucket, int flags)
44 {
45         int v, lock_val = flags ? 1 : -1;
46         unsigned i;
47
48         spin_lock(&l->lock);
49
50         for (i = 0; i < ARRAY_SIZE(l->b); i++)
51                 if (l->b[i] == dev_bucket)
52                         goto got_entry;
53
54         for (i = 0; i < ARRAY_SIZE(l->b); i++)
55                 if (!atomic_read(&l->l[i])) {
56                         l->b[i] = dev_bucket;
57                         goto take_lock;
58                 }
59 fail:
60         spin_unlock(&l->lock);
61         return false;
62 got_entry:
63         v = atomic_read(&l->l[i]);
64         if (lock_val > 0 ? v < 0 : v > 0)
65                 goto fail;
66 take_lock:
67         atomic_add(lock_val, &l->l[i]);
68         spin_unlock(&l->lock);
69         return true;
70 }
71
72 void __bch2_bucket_nocow_lock(struct bucket_nocow_lock_table *t,
73                               struct nocow_lock_bucket *l,
74                               u64 dev_bucket, int flags)
75 {
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();
79
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);
82         }
83 }
84
85 void bch2_nocow_locks_to_text(struct printbuf *out, struct bucket_nocow_lock_table *t)
86 {
87         unsigned i, nr_zero = 0;
88         struct nocow_lock_bucket *l;
89
90         for (l = t->l; l < t->l + ARRAY_SIZE(t->l); l++) {
91                 unsigned v = 0;
92
93                 for (i = 0; i < ARRAY_SIZE(l->l); i++)
94                         v |= atomic_read(&l->l[i]);
95
96                 if (!v) {
97                         nr_zero++;
98                         continue;
99                 }
100
101                 if (nr_zero)
102                         prt_printf(out, "(%u empty entries)\n", nr_zero);
103                 nr_zero = 0;
104
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]));
108                 prt_newline(out);
109         }
110
111         if (nr_zero)
112                 prt_printf(out, "(%u empty entries)\n", nr_zero);
113 }
114
115 int bch2_fs_nocow_locking_init(struct bch_fs *c)
116 {
117         unsigned i;
118
119         for (i = 0; i < ARRAY_SIZE(c->nocow_locks.l); i++)
120                 spin_lock_init(&c->nocow_locks.l[i].lock);
121
122         return 0;
123 }