1 // SPDX-License-Identifier: GPL-2.0
4 #include "journal_sb.h"
6 #include <linux/sort.h>
8 /* BCH_SB_FIELD_journal: */
10 static int u64_cmp(const void *_l, const void *_r)
15 return cmp_int(*l, *r);
18 static int bch2_sb_journal_validate(struct bch_sb *sb,
19 struct bch_sb_field *f,
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;
29 nr = bch2_nr_journal_buckets(journal);
33 b = kmalloc_array(sizeof(u64), nr, GFP_KERNEL);
37 for (i = 0; i < nr; i++)
38 b[i] = le64_to_cpu(journal->buckets[i]);
40 sort(b, nr, sizeof(u64), u64_cmp, NULL);
43 pr_buf(err, "journal bucket at sector 0");
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));
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));
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]);
71 static void bch2_sb_journal_to_text(struct printbuf *out, struct bch_sb *sb,
72 struct bch_sb_field *f)
74 struct bch_sb_field_journal *journal = field_to_type(f, journal);
75 unsigned i, nr = bch2_nr_journal_buckets(journal);
77 pr_buf(out, "Buckets: ");
78 for (i = 0; i < nr; i++)
79 pr_buf(out, " %llu", le64_to_cpu(journal->buckets[i]));
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,
93 static int u64_range_cmp(const void *_l, const void *_r)
95 const struct u64_range *l = _l;
96 const struct u64_range *r = _r;
98 return cmp_int(l->start, r->start);
101 static int bch2_sb_journal_v2_validate(struct bch_sb *sb,
102 struct bch_sb_field *f,
103 struct printbuf *err)
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;
112 nr = bch2_sb_field_journal_v2_nr_entries(journal);
116 b = kmalloc_array(sizeof(*b), nr, GFP_KERNEL);
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);
125 sort(b, nr, sizeof(*b), u64_range_cmp, NULL);
128 pr_buf(err, "journal bucket at sector 0");
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));
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));
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);
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);
164 static void bch2_sb_journal_v2_to_text(struct printbuf *out, struct bch_sb *sb,
165 struct bch_sb_field *f)
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);
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));
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,
183 int bch2_journal_buckets_to_sb(struct bch_fs *c, struct bch_dev *ca)
185 struct journal_device *ja = &ca->journal;
186 struct bch_sb_field_journal_v2 *j;
187 unsigned i, dst = 0, nr = 1;
189 lockdep_assert_held(&c->sb_lock);
192 bch2_sb_field_delete(&ca->disk_sb, BCH_SB_FIELD_journal);
193 bch2_sb_field_delete(&ca->disk_sb, BCH_SB_FIELD_journal_v2);
197 for (i = 0; i + 1 < ja->nr; i++)
198 if (ja->buckets[i] + 1 != ja->buckets[i + 1])
201 j = bch2_sb_resize_journal_v2(&ca->disk_sb,
202 (sizeof(*j) + sizeof(j->d[0]) * nr) / sizeof(u64));
206 bch2_sb_field_delete(&ca->disk_sb, BCH_SB_FIELD_journal);
208 j->d[dst].start = le64_to_cpu(ja->buckets[0]);
209 j->d[dst].nr = le64_to_cpu(1);
211 for (i = 1; i < ja->nr; i++) {
212 if (ja->buckets[i] == ja->buckets[i - 1] + 1) {
213 le64_add_cpu(&j->d[dst].nr, 1);
216 j->d[dst].start = le64_to_cpu(ja->buckets[i]);
217 j->d[dst].nr = le64_to_cpu(1);