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