Loading fs/bcachefs/disk_accounting.c +87 −0 Original line number Diff line number Diff line Loading @@ -588,6 +588,93 @@ int bch2_dev_usage_init(struct bch_dev *ca, bool gc) return ret; } void bch2_verify_accounting_clean(struct bch_fs *c) { bool mismatch = false; struct bch_fs_usage_base base = {}, base_inmem = {}; bch2_trans_run(c, for_each_btree_key(trans, iter, BTREE_ID_accounting, POS_MIN, BTREE_ITER_all_snapshots, k, ({ u64 v[BCH_ACCOUNTING_MAX_COUNTERS]; struct bkey_s_c_accounting a = bkey_s_c_to_accounting(k); unsigned nr = bch2_accounting_counters(k.k); bch2_accounting_mem_read(c, k.k->p, v, nr); if (memcmp(a.v->d, v, nr * sizeof(u64))) { struct printbuf buf = PRINTBUF; bch2_bkey_val_to_text(&buf, c, k); prt_str(&buf, " !="); for (unsigned j = 0; j < nr; j++) prt_printf(&buf, " %llu", v[j]); pr_err("%s", buf.buf); printbuf_exit(&buf); mismatch = true; } struct disk_accounting_pos acc_k; bpos_to_disk_accounting_pos(&acc_k, a.k->p); switch (acc_k.type) { case BCH_DISK_ACCOUNTING_persistent_reserved: base.reserved += acc_k.persistent_reserved.nr_replicas * a.v->d[0]; break; case BCH_DISK_ACCOUNTING_replicas: fs_usage_data_type_to_base(&base, acc_k.replicas.data_type, a.v->d[0]); break; case BCH_DISK_ACCOUNTING_dev_data_type: { rcu_read_lock(); struct bch_dev *ca = bch2_dev_rcu(c, acc_k.dev_data_type.dev); if (!ca) { rcu_read_unlock(); continue; } v[0] = percpu_u64_get(&ca->usage->d[acc_k.dev_data_type.data_type].buckets); v[1] = percpu_u64_get(&ca->usage->d[acc_k.dev_data_type.data_type].sectors); v[2] = percpu_u64_get(&ca->usage->d[acc_k.dev_data_type.data_type].fragmented); rcu_read_unlock(); if (memcmp(a.v->d, v, 3 * sizeof(u64))) { struct printbuf buf = PRINTBUF; bch2_bkey_val_to_text(&buf, c, k); prt_str(&buf, " in mem"); for (unsigned j = 0; j < nr; j++) prt_printf(&buf, " %llu", v[j]); pr_err("dev accounting mismatch: %s", buf.buf); printbuf_exit(&buf); mismatch = true; } } } 0; }))); acc_u64s_percpu(&base_inmem.hidden, &c->usage->hidden, sizeof(base_inmem) / sizeof(u64)); #define check(x) \ if (base.x != base_inmem.x) { \ pr_err("fs_usage_base.%s mismatch: %llu != %llu", #x, base.x, base_inmem.x); \ mismatch = true; \ } //check(hidden); check(btree); check(data); check(cached); check(reserved); check(nr_inodes); WARN_ON(mismatch); } void bch2_accounting_free(struct bch_accounting_mem *acc) { darray_exit(&acc->k); Loading fs/bcachefs/disk_accounting.h +3 −1 Original line number Diff line number Diff line Loading @@ -171,7 +171,7 @@ static inline void bch2_accounting_mem_read_counters(struct bch_fs *c, unsigned { memset(v, 0, sizeof(*v) * nr); struct bch_accounting_mem *acc = &c->accounting[0]; struct bch_accounting_mem *acc = &c->accounting[gc]; if (unlikely(idx >= acc->k.nr)) return; Loading Loading @@ -201,6 +201,8 @@ int bch2_accounting_read(struct bch_fs *); int bch2_dev_usage_remove(struct bch_fs *, unsigned); int bch2_dev_usage_init(struct bch_dev *, bool); void bch2_verify_accounting_clean(struct bch_fs *c); void bch2_accounting_free(struct bch_accounting_mem *); void bch2_fs_accounting_exit(struct bch_fs *); Loading fs/bcachefs/super.c +1 −0 Original line number Diff line number Diff line Loading @@ -361,6 +361,7 @@ void bch2_fs_read_only(struct bch_fs *c) BUG_ON(atomic_long_read(&c->btree_key_cache.nr_dirty)); BUG_ON(c->btree_write_buffer.inc.keys.nr); BUG_ON(c->btree_write_buffer.flushing.keys.nr); bch2_verify_accounting_clean(c); bch_verbose(c, "marking filesystem clean"); bch2_fs_mark_clean(c); Loading Loading
fs/bcachefs/disk_accounting.c +87 −0 Original line number Diff line number Diff line Loading @@ -588,6 +588,93 @@ int bch2_dev_usage_init(struct bch_dev *ca, bool gc) return ret; } void bch2_verify_accounting_clean(struct bch_fs *c) { bool mismatch = false; struct bch_fs_usage_base base = {}, base_inmem = {}; bch2_trans_run(c, for_each_btree_key(trans, iter, BTREE_ID_accounting, POS_MIN, BTREE_ITER_all_snapshots, k, ({ u64 v[BCH_ACCOUNTING_MAX_COUNTERS]; struct bkey_s_c_accounting a = bkey_s_c_to_accounting(k); unsigned nr = bch2_accounting_counters(k.k); bch2_accounting_mem_read(c, k.k->p, v, nr); if (memcmp(a.v->d, v, nr * sizeof(u64))) { struct printbuf buf = PRINTBUF; bch2_bkey_val_to_text(&buf, c, k); prt_str(&buf, " !="); for (unsigned j = 0; j < nr; j++) prt_printf(&buf, " %llu", v[j]); pr_err("%s", buf.buf); printbuf_exit(&buf); mismatch = true; } struct disk_accounting_pos acc_k; bpos_to_disk_accounting_pos(&acc_k, a.k->p); switch (acc_k.type) { case BCH_DISK_ACCOUNTING_persistent_reserved: base.reserved += acc_k.persistent_reserved.nr_replicas * a.v->d[0]; break; case BCH_DISK_ACCOUNTING_replicas: fs_usage_data_type_to_base(&base, acc_k.replicas.data_type, a.v->d[0]); break; case BCH_DISK_ACCOUNTING_dev_data_type: { rcu_read_lock(); struct bch_dev *ca = bch2_dev_rcu(c, acc_k.dev_data_type.dev); if (!ca) { rcu_read_unlock(); continue; } v[0] = percpu_u64_get(&ca->usage->d[acc_k.dev_data_type.data_type].buckets); v[1] = percpu_u64_get(&ca->usage->d[acc_k.dev_data_type.data_type].sectors); v[2] = percpu_u64_get(&ca->usage->d[acc_k.dev_data_type.data_type].fragmented); rcu_read_unlock(); if (memcmp(a.v->d, v, 3 * sizeof(u64))) { struct printbuf buf = PRINTBUF; bch2_bkey_val_to_text(&buf, c, k); prt_str(&buf, " in mem"); for (unsigned j = 0; j < nr; j++) prt_printf(&buf, " %llu", v[j]); pr_err("dev accounting mismatch: %s", buf.buf); printbuf_exit(&buf); mismatch = true; } } } 0; }))); acc_u64s_percpu(&base_inmem.hidden, &c->usage->hidden, sizeof(base_inmem) / sizeof(u64)); #define check(x) \ if (base.x != base_inmem.x) { \ pr_err("fs_usage_base.%s mismatch: %llu != %llu", #x, base.x, base_inmem.x); \ mismatch = true; \ } //check(hidden); check(btree); check(data); check(cached); check(reserved); check(nr_inodes); WARN_ON(mismatch); } void bch2_accounting_free(struct bch_accounting_mem *acc) { darray_exit(&acc->k); Loading
fs/bcachefs/disk_accounting.h +3 −1 Original line number Diff line number Diff line Loading @@ -171,7 +171,7 @@ static inline void bch2_accounting_mem_read_counters(struct bch_fs *c, unsigned { memset(v, 0, sizeof(*v) * nr); struct bch_accounting_mem *acc = &c->accounting[0]; struct bch_accounting_mem *acc = &c->accounting[gc]; if (unlikely(idx >= acc->k.nr)) return; Loading Loading @@ -201,6 +201,8 @@ int bch2_accounting_read(struct bch_fs *); int bch2_dev_usage_remove(struct bch_fs *, unsigned); int bch2_dev_usage_init(struct bch_dev *, bool); void bch2_verify_accounting_clean(struct bch_fs *c); void bch2_accounting_free(struct bch_accounting_mem *); void bch2_fs_accounting_exit(struct bch_fs *); Loading
fs/bcachefs/super.c +1 −0 Original line number Diff line number Diff line Loading @@ -361,6 +361,7 @@ void bch2_fs_read_only(struct bch_fs *c) BUG_ON(atomic_long_read(&c->btree_key_cache.nr_dirty)); BUG_ON(c->btree_write_buffer.inc.keys.nr); BUG_ON(c->btree_write_buffer.flushing.keys.nr); bch2_verify_accounting_clean(c); bch_verbose(c, "marking filesystem clean"); bch2_fs_mark_clean(c); Loading