]> git.sesse.net Git - bcachefs-tools-debian/blob - libbcachefs/journal_sb.c
Update bcachefs sources to 91e6c3e0d5 bcachefs: Gap buffer for journal keys
[bcachefs-tools-debian] / libbcachefs / journal_sb.c
1 // SPDX-License-Identifier: GPL-2.0
2
3 #include "bcachefs.h"
4 #include "journal_sb.h"
5
6 #include <linux/sort.h>
7
8 /* BCH_SB_FIELD_journal: */
9
10 static int u64_cmp(const void *_l, const void *_r)
11 {
12         const u64 *l = _l;
13         const u64 *r = _r;
14
15         return cmp_int(*l, *r);
16 }
17
18 static int bch2_sb_journal_validate(struct bch_sb *sb,
19                                     struct bch_sb_field *f,
20                                     struct printbuf *err)
21 {
22         struct bch_sb_field_journal *journal = field_to_type(f, journal);
23         struct bch_member *m = bch2_sb_get_members(sb)->members + sb->dev_idx;
24         int ret = -EINVAL;
25         unsigned nr;
26         unsigned i;
27         u64 *b;
28
29         nr = bch2_nr_journal_buckets(journal);
30         if (!nr)
31                 return 0;
32
33         b = kmalloc_array(sizeof(u64), nr, GFP_KERNEL);
34         if (!b)
35                 return -ENOMEM;
36
37         for (i = 0; i < nr; i++)
38                 b[i] = le64_to_cpu(journal->buckets[i]);
39
40         sort(b, nr, sizeof(u64), u64_cmp, NULL);
41
42         if (!b[0]) {
43                 pr_buf(err, "journal bucket at sector 0");
44                 goto err;
45         }
46
47         if (b[0] < le16_to_cpu(m->first_bucket)) {
48                 pr_buf(err, "journal bucket %llu before first bucket %u",
49                        b[0], le16_to_cpu(m->first_bucket));
50                 goto err;
51         }
52
53         if (b[nr - 1] >= le64_to_cpu(m->nbuckets)) {
54                 pr_buf(err, "journal bucket %llu past end of device (nbuckets %llu)",
55                        b[nr - 1], le64_to_cpu(m->nbuckets));
56                 goto err;
57         }
58
59         for (i = 0; i + 1 < nr; i++)
60                 if (b[i] == b[i + 1]) {
61                         pr_buf(err, "duplicate journal buckets %llu", b[i]);
62                         goto err;
63                 }
64
65         ret = 0;
66 err:
67         kfree(b);
68         return ret;
69 }
70
71 static void bch2_sb_journal_to_text(struct printbuf *out, struct bch_sb *sb,
72                                     struct bch_sb_field *f)
73 {
74         struct bch_sb_field_journal *journal = field_to_type(f, journal);
75         unsigned i, nr = bch2_nr_journal_buckets(journal);
76
77         pr_buf(out, "Buckets: ");
78         for (i = 0; i < nr; i++)
79                 pr_buf(out, " %llu", le64_to_cpu(journal->buckets[i]));
80         pr_newline(out);
81 }
82
83 const struct bch_sb_field_ops bch_sb_field_ops_journal = {
84         .validate       = bch2_sb_journal_validate,
85         .to_text        = bch2_sb_journal_to_text,
86 };
87
88 struct u64_range {
89         u64     start;
90         u64     end;
91 };
92
93 static int u64_range_cmp(const void *_l, const void *_r)
94 {
95         const struct u64_range *l = _l;
96         const struct u64_range *r = _r;
97
98         return cmp_int(l->start, r->start);
99 }
100
101 static int bch2_sb_journal_v2_validate(struct bch_sb *sb,
102                                     struct bch_sb_field *f,
103                                     struct printbuf *err)
104 {
105         struct bch_sb_field_journal_v2 *journal = field_to_type(f, journal_v2);
106         struct bch_member *m = bch2_sb_get_members(sb)->members + sb->dev_idx;
107         int ret = -EINVAL;
108         unsigned nr;
109         unsigned i;
110         struct u64_range *b;
111
112         nr = bch2_sb_field_journal_v2_nr_entries(journal);
113         if (!nr)
114                 return 0;
115
116         b = kmalloc_array(sizeof(*b), nr, GFP_KERNEL);
117         if (!b)
118                 return -ENOMEM;
119
120         for (i = 0; i < nr; i++) {
121                 b[i].start = le64_to_cpu(journal->d[i].start);
122                 b[i].end = b[i].start + le64_to_cpu(journal->d[i].nr);
123         }
124
125         sort(b, nr, sizeof(*b), u64_range_cmp, NULL);
126
127         if (!b[0].start) {
128                 pr_buf(err, "journal bucket at sector 0");
129                 goto err;
130         }
131
132         if (b[0].start < le16_to_cpu(m->first_bucket)) {
133                 pr_buf(err, "journal bucket %llu before first bucket %u",
134                        b[0].start, le16_to_cpu(m->first_bucket));
135                 goto err;
136         }
137
138         if (b[nr - 1].end > le64_to_cpu(m->nbuckets)) {
139                 pr_buf(err, "journal bucket %llu past end of device (nbuckets %llu)",
140                        b[nr - 1].end - 1, le64_to_cpu(m->nbuckets));
141                 goto err;
142         }
143
144         for (i = 0; i + 1 < nr; i++) {
145                 if (b[i].end == b[i + 1].start) {
146                         pr_buf(err, "contiguous journal buckets ranges %llu-%llu, %llu-%llu",
147                                b[i].start, b[i].end, b[i + 1].start, b[i + 1].end);
148                         goto err;
149                 }
150
151                 if (b[i].end > b[i + 1].start) {
152                         pr_buf(err, "duplicate journal buckets in ranges %llu-%llu, %llu-%llu",
153                                b[i].start, b[i].end, b[i + 1].start, b[i + 1].end);
154                         goto err;
155                 }
156         }
157
158         ret = 0;
159 err:
160         kfree(b);
161         return ret;
162 }
163
164 static void bch2_sb_journal_v2_to_text(struct printbuf *out, struct bch_sb *sb,
165                                     struct bch_sb_field *f)
166 {
167         struct bch_sb_field_journal_v2 *journal = field_to_type(f, journal_v2);
168         unsigned i, nr = bch2_sb_field_journal_v2_nr_entries(journal);
169
170         pr_buf(out, "Buckets: ");
171         for (i = 0; i < nr; i++)
172                 pr_buf(out, " %llu-%llu",
173                        le64_to_cpu(journal->d[i].start),
174                        le64_to_cpu(journal->d[i].start) + le64_to_cpu(journal->d[i].nr));
175         pr_newline(out);
176 }
177
178 const struct bch_sb_field_ops bch_sb_field_ops_journal_v2 = {
179         .validate       = bch2_sb_journal_v2_validate,
180         .to_text        = bch2_sb_journal_v2_to_text,
181 };
182
183 int bch2_journal_buckets_to_sb(struct bch_fs *c, struct bch_dev *ca)
184 {
185         struct journal_device *ja = &ca->journal;
186         struct bch_sb_field_journal_v2 *j;
187         unsigned i, dst = 0, nr = 1;
188
189         if (c)
190                 lockdep_assert_held(&c->sb_lock);
191
192         if (!ja->nr) {
193                 bch2_sb_field_delete(&ca->disk_sb, BCH_SB_FIELD_journal);
194                 bch2_sb_field_delete(&ca->disk_sb, BCH_SB_FIELD_journal_v2);
195                 return 0;
196         }
197
198         for (i = 0; i + 1 < ja->nr; i++)
199                 if (ja->buckets[i] + 1 != ja->buckets[i + 1])
200                         nr++;
201
202         j = bch2_sb_resize_journal_v2(&ca->disk_sb,
203                                  (sizeof(*j) + sizeof(j->d[0]) * nr) / sizeof(u64));
204         if (!j)
205                 return -ENOSPC;
206
207         bch2_sb_field_delete(&ca->disk_sb, BCH_SB_FIELD_journal);
208
209         j->d[dst].start = le64_to_cpu(ja->buckets[0]);
210         j->d[dst].nr    = le64_to_cpu(1);
211
212         for (i = 1; i < ja->nr; i++) {
213                 if (ja->buckets[i] == ja->buckets[i - 1] + 1) {
214                         le64_add_cpu(&j->d[dst].nr, 1);
215                 } else {
216                         dst++;
217                         j->d[dst].start = le64_to_cpu(ja->buckets[i]);
218                         j->d[dst].nr    = le64_to_cpu(1);
219                 }
220         }
221
222         return 0;
223 }