1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include "bcachefs.h" |
3 | #include "super-io.h" |
4 | #include "sb-counters.h" |
5 | |
6 | /* BCH_SB_FIELD_counters */ |
7 | |
8 | static const char * const bch2_counter_names[] = { |
9 | #define x(t, n, ...) (#t), |
10 | BCH_PERSISTENT_COUNTERS() |
11 | #undef x |
12 | NULL |
13 | }; |
14 | |
15 | static size_t bch2_sb_counter_nr_entries(struct bch_sb_field_counters *ctrs) |
16 | { |
17 | if (!ctrs) |
18 | return 0; |
19 | |
20 | return (__le64 *) vstruct_end(&ctrs->field) - &ctrs->d[0]; |
21 | }; |
22 | |
23 | static int bch2_sb_counters_validate(struct bch_sb *sb, |
24 | struct bch_sb_field *f, |
25 | struct printbuf *err) |
26 | { |
27 | return 0; |
28 | }; |
29 | |
30 | static void bch2_sb_counters_to_text(struct printbuf *out, struct bch_sb *sb, |
31 | struct bch_sb_field *f) |
32 | { |
33 | struct bch_sb_field_counters *ctrs = field_to_type(f, counters); |
34 | unsigned int i; |
35 | unsigned int nr = bch2_sb_counter_nr_entries(ctrs); |
36 | |
37 | for (i = 0; i < nr; i++) { |
38 | if (i < BCH_COUNTER_NR) |
39 | prt_printf(out, "%s " , bch2_counter_names[i]); |
40 | else |
41 | prt_printf(out, "(unknown)" ); |
42 | |
43 | prt_tab(out); |
44 | prt_printf(out, "%llu" , le64_to_cpu(ctrs->d[i])); |
45 | prt_newline(out); |
46 | } |
47 | }; |
48 | |
49 | int bch2_sb_counters_to_cpu(struct bch_fs *c) |
50 | { |
51 | struct bch_sb_field_counters *ctrs = bch2_sb_field_get(c->disk_sb.sb, counters); |
52 | unsigned int i; |
53 | unsigned int nr = bch2_sb_counter_nr_entries(ctrs); |
54 | u64 val = 0; |
55 | |
56 | for (i = 0; i < BCH_COUNTER_NR; i++) |
57 | c->counters_on_mount[i] = 0; |
58 | |
59 | for (i = 0; i < min_t(unsigned int, nr, BCH_COUNTER_NR); i++) { |
60 | val = le64_to_cpu(ctrs->d[i]); |
61 | percpu_u64_set(dst: &c->counters[i], src: val); |
62 | c->counters_on_mount[i] = val; |
63 | } |
64 | return 0; |
65 | }; |
66 | |
67 | int bch2_sb_counters_from_cpu(struct bch_fs *c) |
68 | { |
69 | struct bch_sb_field_counters *ctrs = bch2_sb_field_get(c->disk_sb.sb, counters); |
70 | struct bch_sb_field_counters *ret; |
71 | unsigned int i; |
72 | unsigned int nr = bch2_sb_counter_nr_entries(ctrs); |
73 | |
74 | if (nr < BCH_COUNTER_NR) { |
75 | ret = bch2_sb_field_resize(&c->disk_sb, counters, |
76 | sizeof(*ctrs) / sizeof(u64) + BCH_COUNTER_NR); |
77 | |
78 | if (ret) { |
79 | ctrs = ret; |
80 | nr = bch2_sb_counter_nr_entries(ctrs); |
81 | } |
82 | } |
83 | |
84 | |
85 | for (i = 0; i < min_t(unsigned int, nr, BCH_COUNTER_NR); i++) |
86 | ctrs->d[i] = cpu_to_le64(percpu_u64_get(&c->counters[i])); |
87 | return 0; |
88 | } |
89 | |
90 | void bch2_fs_counters_exit(struct bch_fs *c) |
91 | { |
92 | free_percpu(pdata: c->counters); |
93 | } |
94 | |
95 | int bch2_fs_counters_init(struct bch_fs *c) |
96 | { |
97 | c->counters = __alloc_percpu(size: sizeof(u64) * BCH_COUNTER_NR, align: sizeof(u64)); |
98 | if (!c->counters) |
99 | return -BCH_ERR_ENOMEM_fs_counters_init; |
100 | |
101 | return bch2_sb_counters_to_cpu(c); |
102 | } |
103 | |
104 | const struct bch_sb_field_ops bch_sb_field_ops_counters = { |
105 | .validate = bch2_sb_counters_validate, |
106 | .to_text = bch2_sb_counters_to_text, |
107 | }; |
108 | |