]> Git Repo - linux.git/blob - fs/bcachefs/journal_sb.c
cifs: Add a tracepoint to track credits involved in R/W requests
[linux.git] / fs / bcachefs / 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, struct bch_sb_field *f,
20                                 enum bch_validate_flags flags, struct printbuf *err)
21 {
22         struct bch_sb_field_journal *journal = field_to_type(f, journal);
23         struct bch_member m = bch2_sb_member_get(sb, sb->dev_idx);
24         int ret = -BCH_ERR_invalid_sb_journal;
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(nr, sizeof(u64), GFP_KERNEL);
34         if (!b)
35                 return -BCH_ERR_ENOMEM_sb_journal_validate;
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                 prt_printf(err, "journal bucket at sector 0");
44                 goto err;
45         }
46
47         if (b[0] < le16_to_cpu(m.first_bucket)) {
48                 prt_printf(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                 prt_printf(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                         prt_printf(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         prt_printf(out, "Buckets: ");
78         for (i = 0; i < nr; i++)
79                 prt_printf(out, " %llu", le64_to_cpu(journal->buckets[i]));
80         prt_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, struct bch_sb_field *f,
102                                 enum bch_validate_flags flags, struct printbuf *err)
103 {
104         struct bch_sb_field_journal_v2 *journal = field_to_type(f, journal_v2);
105         struct bch_member m = bch2_sb_member_get(sb, sb->dev_idx);
106         int ret = -BCH_ERR_invalid_sb_journal;
107         unsigned nr;
108         unsigned i;
109         struct u64_range *b;
110
111         nr = bch2_sb_field_journal_v2_nr_entries(journal);
112         if (!nr)
113                 return 0;
114
115         b = kmalloc_array(nr, sizeof(*b), GFP_KERNEL);
116         if (!b)
117                 return -BCH_ERR_ENOMEM_sb_journal_v2_validate;
118
119         for (i = 0; i < nr; i++) {
120                 b[i].start = le64_to_cpu(journal->d[i].start);
121                 b[i].end = b[i].start + le64_to_cpu(journal->d[i].nr);
122         }
123
124         sort(b, nr, sizeof(*b), u64_range_cmp, NULL);
125
126         if (!b[0].start) {
127                 prt_printf(err, "journal bucket at sector 0");
128                 goto err;
129         }
130
131         if (b[0].start < le16_to_cpu(m.first_bucket)) {
132                 prt_printf(err, "journal bucket %llu before first bucket %u",
133                        b[0].start, le16_to_cpu(m.first_bucket));
134                 goto err;
135         }
136
137         if (b[nr - 1].end > le64_to_cpu(m.nbuckets)) {
138                 prt_printf(err, "journal bucket %llu past end of device (nbuckets %llu)",
139                        b[nr - 1].end - 1, le64_to_cpu(m.nbuckets));
140                 goto err;
141         }
142
143         for (i = 0; i + 1 < nr; i++) {
144                 if (b[i].end > b[i + 1].start) {
145                         prt_printf(err, "duplicate journal buckets in ranges %llu-%llu, %llu-%llu",
146                                b[i].start, b[i].end, b[i + 1].start, b[i + 1].end);
147                         goto err;
148                 }
149         }
150
151         ret = 0;
152 err:
153         kfree(b);
154         return ret;
155 }
156
157 static void bch2_sb_journal_v2_to_text(struct printbuf *out, struct bch_sb *sb,
158                                     struct bch_sb_field *f)
159 {
160         struct bch_sb_field_journal_v2 *journal = field_to_type(f, journal_v2);
161         unsigned i, nr = bch2_sb_field_journal_v2_nr_entries(journal);
162
163         prt_printf(out, "Buckets: ");
164         for (i = 0; i < nr; i++)
165                 prt_printf(out, " %llu-%llu",
166                        le64_to_cpu(journal->d[i].start),
167                        le64_to_cpu(journal->d[i].start) + le64_to_cpu(journal->d[i].nr));
168         prt_newline(out);
169 }
170
171 const struct bch_sb_field_ops bch_sb_field_ops_journal_v2 = {
172         .validate       = bch2_sb_journal_v2_validate,
173         .to_text        = bch2_sb_journal_v2_to_text,
174 };
175
176 int bch2_journal_buckets_to_sb(struct bch_fs *c, struct bch_dev *ca,
177                                u64 *buckets, unsigned nr)
178 {
179         struct bch_sb_field_journal_v2 *j;
180         unsigned i, dst = 0, nr_compacted = 1;
181
182         if (c)
183                 lockdep_assert_held(&c->sb_lock);
184
185         if (!nr) {
186                 bch2_sb_field_delete(&ca->disk_sb, BCH_SB_FIELD_journal);
187                 bch2_sb_field_delete(&ca->disk_sb, BCH_SB_FIELD_journal_v2);
188                 return 0;
189         }
190
191         for (i = 0; i + 1 < nr; i++)
192                 if (buckets[i] + 1 != buckets[i + 1])
193                         nr_compacted++;
194
195         j = bch2_sb_field_resize(&ca->disk_sb, journal_v2,
196                          (sizeof(*j) + sizeof(j->d[0]) * nr_compacted) / sizeof(u64));
197         if (!j)
198                 return -BCH_ERR_ENOSPC_sb_journal;
199
200         bch2_sb_field_delete(&ca->disk_sb, BCH_SB_FIELD_journal);
201
202         j->d[dst].start = cpu_to_le64(buckets[0]);
203         j->d[dst].nr    = cpu_to_le64(1);
204
205         for (i = 1; i < nr; i++) {
206                 if (buckets[i] == buckets[i - 1] + 1) {
207                         le64_add_cpu(&j->d[dst].nr, 1);
208                 } else {
209                         dst++;
210                         j->d[dst].start = cpu_to_le64(buckets[i]);
211                         j->d[dst].nr    = cpu_to_le64(1);
212                 }
213         }
214
215         BUG_ON(dst + 1 != nr_compacted);
216         return 0;
217 }
This page took 0.045067 seconds and 4 git commands to generate.