]> git.sesse.net Git - bcachefs-tools-debian/blob - libbcachefs/sb-errors.c
Update bcachefs sources to 7250b2ee5574 bcachefs: Fix deleted inodes btree in snapsho...
[bcachefs-tools-debian] / libbcachefs / sb-errors.c
1 // SPDX-License-Identifier: GPL-2.0
2
3 #include "bcachefs.h"
4 #include "sb-errors.h"
5 #include "super-io.h"
6
7 static const char * const bch2_sb_error_strs[] = {
8 #define x(t, n, ...) [n] = #t,
9         BCH_SB_ERRS()
10         NULL
11 };
12
13 static void bch2_sb_error_id_to_text(struct printbuf *out, enum bch_sb_error_id id)
14 {
15         if (id < BCH_SB_ERR_MAX)
16                 prt_str(out, bch2_sb_error_strs[id]);
17         else
18                 prt_printf(out, "(unknown error %u)", id);
19 }
20
21 static inline unsigned bch2_sb_field_errors_nr_entries(struct bch_sb_field_errors *e)
22 {
23         return e
24                 ? (bch2_sb_field_bytes(&e->field) - sizeof(*e)) / sizeof(e->entries[0])
25                 : 0;
26 }
27
28 static inline unsigned bch2_sb_field_errors_u64s(unsigned nr)
29 {
30         return (sizeof(struct bch_sb_field_errors) +
31                 sizeof(struct bch_sb_field_error_entry) * nr) / sizeof(u64);
32 }
33
34 static int bch2_sb_errors_validate(struct bch_sb *sb, struct bch_sb_field *f,
35                                    struct printbuf *err)
36 {
37         struct bch_sb_field_errors *e = field_to_type(f, errors);
38         unsigned i, nr = bch2_sb_field_errors_nr_entries(e);
39
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]));
44                         prt_printf(err, ")");
45                         return -BCH_ERR_invalid_sb_errors;
46                 }
47
48                 if (i + 1 < nr &&
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;
53                 }
54         }
55
56         return 0;
57 }
58
59 static void bch2_sb_errors_to_text(struct printbuf *out, struct bch_sb *sb,
60                                    struct bch_sb_field *f)
61 {
62         struct bch_sb_field_errors *e = field_to_type(f, errors);
63         unsigned i, nr = bch2_sb_field_errors_nr_entries(e);
64         u64 now = ktime_get_real_seconds();
65
66         if (out->nr_tabstops <= 1)
67                 printbuf_tabstop_push(out, 16);
68
69         for (i = 0; i < nr; i++) {
70                 bch2_sb_error_id_to_text(out, BCH_SB_ERROR_ENTRY_ID(&e->entries[i]));
71                 prt_tab(out);
72                 prt_u64(out, BCH_SB_ERROR_ENTRY_NR(&e->entries[i]));
73                 prt_tab(out);
74                 bch2_pr_time_units(out, (now - le64_to_cpu(e->entries[i].last_error_time)) *
75                                    NSEC_PER_SEC);
76                 prt_str(out, " ago");
77                 prt_newline(out);
78         }
79 }
80
81 const struct bch_sb_field_ops bch_sb_field_ops_errors = {
82         .validate       = bch2_sb_errors_validate,
83         .to_text        = bch2_sb_errors_to_text,
84 };
85
86 void bch2_sb_error_count(struct bch_fs *c, enum bch_sb_error_id err)
87 {
88         bch_sb_errors_cpu *e = &c->fsck_error_counts;
89         struct bch_sb_error_entry_cpu n = {
90                 .id = err,
91                 .nr = 1,
92                 .last_error_time = ktime_get_real_seconds()
93         };
94         unsigned i;
95
96         mutex_lock(&c->fsck_error_counts_lock);
97         for (i = 0; i < e->nr; i++) {
98                 if (err == e->data[i].id) {
99                         e->data[i].nr++;
100                         e->data[i].last_error_time = n.last_error_time;
101                         goto out;
102                 }
103                 if (err < e->data[i].id)
104                         break;
105         }
106
107         if (darray_make_room(e, 1))
108                 goto out;
109
110         darray_insert_item(e, i, n);
111 out:
112         mutex_unlock(&c->fsck_error_counts_lock);
113 }
114
115 void bch2_sb_errors_from_cpu(struct bch_fs *c)
116 {
117         bch_sb_errors_cpu *src = &c->fsck_error_counts;
118         struct bch_sb_field_errors *dst =
119                 bch2_sb_field_resize(&c->disk_sb, errors,
120                                      bch2_sb_field_errors_u64s(src->nr));
121         unsigned i;
122
123         if (!dst)
124                 return;
125
126         for (i = 0; i < src->nr; i++) {
127                 SET_BCH_SB_ERROR_ENTRY_ID(&dst->entries[i], src->data[i].id);
128                 SET_BCH_SB_ERROR_ENTRY_NR(&dst->entries[i], src->data[i].nr);
129                 dst->entries[i].last_error_time = cpu_to_le64(src->data[i].last_error_time);
130         }
131 }
132
133 static int bch2_sb_errors_to_cpu(struct bch_fs *c)
134 {
135         struct bch_sb_field_errors *src = bch2_sb_field_get(c->disk_sb.sb, errors);
136         bch_sb_errors_cpu *dst = &c->fsck_error_counts;
137         unsigned i, nr = bch2_sb_field_errors_nr_entries(src);
138         int ret;
139
140         if (!nr)
141                 return 0;
142
143         mutex_lock(&c->fsck_error_counts_lock);
144         ret = darray_make_room(dst, nr);
145         if (ret)
146                 goto err;
147
148         dst->nr = nr;
149
150         for (i = 0; i < nr; i++) {
151                 dst->data[i].id = BCH_SB_ERROR_ENTRY_ID(&src->entries[i]);
152                 dst->data[i].nr = BCH_SB_ERROR_ENTRY_NR(&src->entries[i]);
153                 dst->data[i].last_error_time = le64_to_cpu(src->entries[i].last_error_time);
154         }
155 err:
156         mutex_unlock(&c->fsck_error_counts_lock);
157
158         return ret;
159 }
160
161 void bch2_fs_sb_errors_exit(struct bch_fs *c)
162 {
163         darray_exit(&c->fsck_error_counts);
164 }
165
166 void bch2_fs_sb_errors_init_early(struct bch_fs *c)
167 {
168         mutex_init(&c->fsck_error_counts_lock);
169         darray_init(&c->fsck_error_counts);
170 }
171
172 int bch2_fs_sb_errors_init(struct bch_fs *c)
173 {
174         return bch2_sb_errors_to_cpu(c);
175 }