Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v6.7-rc2 172 lines 4.3 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2 3#include "bcachefs.h" 4#include "sb-errors.h" 5#include "super-io.h" 6 7static const char * const bch2_sb_error_strs[] = { 8#define x(t, n, ...) [n] = #t, 9 BCH_SB_ERRS() 10 NULL 11}; 12 13static 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 21static 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 28static 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 34static 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 59static 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 65 if (out->nr_tabstops <= 1) 66 printbuf_tabstop_push(out, 16); 67 68 for (i = 0; i < nr; i++) { 69 bch2_sb_error_id_to_text(out, BCH_SB_ERROR_ENTRY_ID(&e->entries[i])); 70 prt_tab(out); 71 prt_u64(out, BCH_SB_ERROR_ENTRY_NR(&e->entries[i])); 72 prt_tab(out); 73 bch2_prt_datetime(out, le64_to_cpu(e->entries[i].last_error_time)); 74 prt_newline(out); 75 } 76} 77 78const struct bch_sb_field_ops bch_sb_field_ops_errors = { 79 .validate = bch2_sb_errors_validate, 80 .to_text = bch2_sb_errors_to_text, 81}; 82 83void bch2_sb_error_count(struct bch_fs *c, enum bch_sb_error_id err) 84{ 85 bch_sb_errors_cpu *e = &c->fsck_error_counts; 86 struct bch_sb_error_entry_cpu n = { 87 .id = err, 88 .nr = 1, 89 .last_error_time = ktime_get_real_seconds() 90 }; 91 unsigned i; 92 93 mutex_lock(&c->fsck_error_counts_lock); 94 for (i = 0; i < e->nr; i++) { 95 if (err == e->data[i].id) { 96 e->data[i].nr++; 97 e->data[i].last_error_time = n.last_error_time; 98 goto out; 99 } 100 if (err < e->data[i].id) 101 break; 102 } 103 104 if (darray_make_room(e, 1)) 105 goto out; 106 107 darray_insert_item(e, i, n); 108out: 109 mutex_unlock(&c->fsck_error_counts_lock); 110} 111 112void bch2_sb_errors_from_cpu(struct bch_fs *c) 113{ 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)); 118 unsigned i; 119 120 if (!dst) 121 return; 122 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); 127 } 128} 129 130static int bch2_sb_errors_to_cpu(struct bch_fs *c) 131{ 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); 135 int ret; 136 137 if (!nr) 138 return 0; 139 140 mutex_lock(&c->fsck_error_counts_lock); 141 ret = darray_make_room(dst, nr); 142 if (ret) 143 goto err; 144 145 dst->nr = nr; 146 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); 151 } 152err: 153 mutex_unlock(&c->fsck_error_counts_lock); 154 155 return ret; 156} 157 158void bch2_fs_sb_errors_exit(struct bch_fs *c) 159{ 160 darray_exit(&c->fsck_error_counts); 161} 162 163void bch2_fs_sb_errors_init_early(struct bch_fs *c) 164{ 165 mutex_init(&c->fsck_error_counts_lock); 166 darray_init(&c->fsck_error_counts); 167} 168 169int bch2_fs_sb_errors_init(struct bch_fs *c) 170{ 171 return bch2_sb_errors_to_cpu(c); 172}