]> git.sesse.net Git - bcachefs-tools-debian/blob - libbcachefs/sb-members.c
032fe45481d3d088ecd2e13dee5f1c9e91fbef1c
[bcachefs-tools-debian] / libbcachefs / sb-members.c
1 // SPDX-License-Identifier: GPL-2.0
2
3 #include "bcachefs.h"
4 #include "disk_groups.h"
5 #include "opts.h"
6 #include "replicas.h"
7 #include "sb-members.h"
8 #include "super-io.h"
9
10 #define x(t, n, ...) [n] = #t,
11 static const char * const bch2_iops_measurements[] = {
12         BCH_IOPS_MEASUREMENTS()
13         NULL
14 };
15
16 char * const bch2_member_error_strs[] = {
17         BCH_MEMBER_ERROR_TYPES()
18         NULL
19 };
20 #undef x
21
22 /* Code for bch_sb_field_members_v1: */
23
24 static struct bch_member *members_v2_get_mut(struct bch_sb_field_members_v2 *mi, int i)
25 {
26         return (void *) mi->_members + (i * le16_to_cpu(mi->member_bytes));
27 }
28
29 struct bch_member *bch2_members_v2_get_mut(struct bch_sb *sb, int i)
30 {
31         return members_v2_get_mut(bch2_sb_field_get(sb, members_v2), i);
32 }
33
34 static struct bch_member members_v2_get(struct bch_sb_field_members_v2 *mi, int i)
35 {
36         struct bch_member ret, *p = members_v2_get_mut(mi, i);
37         memset(&ret, 0, sizeof(ret));
38         memcpy(&ret, p, min_t(size_t, le16_to_cpu(mi->member_bytes), sizeof(ret)));
39         return ret;
40 }
41
42 static struct bch_member *members_v1_get_mut(struct bch_sb_field_members_v1 *mi, int i)
43 {
44         return (void *) mi->_members + (i * BCH_MEMBER_V1_BYTES);
45 }
46
47 static struct bch_member members_v1_get(struct bch_sb_field_members_v1 *mi, int i)
48 {
49         struct bch_member ret, *p = members_v1_get_mut(mi, i);
50         memset(&ret, 0, sizeof(ret));
51         memcpy(&ret, p, min_t(size_t, BCH_MEMBER_V1_BYTES, sizeof(ret)));
52         return ret;
53 }
54
55 struct bch_member bch2_sb_member_get(struct bch_sb *sb, int i)
56 {
57         struct bch_sb_field_members_v2 *mi2 = bch2_sb_field_get(sb, members_v2);
58         if (mi2)
59                 return members_v2_get(mi2, i);
60         struct bch_sb_field_members_v1 *mi1 = bch2_sb_field_get(sb, members_v1);
61         return members_v1_get(mi1, i);
62 }
63
64 static int sb_members_v2_resize_entries(struct bch_fs *c)
65 {
66         struct bch_sb_field_members_v2 *mi = bch2_sb_field_get(c->disk_sb.sb, members_v2);
67
68         if (le16_to_cpu(mi->member_bytes) < sizeof(struct bch_member)) {
69                 unsigned u64s = DIV_ROUND_UP((sizeof(*mi) + sizeof(mi->_members[0]) *
70                                               c->disk_sb.sb->nr_devices), 8);
71
72                 mi = bch2_sb_field_resize(&c->disk_sb, members_v2, u64s);
73                 if (!mi)
74                         return -BCH_ERR_ENOSPC_sb_members_v2;
75
76                 for (int i = c->disk_sb.sb->nr_devices - 1; i >= 0; --i) {
77                         void *dst = (void *) mi->_members + (i * sizeof(struct bch_member));
78                         memmove(dst, members_v2_get_mut(mi, i), le16_to_cpu(mi->member_bytes));
79                         memset(dst + le16_to_cpu(mi->member_bytes),
80                                0, (sizeof(struct bch_member) - le16_to_cpu(mi->member_bytes)));
81                 }
82                 mi->member_bytes = cpu_to_le16(sizeof(struct bch_member));
83         }
84         return 0;
85 }
86
87 int bch2_sb_members_v2_init(struct bch_fs *c)
88 {
89         struct bch_sb_field_members_v1 *mi1;
90         struct bch_sb_field_members_v2 *mi2;
91
92         if (!bch2_sb_field_get(c->disk_sb.sb, members_v2)) {
93                 mi2 = bch2_sb_field_resize(&c->disk_sb, members_v2,
94                                 DIV_ROUND_UP(sizeof(*mi2) +
95                                              sizeof(struct bch_member) * c->sb.nr_devices,
96                                              sizeof(u64)));
97                 mi1 = bch2_sb_field_get(c->disk_sb.sb, members_v1);
98                 memcpy(&mi2->_members[0], &mi1->_members[0],
99                        BCH_MEMBER_V1_BYTES * c->sb.nr_devices);
100                 memset(&mi2->pad[0], 0, sizeof(mi2->pad));
101                 mi2->member_bytes = cpu_to_le16(BCH_MEMBER_V1_BYTES);
102         }
103
104         return sb_members_v2_resize_entries(c);
105 }
106
107 int bch2_sb_members_cpy_v2_v1(struct bch_sb_handle *disk_sb)
108 {
109         struct bch_sb_field_members_v1 *mi1;
110         struct bch_sb_field_members_v2 *mi2;
111
112         mi1 = bch2_sb_field_resize(disk_sb, members_v1,
113                         DIV_ROUND_UP(sizeof(*mi1) + BCH_MEMBER_V1_BYTES *
114                                      disk_sb->sb->nr_devices, sizeof(u64)));
115         if (!mi1)
116                 return -BCH_ERR_ENOSPC_sb_members;
117
118         mi2 = bch2_sb_field_get(disk_sb->sb, members_v2);
119
120         for (unsigned i = 0; i < disk_sb->sb->nr_devices; i++)
121                 memcpy(members_v1_get_mut(mi1, i), members_v2_get_mut(mi2, i), BCH_MEMBER_V1_BYTES);
122
123         return 0;
124 }
125
126 static int validate_member(struct printbuf *err,
127                            struct bch_member m,
128                            struct bch_sb *sb,
129                            int i)
130 {
131         if (le64_to_cpu(m.nbuckets) > LONG_MAX) {
132                 prt_printf(err, "device %u: too many buckets (got %llu, max %lu)",
133                            i, le64_to_cpu(m.nbuckets), LONG_MAX);
134                 return -BCH_ERR_invalid_sb_members;
135         }
136
137         if (le64_to_cpu(m.nbuckets) -
138             le16_to_cpu(m.first_bucket) < BCH_MIN_NR_NBUCKETS) {
139                 prt_printf(err, "device %u: not enough buckets (got %llu, max %u)",
140                            i, le64_to_cpu(m.nbuckets), BCH_MIN_NR_NBUCKETS);
141                 return -BCH_ERR_invalid_sb_members;
142         }
143
144         if (le16_to_cpu(m.bucket_size) <
145             le16_to_cpu(sb->block_size)) {
146                 prt_printf(err, "device %u: bucket size %u smaller than block size %u",
147                            i, le16_to_cpu(m.bucket_size), le16_to_cpu(sb->block_size));
148                 return -BCH_ERR_invalid_sb_members;
149         }
150
151         if (le16_to_cpu(m.bucket_size) <
152             BCH_SB_BTREE_NODE_SIZE(sb)) {
153                 prt_printf(err, "device %u: bucket size %u smaller than btree node size %llu",
154                            i, le16_to_cpu(m.bucket_size), BCH_SB_BTREE_NODE_SIZE(sb));
155                 return -BCH_ERR_invalid_sb_members;
156         }
157
158         return 0;
159 }
160
161 static void member_to_text(struct printbuf *out,
162                            struct bch_member m,
163                            struct bch_sb_field_disk_groups *gi,
164                            struct bch_sb *sb,
165                            int i)
166 {
167         unsigned data_have = bch2_sb_dev_has_data(sb, i);
168         u64 bucket_size = le16_to_cpu(m.bucket_size);
169         u64 device_size = le64_to_cpu(m.nbuckets) * bucket_size;
170
171         prt_printf(out, "Device:");
172         prt_tab(out);
173         prt_printf(out, "%u", i);
174         prt_newline(out);
175
176         printbuf_indent_add(out, 2);
177
178         prt_printf(out, "Label:");
179         prt_tab(out);
180         if (BCH_MEMBER_GROUP(&m)) {
181                 unsigned idx = BCH_MEMBER_GROUP(&m) - 1;
182
183                 if (idx < disk_groups_nr(gi))
184                         prt_printf(out, "%s (%u)",
185                                    gi->entries[idx].label, idx);
186                 else
187                         prt_printf(out, "(bad disk labels section)");
188         } else {
189                 prt_printf(out, "(none)");
190         }
191         prt_newline(out);
192
193         prt_printf(out, "UUID:");
194         prt_tab(out);
195         pr_uuid(out, m.uuid.b);
196         prt_newline(out);
197
198         prt_printf(out, "Size:");
199         prt_tab(out);
200         prt_units_u64(out, device_size << 9);
201         prt_newline(out);
202
203         for (unsigned i = 0; i < BCH_MEMBER_ERROR_NR; i++) {
204                 prt_printf(out, "%s errors:", bch2_member_error_strs[i]);
205                 prt_tab(out);
206                 prt_u64(out, le64_to_cpu(m.errors[i]));
207                 prt_newline(out);
208         }
209
210         for (unsigned i = 0; i < BCH_IOPS_NR; i++) {
211                 prt_printf(out, "%s iops:", bch2_iops_measurements[i]);
212                 prt_tab(out);
213                 prt_printf(out, "%u", le32_to_cpu(m.iops[i]));
214                 prt_newline(out);
215         }
216
217         prt_printf(out, "Bucket size:");
218         prt_tab(out);
219         prt_units_u64(out, bucket_size << 9);
220         prt_newline(out);
221
222         prt_printf(out, "First bucket:");
223         prt_tab(out);
224         prt_printf(out, "%u", le16_to_cpu(m.first_bucket));
225         prt_newline(out);
226
227         prt_printf(out, "Buckets:");
228         prt_tab(out);
229         prt_printf(out, "%llu", le64_to_cpu(m.nbuckets));
230         prt_newline(out);
231
232         prt_printf(out, "Last mount:");
233         prt_tab(out);
234         if (m.last_mount)
235                 pr_time(out, le64_to_cpu(m.last_mount));
236         else
237                 prt_printf(out, "(never)");
238         prt_newline(out);
239
240         prt_printf(out, "State:");
241         prt_tab(out);
242         prt_printf(out, "%s",
243                    BCH_MEMBER_STATE(&m) < BCH_MEMBER_STATE_NR
244                    ? bch2_member_states[BCH_MEMBER_STATE(&m)]
245                    : "unknown");
246         prt_newline(out);
247
248         prt_printf(out, "Data allowed:");
249         prt_tab(out);
250         if (BCH_MEMBER_DATA_ALLOWED(&m))
251                 prt_bitflags(out, bch2_data_types, BCH_MEMBER_DATA_ALLOWED(&m));
252         else
253                 prt_printf(out, "(none)");
254         prt_newline(out);
255
256         prt_printf(out, "Has data:");
257         prt_tab(out);
258         if (data_have)
259                 prt_bitflags(out, bch2_data_types, data_have);
260         else
261                 prt_printf(out, "(none)");
262         prt_newline(out);
263
264         prt_printf(out, "Discard:");
265         prt_tab(out);
266         prt_printf(out, "%llu", BCH_MEMBER_DISCARD(&m));
267         prt_newline(out);
268
269         prt_printf(out, "Freespace initialized:");
270         prt_tab(out);
271         prt_printf(out, "%llu", BCH_MEMBER_FREESPACE_INITIALIZED(&m));
272         prt_newline(out);
273
274         printbuf_indent_sub(out, 2);
275 }
276
277 static int bch2_sb_members_v1_validate(struct bch_sb *sb,
278                                     struct bch_sb_field *f,
279                                     struct printbuf *err)
280 {
281         struct bch_sb_field_members_v1 *mi = field_to_type(f, members_v1);
282         unsigned i;
283
284         if ((void *) members_v1_get_mut(mi, sb->nr_devices) > vstruct_end(&mi->field)) {
285                 prt_printf(err, "too many devices for section size");
286                 return -BCH_ERR_invalid_sb_members;
287         }
288
289         for (i = 0; i < sb->nr_devices; i++) {
290                 struct bch_member m = members_v1_get(mi, i);
291
292                 int ret = validate_member(err, m, sb, i);
293                 if (ret)
294                         return ret;
295         }
296
297         return 0;
298 }
299
300 static void bch2_sb_members_v1_to_text(struct printbuf *out, struct bch_sb *sb,
301                                        struct bch_sb_field *f)
302 {
303         struct bch_sb_field_members_v1 *mi = field_to_type(f, members_v1);
304         struct bch_sb_field_disk_groups *gi = bch2_sb_field_get(sb, disk_groups);
305         unsigned i;
306
307         for (i = 0; i < sb->nr_devices; i++) {
308                 struct bch_member m = members_v1_get(mi, i);
309                 member_to_text(out, m, gi, sb, i);
310         }
311 }
312
313 const struct bch_sb_field_ops bch_sb_field_ops_members_v1 = {
314         .validate       = bch2_sb_members_v1_validate,
315         .to_text        = bch2_sb_members_v1_to_text,
316 };
317
318 static void bch2_sb_members_v2_to_text(struct printbuf *out, struct bch_sb *sb,
319                                        struct bch_sb_field *f)
320 {
321         struct bch_sb_field_members_v2 *mi = field_to_type(f, members_v2);
322         struct bch_sb_field_disk_groups *gi = bch2_sb_field_get(sb, disk_groups);
323         unsigned i;
324
325         for (i = 0; i < sb->nr_devices; i++) {
326                 struct bch_member m = members_v2_get(mi, i);
327                 member_to_text(out, m, gi, sb, i);
328         }
329 }
330
331 static int bch2_sb_members_v2_validate(struct bch_sb *sb,
332                                        struct bch_sb_field *f,
333                                        struct printbuf *err)
334 {
335         struct bch_sb_field_members_v2 *mi = field_to_type(f, members_v2);
336         size_t mi_bytes = (void *) members_v2_get_mut(mi, sb->nr_devices) -
337                 (void *) mi;
338
339         if (mi_bytes > vstruct_bytes(&mi->field)) {
340                 prt_printf(err, "section too small (%zu > %zu)",
341                            mi_bytes, vstruct_bytes(&mi->field));
342                 return -BCH_ERR_invalid_sb_members;
343         }
344
345         for (unsigned i = 0; i < sb->nr_devices; i++) {
346                 int ret = validate_member(err, members_v2_get(mi, i), sb, i);
347                 if (ret)
348                         return ret;
349         }
350
351         return 0;
352 }
353
354 const struct bch_sb_field_ops bch_sb_field_ops_members_v2 = {
355         .validate       = bch2_sb_members_v2_validate,
356         .to_text        = bch2_sb_members_v2_to_text,
357 };
358
359 void bch2_sb_members_from_cpu(struct bch_fs *c)
360 {
361         struct bch_sb_field_members_v2 *mi = bch2_sb_field_get(c->disk_sb.sb, members_v2);
362         struct bch_dev *ca;
363         unsigned i, e;
364
365         rcu_read_lock();
366         for_each_member_device_rcu(ca, c, i, NULL) {
367                 struct bch_member *m = members_v2_get_mut(mi, i);
368
369                 for (e = 0; e < BCH_MEMBER_ERROR_NR; e++)
370                         m->errors[e] = cpu_to_le64(atomic64_read(&ca->errors[e]));
371         }
372         rcu_read_unlock();
373 }
374
375 void bch2_dev_io_errors_to_text(struct printbuf *out, struct bch_dev *ca)
376 {
377         struct bch_fs *c = ca->fs;
378         struct bch_member m;
379
380         mutex_lock(&ca->fs->sb_lock);
381         m = bch2_sb_member_get(c->disk_sb.sb, ca->dev_idx);
382         mutex_unlock(&ca->fs->sb_lock);
383
384         printbuf_tabstop_push(out, 12);
385
386         prt_str(out, "IO errors since filesystem creation");
387         prt_newline(out);
388
389         printbuf_indent_add(out, 2);
390         for (unsigned i = 0; i < BCH_MEMBER_ERROR_NR; i++) {
391                 prt_printf(out, "%s:", bch2_member_error_strs[i]);
392                 prt_tab(out);
393                 prt_u64(out, atomic64_read(&ca->errors[i]));
394                 prt_newline(out);
395         }
396         printbuf_indent_sub(out, 2);
397
398         prt_str(out, "IO errors since ");
399         bch2_pr_time_units(out, (ktime_get_real_seconds() - le64_to_cpu(m.errors_reset_time)) * NSEC_PER_SEC);
400         prt_str(out, " ago");
401         prt_newline(out);
402
403         printbuf_indent_add(out, 2);
404         for (unsigned i = 0; i < BCH_MEMBER_ERROR_NR; i++) {
405                 prt_printf(out, "%s:", bch2_member_error_strs[i]);
406                 prt_tab(out);
407                 prt_u64(out, atomic64_read(&ca->errors[i]) - le64_to_cpu(m.errors_at_reset[i]));
408                 prt_newline(out);
409         }
410         printbuf_indent_sub(out, 2);
411 }
412
413 void bch2_dev_errors_reset(struct bch_dev *ca)
414 {
415         struct bch_fs *c = ca->fs;
416         struct bch_member *m;
417
418         mutex_lock(&c->sb_lock);
419         m = bch2_members_v2_get_mut(c->disk_sb.sb, ca->dev_idx);
420         for (unsigned i = 0; i < ARRAY_SIZE(m->errors_at_reset); i++)
421                 m->errors_at_reset[i] = cpu_to_le64(atomic64_read(&ca->errors[i]));
422         m->errors_reset_time = ktime_get_real_seconds();
423
424         bch2_write_super(c);
425         mutex_unlock(&c->sb_lock);
426 }