]> git.ipfire.org Git - thirdparty/linux.git/blame - fs/bcachefs/sb-members.c
bcachefs: bch2_prt_datetime()
[thirdparty/linux.git] / fs / bcachefs / sb-members.c
CommitLineData
fb8e5b4c
KO
1// SPDX-License-Identifier: GPL-2.0
2
3#include "bcachefs.h"
4#include "disk_groups.h"
40f7914e 5#include "opts.h"
fb8e5b4c
KO
6#include "replicas.h"
7#include "sb-members.h"
8#include "super-io.h"
9
94119eeb
KO
10#define x(t, n, ...) [n] = #t,
11static const char * const bch2_iops_measurements[] = {
12 BCH_IOPS_MEASUREMENTS()
13 NULL
14};
15
16char * const bch2_member_error_strs[] = {
17 BCH_MEMBER_ERROR_TYPES()
18 NULL
19};
20#undef x
21
9af26120 22/* Code for bch_sb_field_members_v1: */
3f7b9713
HS
23
24static 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
29struct bch_member *bch2_members_v2_get_mut(struct bch_sb *sb, int i)
30{
4637429e 31 return members_v2_get_mut(bch2_sb_field_get(sb, members_v2), i);
3f7b9713
HS
32}
33
34static 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
9af26120 42static struct bch_member *members_v1_get_mut(struct bch_sb_field_members_v1 *mi, int i)
1241df58 43{
3f7b9713 44 return (void *) mi->_members + (i * BCH_MEMBER_V1_BYTES);
1241df58
HS
45}
46
9af26120 47static struct bch_member members_v1_get(struct bch_sb_field_members_v1 *mi, int i)
1241df58
HS
48{
49 struct bch_member ret, *p = members_v1_get_mut(mi, i);
50 memset(&ret, 0, sizeof(ret));
5c1ab40e
KO
51 memcpy(&ret, p, min_t(size_t, BCH_MEMBER_V1_BYTES, sizeof(ret)));
52 return ret;
1241df58
HS
53}
54
55struct bch_member bch2_sb_member_get(struct bch_sb *sb, int i)
56{
4637429e 57 struct bch_sb_field_members_v2 *mi2 = bch2_sb_field_get(sb, members_v2);
3f7b9713
HS
58 if (mi2)
59 return members_v2_get(mi2, i);
4637429e 60 struct bch_sb_field_members_v1 *mi1 = bch2_sb_field_get(sb, members_v1);
1241df58
HS
61 return members_v1_get(mi1, i);
62}
fb8e5b4c 63
3f7b9713
HS
64static int sb_members_v2_resize_entries(struct bch_fs *c)
65{
4637429e 66 struct bch_sb_field_members_v2 *mi = bch2_sb_field_get(c->disk_sb.sb, members_v2);
3f7b9713
HS
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
4637429e 72 mi = bch2_sb_field_resize(&c->disk_sb, members_v2, u64s);
3f7b9713
HS
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
f5d26fa3 87int bch2_sb_members_v2_init(struct bch_fs *c)
3f7b9713 88{
9af26120 89 struct bch_sb_field_members_v1 *mi1;
3f7b9713
HS
90 struct bch_sb_field_members_v2 *mi2;
91
4637429e
KO
92 if (!bch2_sb_field_get(c->disk_sb.sb, members_v2)) {
93 mi2 = bch2_sb_field_resize(&c->disk_sb, members_v2,
3f7b9713
HS
94 DIV_ROUND_UP(sizeof(*mi2) +
95 sizeof(struct bch_member) * c->sb.nr_devices,
96 sizeof(u64)));
4637429e 97 mi1 = bch2_sb_field_get(c->disk_sb.sb, members_v1);
3f7b9713
HS
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
94119eeb 107int bch2_sb_members_cpy_v2_v1(struct bch_sb_handle *disk_sb)
3f7b9713 108{
9af26120 109 struct bch_sb_field_members_v1 *mi1;
3f7b9713
HS
110 struct bch_sb_field_members_v2 *mi2;
111
4637429e 112 mi1 = bch2_sb_field_resize(disk_sb, members_v1,
3f7b9713
HS
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
4637429e 118 mi2 = bch2_sb_field_get(disk_sb->sb, members_v2);
3f7b9713
HS
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
126static 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
161static 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
dc7a15fb
KO
171 if (!bch2_member_exists(&m))
172 return;
173
3f7b9713
HS
174 prt_printf(out, "Device:");
175 prt_tab(out);
176 prt_printf(out, "%u", i);
177 prt_newline(out);
178
179 printbuf_indent_add(out, 2);
180
94119eeb
KO
181 prt_printf(out, "Label:");
182 prt_tab(out);
183 if (BCH_MEMBER_GROUP(&m)) {
184 unsigned idx = BCH_MEMBER_GROUP(&m) - 1;
185
186 if (idx < disk_groups_nr(gi))
187 prt_printf(out, "%s (%u)",
188 gi->entries[idx].label, idx);
189 else
190 prt_printf(out, "(bad disk labels section)");
191 } else {
192 prt_printf(out, "(none)");
193 }
194 prt_newline(out);
195
3f7b9713
HS
196 prt_printf(out, "UUID:");
197 prt_tab(out);
198 pr_uuid(out, m.uuid.b);
199 prt_newline(out);
200
201 prt_printf(out, "Size:");
202 prt_tab(out);
203 prt_units_u64(out, device_size << 9);
204 prt_newline(out);
205
94119eeb
KO
206 for (unsigned i = 0; i < BCH_MEMBER_ERROR_NR; i++) {
207 prt_printf(out, "%s errors:", bch2_member_error_strs[i]);
208 prt_tab(out);
209 prt_u64(out, le64_to_cpu(m.errors[i]));
210 prt_newline(out);
211 }
212
40f7914e
HS
213 for (unsigned i = 0; i < BCH_IOPS_NR; i++) {
214 prt_printf(out, "%s iops:", bch2_iops_measurements[i]);
215 prt_tab(out);
216 prt_printf(out, "%u", le32_to_cpu(m.iops[i]));
217 prt_newline(out);
218 }
219
3f7b9713
HS
220 prt_printf(out, "Bucket size:");
221 prt_tab(out);
222 prt_units_u64(out, bucket_size << 9);
223 prt_newline(out);
224
225 prt_printf(out, "First bucket:");
226 prt_tab(out);
227 prt_printf(out, "%u", le16_to_cpu(m.first_bucket));
228 prt_newline(out);
229
230 prt_printf(out, "Buckets:");
231 prt_tab(out);
232 prt_printf(out, "%llu", le64_to_cpu(m.nbuckets));
233 prt_newline(out);
234
235 prt_printf(out, "Last mount:");
236 prt_tab(out);
237 if (m.last_mount)
59154f2c 238 bch2_prt_datetime(out, le64_to_cpu(m.last_mount));
3f7b9713
HS
239 else
240 prt_printf(out, "(never)");
241 prt_newline(out);
242
243 prt_printf(out, "State:");
244 prt_tab(out);
245 prt_printf(out, "%s",
246 BCH_MEMBER_STATE(&m) < BCH_MEMBER_STATE_NR
247 ? bch2_member_states[BCH_MEMBER_STATE(&m)]
248 : "unknown");
249 prt_newline(out);
250
3f7b9713
HS
251 prt_printf(out, "Data allowed:");
252 prt_tab(out);
253 if (BCH_MEMBER_DATA_ALLOWED(&m))
254 prt_bitflags(out, bch2_data_types, BCH_MEMBER_DATA_ALLOWED(&m));
255 else
256 prt_printf(out, "(none)");
257 prt_newline(out);
258
259 prt_printf(out, "Has data:");
260 prt_tab(out);
261 if (data_have)
262 prt_bitflags(out, bch2_data_types, data_have);
263 else
264 prt_printf(out, "(none)");
265 prt_newline(out);
266
267 prt_printf(out, "Discard:");
268 prt_tab(out);
269 prt_printf(out, "%llu", BCH_MEMBER_DISCARD(&m));
270 prt_newline(out);
271
272 prt_printf(out, "Freespace initialized:");
273 prt_tab(out);
274 prt_printf(out, "%llu", BCH_MEMBER_FREESPACE_INITIALIZED(&m));
275 prt_newline(out);
276
277 printbuf_indent_sub(out, 2);
278}
279
280static int bch2_sb_members_v1_validate(struct bch_sb *sb,
fb8e5b4c
KO
281 struct bch_sb_field *f,
282 struct printbuf *err)
283{
9af26120 284 struct bch_sb_field_members_v1 *mi = field_to_type(f, members_v1);
fb8e5b4c
KO
285 unsigned i;
286
5c1ab40e 287 if ((void *) members_v1_get_mut(mi, sb->nr_devices) > vstruct_end(&mi->field)) {
fb8e5b4c
KO
288 prt_printf(err, "too many devices for section size");
289 return -BCH_ERR_invalid_sb_members;
290 }
291
292 for (i = 0; i < sb->nr_devices; i++) {
3f7b9713 293 struct bch_member m = members_v1_get(mi, i);
fb8e5b4c 294
3f7b9713
HS
295 int ret = validate_member(err, m, sb, i);
296 if (ret)
297 return ret;
fb8e5b4c
KO
298 }
299
300 return 0;
301}
302
3f7b9713
HS
303static void bch2_sb_members_v1_to_text(struct printbuf *out, struct bch_sb *sb,
304 struct bch_sb_field *f)
fb8e5b4c 305{
9af26120 306 struct bch_sb_field_members_v1 *mi = field_to_type(f, members_v1);
4637429e 307 struct bch_sb_field_disk_groups *gi = bch2_sb_field_get(sb, disk_groups);
fb8e5b4c
KO
308 unsigned i;
309
dc7a15fb
KO
310 for (i = 0; i < sb->nr_devices; i++)
311 member_to_text(out, members_v1_get(mi, i), gi, sb, i);
3f7b9713 312}
fb8e5b4c 313
9af26120 314const struct bch_sb_field_ops bch_sb_field_ops_members_v1 = {
3f7b9713
HS
315 .validate = bch2_sb_members_v1_validate,
316 .to_text = bch2_sb_members_v1_to_text,
317};
fb8e5b4c 318
3f7b9713
HS
319static void bch2_sb_members_v2_to_text(struct printbuf *out, struct bch_sb *sb,
320 struct bch_sb_field *f)
321{
322 struct bch_sb_field_members_v2 *mi = field_to_type(f, members_v2);
4637429e 323 struct bch_sb_field_disk_groups *gi = bch2_sb_field_get(sb, disk_groups);
3f7b9713 324 unsigned i;
fb8e5b4c 325
dc7a15fb
KO
326 for (i = 0; i < sb->nr_devices; i++)
327 member_to_text(out, members_v2_get(mi, i), gi, sb, i);
3f7b9713
HS
328}
329
330static int bch2_sb_members_v2_validate(struct bch_sb *sb,
331 struct bch_sb_field *f,
332 struct printbuf *err)
333{
334 struct bch_sb_field_members_v2 *mi = field_to_type(f, members_v2);
335 size_t mi_bytes = (void *) members_v2_get_mut(mi, sb->nr_devices) -
336 (void *) mi;
fb8e5b4c 337
3f7b9713
HS
338 if (mi_bytes > vstruct_bytes(&mi->field)) {
339 prt_printf(err, "section too small (%zu > %zu)",
340 mi_bytes, vstruct_bytes(&mi->field));
341 return -BCH_ERR_invalid_sb_members;
342 }
fb8e5b4c 343
3f7b9713
HS
344 for (unsigned i = 0; i < sb->nr_devices; i++) {
345 int ret = validate_member(err, members_v2_get(mi, i), sb, i);
346 if (ret)
347 return ret;
fb8e5b4c 348 }
3f7b9713
HS
349
350 return 0;
fb8e5b4c
KO
351}
352
3f7b9713
HS
353const struct bch_sb_field_ops bch_sb_field_ops_members_v2 = {
354 .validate = bch2_sb_members_v2_validate,
355 .to_text = bch2_sb_members_v2_to_text,
fb8e5b4c 356};
94119eeb
KO
357
358void bch2_sb_members_from_cpu(struct bch_fs *c)
359{
360 struct bch_sb_field_members_v2 *mi = bch2_sb_field_get(c->disk_sb.sb, members_v2);
361 struct bch_dev *ca;
362 unsigned i, e;
363
364 rcu_read_lock();
365 for_each_member_device_rcu(ca, c, i, NULL) {
366 struct bch_member *m = members_v2_get_mut(mi, i);
367
368 for (e = 0; e < BCH_MEMBER_ERROR_NR; e++)
369 m->errors[e] = cpu_to_le64(atomic64_read(&ca->errors[e]));
370 }
371 rcu_read_unlock();
372}
373
374void bch2_dev_io_errors_to_text(struct printbuf *out, struct bch_dev *ca)
375{
376 struct bch_fs *c = ca->fs;
377 struct bch_member m;
378
379 mutex_lock(&ca->fs->sb_lock);
380 m = bch2_sb_member_get(c->disk_sb.sb, ca->dev_idx);
381 mutex_unlock(&ca->fs->sb_lock);
382
383 printbuf_tabstop_push(out, 12);
384
385 prt_str(out, "IO errors since filesystem creation");
386 prt_newline(out);
387
388 printbuf_indent_add(out, 2);
389 for (unsigned i = 0; i < BCH_MEMBER_ERROR_NR; i++) {
390 prt_printf(out, "%s:", bch2_member_error_strs[i]);
391 prt_tab(out);
392 prt_u64(out, atomic64_read(&ca->errors[i]));
393 prt_newline(out);
394 }
395 printbuf_indent_sub(out, 2);
396
397 prt_str(out, "IO errors since ");
398 bch2_pr_time_units(out, (ktime_get_real_seconds() - le64_to_cpu(m.errors_reset_time)) * NSEC_PER_SEC);
399 prt_str(out, " ago");
400 prt_newline(out);
401
402 printbuf_indent_add(out, 2);
403 for (unsigned i = 0; i < BCH_MEMBER_ERROR_NR; i++) {
404 prt_printf(out, "%s:", bch2_member_error_strs[i]);
405 prt_tab(out);
406 prt_u64(out, atomic64_read(&ca->errors[i]) - le64_to_cpu(m.errors_at_reset[i]));
407 prt_newline(out);
408 }
409 printbuf_indent_sub(out, 2);
410}
411
412void bch2_dev_errors_reset(struct bch_dev *ca)
413{
414 struct bch_fs *c = ca->fs;
415 struct bch_member *m;
416
417 mutex_lock(&c->sb_lock);
418 m = bch2_members_v2_get_mut(c->disk_sb.sb, ca->dev_idx);
419 for (unsigned i = 0; i < ARRAY_SIZE(m->errors_at_reset); i++)
420 m->errors_at_reset[i] = cpu_to_le64(atomic64_read(&ca->errors[i]));
421 m->errors_reset_time = ktime_get_real_seconds();
422
423 bch2_write_super(c);
424 mutex_unlock(&c->sb_lock);
425}