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