1 // SPDX-License-Identifier: GPL-2.0
7 static const char * const bch2_sb_error_strs[] = {
8 #define x(t, n, ...) [n] = #t,
13 static void bch2_sb_error_id_to_text(struct printbuf *out, enum bch_sb_error_id id)
15 if (id < BCH_SB_ERR_MAX)
16 prt_str(out, bch2_sb_error_strs[id]);
18 prt_printf(out, "(unknown error %u)", id);
21 static inline unsigned bch2_sb_field_errors_nr_entries(struct bch_sb_field_errors *e)
24 ? (bch2_sb_field_bytes(&e->field) - sizeof(*e)) / sizeof(e->entries[0])
28 static inline unsigned bch2_sb_field_errors_u64s(unsigned nr)
30 return (sizeof(struct bch_sb_field_errors) +
31 sizeof(struct bch_sb_field_error_entry) * nr) / sizeof(u64);
34 static int bch2_sb_errors_validate(struct bch_sb *sb, struct bch_sb_field *f,
37 struct bch_sb_field_errors *e = field_to_type(f, errors);
38 unsigned i, nr = bch2_sb_field_errors_nr_entries(e);
40 for (i = 0; i < nr; i++) {
41 if (!BCH_SB_ERROR_ENTRY_NR(&e->entries[i])) {
42 prt_printf(err, "entry with count 0 (id ");
43 bch2_sb_error_id_to_text(err, BCH_SB_ERROR_ENTRY_ID(&e->entries[i]));
45 return -BCH_ERR_invalid_sb_errors;
49 BCH_SB_ERROR_ENTRY_ID(&e->entries[i]) >=
50 BCH_SB_ERROR_ENTRY_ID(&e->entries[i + 1])) {
51 prt_printf(err, "entries out of order");
52 return -BCH_ERR_invalid_sb_errors;
59 static void bch2_sb_errors_to_text(struct printbuf *out, struct bch_sb *sb,
60 struct bch_sb_field *f)
62 struct bch_sb_field_errors *e = field_to_type(f, errors);
63 unsigned i, nr = bch2_sb_field_errors_nr_entries(e);
65 if (out->nr_tabstops <= 1)
66 printbuf_tabstop_push(out, 16);
68 for (i = 0; i < nr; i++) {
69 bch2_sb_error_id_to_text(out, BCH_SB_ERROR_ENTRY_ID(&e->entries[i]));
71 prt_u64(out, BCH_SB_ERROR_ENTRY_NR(&e->entries[i]));
73 bch2_prt_datetime(out, le64_to_cpu(e->entries[i].last_error_time));
78 const struct bch_sb_field_ops bch_sb_field_ops_errors = {
79 .validate = bch2_sb_errors_validate,
80 .to_text = bch2_sb_errors_to_text,
83 void bch2_sb_error_count(struct bch_fs *c, enum bch_sb_error_id err)
85 bch_sb_errors_cpu *e = &c->fsck_error_counts;
86 struct bch_sb_error_entry_cpu n = {
89 .last_error_time = ktime_get_real_seconds()
93 mutex_lock(&c->fsck_error_counts_lock);
94 for (i = 0; i < e->nr; i++) {
95 if (err == e->data[i].id) {
97 e->data[i].last_error_time = n.last_error_time;
100 if (err < e->data[i].id)
104 if (darray_make_room(e, 1))
107 darray_insert_item(e, i, n);
109 mutex_unlock(&c->fsck_error_counts_lock);
112 void bch2_sb_errors_from_cpu(struct bch_fs *c)
114 bch_sb_errors_cpu *src = &c->fsck_error_counts;
115 struct bch_sb_field_errors *dst =
116 bch2_sb_field_resize(&c->disk_sb, errors,
117 bch2_sb_field_errors_u64s(src->nr));
123 for (i = 0; i < src->nr; i++) {
124 SET_BCH_SB_ERROR_ENTRY_ID(&dst->entries[i], src->data[i].id);
125 SET_BCH_SB_ERROR_ENTRY_NR(&dst->entries[i], src->data[i].nr);
126 dst->entries[i].last_error_time = cpu_to_le64(src->data[i].last_error_time);
130 static int bch2_sb_errors_to_cpu(struct bch_fs *c)
132 struct bch_sb_field_errors *src = bch2_sb_field_get(c->disk_sb.sb, errors);
133 bch_sb_errors_cpu *dst = &c->fsck_error_counts;
134 unsigned i, nr = bch2_sb_field_errors_nr_entries(src);
140 mutex_lock(&c->fsck_error_counts_lock);
141 ret = darray_make_room(dst, nr);
147 for (i = 0; i < nr; i++) {
148 dst->data[i].id = BCH_SB_ERROR_ENTRY_ID(&src->entries[i]);
149 dst->data[i].nr = BCH_SB_ERROR_ENTRY_NR(&src->entries[i]);
150 dst->data[i].last_error_time = le64_to_cpu(src->entries[i].last_error_time);
153 mutex_unlock(&c->fsck_error_counts_lock);
158 void bch2_fs_sb_errors_exit(struct bch_fs *c)
160 darray_exit(&c->fsck_error_counts);
163 void bch2_fs_sb_errors_init_early(struct bch_fs *c)
165 mutex_init(&c->fsck_error_counts_lock);
166 darray_init(&c->fsck_error_counts);
169 int bch2_fs_sb_errors_init(struct bch_fs *c)
171 return bch2_sb_errors_to_cpu(c);