]> git.sesse.net Git - bcachefs-tools-debian/blob - libbcachefs/nocow_locking.c
Merge https://github.com/fougner/bcachefs-tools
[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 void bch2_bucket_nocow_unlock(struct bucket_nocow_lock_table *t, struct bpos bucket, int flags)
22 {
23         u64 dev_bucket = bucket_to_u64(bucket);
24         struct nocow_lock_bucket *l = bucket_nocow_lock(t, dev_bucket);
25         int lock_val = flags ? 1 : -1;
26         unsigned i;
27
28         for (i = 0; i < ARRAY_SIZE(l->b); i++)
29                 if (l->b[i] == dev_bucket) {
30                         if (!atomic_sub_return(lock_val, &l->l[i]))
31                                 closure_wake_up(&l->wait);
32                         return;
33                 }
34
35         BUG();
36 }
37
38 static bool bch2_bucket_nocow_trylock(struct nocow_lock_bucket *l,
39                                       u64 dev_bucket, int flags)
40 {
41         int v, lock_val = flags ? 1 : -1;
42         unsigned i;
43
44         spin_lock(&l->lock);
45
46         for (i = 0; i < ARRAY_SIZE(l->b); i++)
47                 if (l->b[i] == dev_bucket)
48                         goto got_entry;
49
50         for (i = 0; i < ARRAY_SIZE(l->b); i++)
51                 if (!atomic_read(&l->l[i])) {
52                         l->b[i] = dev_bucket;
53                         goto take_lock;
54                 }
55 fail:
56         spin_unlock(&l->lock);
57         return false;
58 got_entry:
59         v = atomic_read(&l->l[i]);
60         if (lock_val > 0 ? v < 0 : v > 0)
61                 goto fail;
62 take_lock:
63         atomic_add(lock_val, &l->l[i]);
64         spin_unlock(&l->lock);
65         return true;
66 }
67
68 void __bch2_bucket_nocow_lock(struct bucket_nocow_lock_table *t,
69                               struct nocow_lock_bucket *l,
70                               u64 dev_bucket, int flags)
71 {
72         if (!bch2_bucket_nocow_trylock(l, dev_bucket, flags)) {
73                 struct bch_fs *c = container_of(t, struct bch_fs, nocow_locks);
74                 u64 start_time = local_clock();
75
76                 __closure_wait_event(&l->wait, bch2_bucket_nocow_trylock(l, dev_bucket, flags));
77                 bch2_time_stats_update(&c->times[BCH_TIME_nocow_lock_contended], start_time);
78         }
79 }
80
81 void bch2_nocow_locks_to_text(struct printbuf *out, struct bucket_nocow_lock_table *t)
82 {
83         unsigned i, nr_zero = 0;
84         struct nocow_lock_bucket *l;
85
86         for (l = t->l; l < t->l + ARRAY_SIZE(t->l); l++) {
87                 unsigned v = 0;
88
89                 for (i = 0; i < ARRAY_SIZE(l->l); i++)
90                         v |= atomic_read(&l->l[i]);
91
92                 if (!v) {
93                         nr_zero++;
94                         continue;
95                 }
96
97                 if (nr_zero)
98                         prt_printf(out, "(%u empty entries)\n", nr_zero);
99                 nr_zero = 0;
100
101                 for (i = 0; i < ARRAY_SIZE(l->l); i++)
102                         if (atomic_read(&l->l[i]))
103                                 prt_printf(out, "%llu: %i ", l->b[i], atomic_read(&l->l[i]));
104                 prt_newline(out);
105         }
106
107         if (nr_zero)
108                 prt_printf(out, "(%u empty entries)\n", nr_zero);
109 }
110
111 int bch2_fs_nocow_locking_init(struct bch_fs *c)
112 {
113         unsigned i;
114
115         for (i = 0; i < ARRAY_SIZE(c->nocow_locks.l); i++)
116                 spin_lock_init(&c->nocow_locks.l[i].lock);
117
118         return 0;
119 }