]> git.ipfire.org Git - thirdparty/linux.git/blame - fs/bcachefs/journal_sb.c
bcachefs: Add new helper to retrieve bch_member from sb
[thirdparty/linux.git] / fs / bcachefs / journal_sb.c
CommitLineData
25be2e5d
KO
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
11static 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
19static 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);
1241df58 24 struct bch_member m = bch2_sb_member_get(sb, sb->dev_idx);
78c0b75c 25 int ret = -BCH_ERR_invalid_sb_journal;
25be2e5d
KO
26 unsigned nr;
27 unsigned i;
28 u64 *b;
29
30 nr = bch2_nr_journal_buckets(journal);
31 if (!nr)
32 return 0;
33
3e3e02e6 34 b = kmalloc_array(nr, sizeof(u64), GFP_KERNEL);
25be2e5d 35 if (!b)
65d48e35 36 return -BCH_ERR_ENOMEM_sb_journal_validate;
25be2e5d
KO
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]) {
401ec4db 44 prt_printf(err, "journal bucket at sector 0");
25be2e5d
KO
45 goto err;
46 }
47
1241df58 48 if (b[0] < le16_to_cpu(m.first_bucket)) {
401ec4db 49 prt_printf(err, "journal bucket %llu before first bucket %u",
1241df58 50 b[0], le16_to_cpu(m.first_bucket));
25be2e5d
KO
51 goto err;
52 }
53
1241df58 54 if (b[nr - 1] >= le64_to_cpu(m.nbuckets)) {
401ec4db 55 prt_printf(err, "journal bucket %llu past end of device (nbuckets %llu)",
1241df58 56 b[nr - 1], le64_to_cpu(m.nbuckets));
25be2e5d
KO
57 goto err;
58 }
59
60 for (i = 0; i + 1 < nr; i++)
61 if (b[i] == b[i + 1]) {
401ec4db 62 prt_printf(err, "duplicate journal buckets %llu", b[i]);
25be2e5d
KO
63 goto err;
64 }
65
66 ret = 0;
67err:
68 kfree(b);
69 return ret;
70}
71
72static 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
401ec4db 78 prt_printf(out, "Buckets: ");
25be2e5d 79 for (i = 0; i < nr; i++)
401ec4db
KO
80 prt_printf(out, " %llu", le64_to_cpu(journal->buckets[i]));
81 prt_newline(out);
25be2e5d
KO
82}
83
84const 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
89struct u64_range {
90 u64 start;
91 u64 end;
92};
93
94static 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
102static 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);
1241df58 107 struct bch_member m = bch2_sb_member_get(sb, sb->dev_idx);
78c0b75c 108 int ret = -BCH_ERR_invalid_sb_journal;
25be2e5d
KO
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
3e3e02e6 117 b = kmalloc_array(nr, sizeof(*b), GFP_KERNEL);
25be2e5d 118 if (!b)
65d48e35 119 return -BCH_ERR_ENOMEM_sb_journal_v2_validate;
25be2e5d
KO
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) {
401ec4db 129 prt_printf(err, "journal bucket at sector 0");
25be2e5d
KO
130 goto err;
131 }
132
1241df58 133 if (b[0].start < le16_to_cpu(m.first_bucket)) {
401ec4db 134 prt_printf(err, "journal bucket %llu before first bucket %u",
1241df58 135 b[0].start, le16_to_cpu(m.first_bucket));
25be2e5d
KO
136 goto err;
137 }
138
1241df58 139 if (b[nr - 1].end > le64_to_cpu(m.nbuckets)) {
401ec4db 140 prt_printf(err, "journal bucket %llu past end of device (nbuckets %llu)",
1241df58 141 b[nr - 1].end - 1, le64_to_cpu(m.nbuckets));
25be2e5d
KO
142 goto err;
143 }
144
145 for (i = 0; i + 1 < nr; i++) {
146 if (b[i].end > b[i + 1].start) {
401ec4db 147 prt_printf(err, "duplicate journal buckets in ranges %llu-%llu, %llu-%llu",
25be2e5d
KO
148 b[i].start, b[i].end, b[i + 1].start, b[i + 1].end);
149 goto err;
150 }
151 }
152
153 ret = 0;
154err:
155 kfree(b);
156 return ret;
157}
158
159static 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
401ec4db 165 prt_printf(out, "Buckets: ");
25be2e5d 166 for (i = 0; i < nr; i++)
401ec4db 167 prt_printf(out, " %llu-%llu",
25be2e5d
KO
168 le64_to_cpu(journal->d[i].start),
169 le64_to_cpu(journal->d[i].start) + le64_to_cpu(journal->d[i].nr));
401ec4db 170 prt_newline(out);
25be2e5d
KO
171}
172
173const 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
2640faeb
KO
178int bch2_journal_buckets_to_sb(struct bch_fs *c, struct bch_dev *ca,
179 u64 *buckets, unsigned nr)
25be2e5d 180{
25be2e5d 181 struct bch_sb_field_journal_v2 *j;
2640faeb 182 unsigned i, dst = 0, nr_compacted = 1;
25be2e5d
KO
183
184 if (c)
185 lockdep_assert_held(&c->sb_lock);
186
2640faeb 187 if (!nr) {
25be2e5d
KO
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
2640faeb
KO
193 for (i = 0; i + 1 < nr; i++)
194 if (buckets[i] + 1 != buckets[i + 1])
195 nr_compacted++;
25be2e5d
KO
196
197 j = bch2_sb_resize_journal_v2(&ca->disk_sb,
2640faeb 198 (sizeof(*j) + sizeof(j->d[0]) * nr_compacted) / sizeof(u64));
25be2e5d 199 if (!j)
098ef98d 200 return -BCH_ERR_ENOSPC_sb_journal;
25be2e5d
KO
201
202 bch2_sb_field_delete(&ca->disk_sb, BCH_SB_FIELD_journal);
203
73bd774d
KO
204 j->d[dst].start = cpu_to_le64(buckets[0]);
205 j->d[dst].nr = cpu_to_le64(1);
25be2e5d 206
2640faeb
KO
207 for (i = 1; i < nr; i++) {
208 if (buckets[i] == buckets[i - 1] + 1) {
25be2e5d
KO
209 le64_add_cpu(&j->d[dst].nr, 1);
210 } else {
211 dst++;
73bd774d
KO
212 j->d[dst].start = cpu_to_le64(buckets[i]);
213 j->d[dst].nr = cpu_to_le64(1);
25be2e5d
KO
214 }
215 }
216
2640faeb 217 BUG_ON(dst + 1 != nr_compacted);
25be2e5d
KO
218 return 0;
219}