1 // SPDX-License-Identifier: GPL-2.0
7 const char * const bch2_sb_error_strs
[] = {
8 #define x(t, n, ...) [n] = #t,
13 void bch2_sb_error_id_to_text(struct printbuf
*out
, enum bch_sb_error_id id
)
15 if (id
< BCH_FSCK_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
)
23 return bch2_sb_field_nr_entries(e
);
26 static inline unsigned bch2_sb_field_errors_u64s(unsigned nr
)
28 return (sizeof(struct bch_sb_field_errors
) +
29 sizeof(struct bch_sb_field_error_entry
) * nr
) / sizeof(u64
);
32 static int bch2_sb_errors_validate(struct bch_sb
*sb
, struct bch_sb_field
*f
,
33 enum bch_validate_flags flags
, struct printbuf
*err
)
35 struct bch_sb_field_errors
*e
= field_to_type(f
, errors
);
36 unsigned i
, nr
= bch2_sb_field_errors_nr_entries(e
);
38 for (i
= 0; i
< nr
; i
++) {
39 if (!BCH_SB_ERROR_ENTRY_NR(&e
->entries
[i
])) {
40 prt_printf(err
, "entry with count 0 (id ");
41 bch2_sb_error_id_to_text(err
, BCH_SB_ERROR_ENTRY_ID(&e
->entries
[i
]));
43 return -BCH_ERR_invalid_sb_errors
;
47 BCH_SB_ERROR_ENTRY_ID(&e
->entries
[i
]) >=
48 BCH_SB_ERROR_ENTRY_ID(&e
->entries
[i
+ 1])) {
49 prt_printf(err
, "entries out of order");
50 return -BCH_ERR_invalid_sb_errors
;
57 static void bch2_sb_errors_to_text(struct printbuf
*out
, struct bch_sb
*sb
,
58 struct bch_sb_field
*f
)
60 struct bch_sb_field_errors
*e
= field_to_type(f
, errors
);
61 unsigned i
, nr
= bch2_sb_field_errors_nr_entries(e
);
63 if (out
->nr_tabstops
<= 1)
64 printbuf_tabstop_push(out
, 16);
66 for (i
= 0; i
< nr
; i
++) {
67 bch2_sb_error_id_to_text(out
, BCH_SB_ERROR_ENTRY_ID(&e
->entries
[i
]));
69 prt_u64(out
, BCH_SB_ERROR_ENTRY_NR(&e
->entries
[i
]));
71 bch2_prt_datetime(out
, le64_to_cpu(e
->entries
[i
].last_error_time
));
76 const struct bch_sb_field_ops bch_sb_field_ops_errors
= {
77 .validate
= bch2_sb_errors_validate
,
78 .to_text
= bch2_sb_errors_to_text
,
81 void bch2_sb_error_count(struct bch_fs
*c
, enum bch_sb_error_id err
)
83 bch_sb_errors_cpu
*e
= &c
->fsck_error_counts
;
84 struct bch_sb_error_entry_cpu n
= {
87 .last_error_time
= ktime_get_real_seconds()
91 mutex_lock(&c
->fsck_error_counts_lock
);
92 for (i
= 0; i
< e
->nr
; i
++) {
93 if (err
== e
->data
[i
].id
) {
95 e
->data
[i
].last_error_time
= n
.last_error_time
;
98 if (err
< e
->data
[i
].id
)
102 if (darray_make_room(e
, 1))
105 darray_insert_item(e
, i
, n
);
107 mutex_unlock(&c
->fsck_error_counts_lock
);
110 void bch2_sb_errors_from_cpu(struct bch_fs
*c
)
112 bch_sb_errors_cpu
*src
= &c
->fsck_error_counts
;
113 struct bch_sb_field_errors
*dst
;
116 mutex_lock(&c
->fsck_error_counts_lock
);
118 dst
= bch2_sb_field_resize(&c
->disk_sb
, errors
,
119 bch2_sb_field_errors_u64s(src
->nr
));
124 for (i
= 0; i
< src
->nr
; i
++) {
125 SET_BCH_SB_ERROR_ENTRY_ID(&dst
->entries
[i
], src
->data
[i
].id
);
126 SET_BCH_SB_ERROR_ENTRY_NR(&dst
->entries
[i
], src
->data
[i
].nr
);
127 dst
->entries
[i
].last_error_time
= cpu_to_le64(src
->data
[i
].last_error_time
);
131 mutex_unlock(&c
->fsck_error_counts_lock
);
134 static int bch2_sb_errors_to_cpu(struct bch_fs
*c
)
136 struct bch_sb_field_errors
*src
= bch2_sb_field_get(c
->disk_sb
.sb
, errors
);
137 bch_sb_errors_cpu
*dst
= &c
->fsck_error_counts
;
138 unsigned i
, nr
= bch2_sb_field_errors_nr_entries(src
);
144 mutex_lock(&c
->fsck_error_counts_lock
);
145 ret
= darray_make_room(dst
, nr
);
151 for (i
= 0; i
< nr
; i
++) {
152 dst
->data
[i
].id
= BCH_SB_ERROR_ENTRY_ID(&src
->entries
[i
]);
153 dst
->data
[i
].nr
= BCH_SB_ERROR_ENTRY_NR(&src
->entries
[i
]);
154 dst
->data
[i
].last_error_time
= le64_to_cpu(src
->entries
[i
].last_error_time
);
157 mutex_unlock(&c
->fsck_error_counts_lock
);
162 void bch2_fs_sb_errors_exit(struct bch_fs
*c
)
164 darray_exit(&c
->fsck_error_counts
);
167 void bch2_fs_sb_errors_init_early(struct bch_fs
*c
)
169 mutex_init(&c
->fsck_error_counts_lock
);
170 darray_init(&c
->fsck_error_counts
);
173 int bch2_fs_sb_errors_init(struct bch_fs
*c
)
175 return bch2_sb_errors_to_cpu(c
);