diff options
| author | Kent Overstreet <kent.overstreet@linux.dev> | 2023-11-09 14:22:46 -0500 |
|---|---|---|
| committer | Kent Overstreet <kent.overstreet@linux.dev> | 2024-07-14 19:00:13 -0400 |
| commit | 1d16c605cc55ef26f0c65b362665a6c99080ccbc (patch) | |
| tree | c7f7f6b6209ac290185dbea26a1f9d59661ac95f /fs/bcachefs/disk_accounting.h | |
| parent | 5d9667d1d6eaca3f6cd3c63cd6a0f309147c7f5c (diff) | |
bcachefs: Disk space accounting rewrite
Main part of the disk accounting rewrite.
This is a wholesale rewrite of the existing disk space accounting, which
relies on percepu counters that are sharded by journal buffer, and
rolled up and added to each journal write.
With the new scheme, every set of counters is a distinct key in the
accounting btree; this fixes scaling limitations of the old scheme,
where counters took up space in each journal entry and required multiple
percpu counters.
Now, in memory accounting requires a single set of percpu counters - not
multiple for each in flight journal buffer - and in the future we'll
probably also have counters that don't use in memory percpu counters,
they're not strictly required.
An accounting update is now a normal btree update, using the btree write
buffer path. At transaction commit time, we apply accounting updates to
the in memory counters, which are percpu counters indexed in an
eytzinger tree by the accounting key.
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Diffstat (limited to 'fs/bcachefs/disk_accounting.h')
| -rw-r--r-- | fs/bcachefs/disk_accounting.h | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/fs/bcachefs/disk_accounting.h b/fs/bcachefs/disk_accounting.h index 178ec25b7ef4..ec1b8ae2aeee 100644 --- a/fs/bcachefs/disk_accounting.h +++ b/fs/bcachefs/disk_accounting.h @@ -2,11 +2,32 @@ #ifndef _BCACHEFS_DISK_ACCOUNTING_H #define _BCACHEFS_DISK_ACCOUNTING_H +#include "eytzinger.h" + +static inline void bch2_u64s_neg(u64 *v, unsigned nr) +{ + for (unsigned i = 0; i < nr; i++) + v[i] = -v[i]; +} + static inline unsigned bch2_accounting_counters(const struct bkey *k) { return bkey_val_u64s(k) - offsetof(struct bch_accounting, d) / sizeof(u64); } +static inline void bch2_accounting_neg(struct bkey_s_accounting a) +{ + bch2_u64s_neg(a.v->d, bch2_accounting_counters(a.k)); +} + +static inline bool bch2_accounting_key_is_zero(struct bkey_s_c_accounting a) +{ + for (unsigned i = 0; i < bch2_accounting_counters(a.k); i++) + if (a.v->d[i]) + return false; + return true; +} + static inline void bch2_accounting_accumulate(struct bkey_i_accounting *dst, struct bkey_s_c_accounting src) { @@ -18,6 +39,26 @@ static inline void bch2_accounting_accumulate(struct bkey_i_accounting *dst, dst->k.version = src.k->version; } +static inline void fs_usage_data_type_to_base(struct bch_fs_usage_base *fs_usage, + enum bch_data_type data_type, + s64 sectors) +{ + switch (data_type) { + case BCH_DATA_btree: + fs_usage->btree += sectors; + break; + case BCH_DATA_user: + case BCH_DATA_parity: + fs_usage->data += sectors; + break; + case BCH_DATA_cached: + fs_usage->cached += sectors; + break; + default: + break; + } +} + static inline void bpos_to_disk_accounting_pos(struct disk_accounting_pos *acc, struct bpos p) { acc->_pad = p; @@ -36,6 +77,12 @@ static inline struct bpos disk_accounting_pos_to_bpos(struct disk_accounting_pos return ret; } +int bch2_disk_accounting_mod(struct btree_trans *, + struct disk_accounting_pos *, + s64 *, unsigned); +int bch2_mod_dev_cached_sectors(struct btree_trans *trans, + unsigned dev, s64 sectors); + int bch2_accounting_invalid(struct bch_fs *, struct bkey_s_c, enum bch_validate_flags, struct printbuf *); void bch2_accounting_key_to_text(struct printbuf *, struct disk_accounting_pos *); @@ -49,4 +96,88 @@ void bch2_accounting_swab(struct bkey_s); .min_val_size = 8, \ }) +int bch2_accounting_update_sb(struct btree_trans *); + +static inline int accounting_pos_cmp(const void *_l, const void *_r) +{ + const struct bpos *l = _l, *r = _r; + + return bpos_cmp(*l, *r); +} + +int bch2_accounting_mem_mod_slowpath(struct bch_fs *, struct bkey_s_c_accounting); + +static inline int __bch2_accounting_mem_mod(struct bch_fs *c, struct bkey_s_c_accounting a) +{ + struct bch_accounting_mem *acc = &c->accounting; + unsigned idx = eytzinger0_find(acc->k.data, acc->k.nr, sizeof(acc->k.data[0]), + accounting_pos_cmp, &a.k->p); + if (unlikely(idx >= acc->k.nr)) + return bch2_accounting_mem_mod_slowpath(c, a); + + unsigned offset = acc->k.data[idx].offset; + + EBUG_ON(bch2_accounting_counters(a.k) != acc->k.data[idx].nr_counters); + + for (unsigned i = 0; i < bch2_accounting_counters(a.k); i++) + this_cpu_add(acc->v[offset + i], a.v->d[i]); + return 0; +} + +/* + * Update in memory counters so they match the btree update we're doing; called + * from transaction commit path + */ +static inline int bch2_accounting_mem_mod(struct btree_trans *trans, struct + bkey_s_c_accounting a) +{ + 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: + trans->fs_usage_delta.reserved += acc_k.persistent_reserved.nr_replicas * a.v->d[0]; + break; + case BCH_DISK_ACCOUNTING_replicas: + fs_usage_data_type_to_base(&trans->fs_usage_delta, acc_k.replicas.data_type, a.v->d[0]); + break; + } + return __bch2_accounting_mem_mod(trans->c, a); +} + +static inline void bch2_accounting_mem_read_counters(struct bch_fs *c, + unsigned idx, + u64 *v, unsigned nr) +{ + memset(v, 0, sizeof(*v) * nr); + + struct bch_accounting_mem *acc = &c->accounting; + if (unlikely(idx >= acc->k.nr)) + return; + + unsigned offset = acc->k.data[idx].offset; + nr = min_t(unsigned, nr, acc->k.data[idx].nr_counters); + + for (unsigned i = 0; i < nr; i++) + v[i] = percpu_u64_get(acc->v + offset + i); +} + +static inline void bch2_accounting_mem_read(struct bch_fs *c, struct bpos p, + u64 *v, unsigned nr) +{ + struct bch_accounting_mem *acc = &c->accounting; + unsigned idx = eytzinger0_find(acc->k.data, acc->k.nr, sizeof(acc->k.data[0]), + accounting_pos_cmp, &p); + + bch2_accounting_mem_read_counters(c, idx, v, nr); +} + +int bch2_fs_replicas_usage_read(struct bch_fs *, darray_char *); + +int bch2_accounting_read(struct bch_fs *); + +int bch2_dev_usage_remove(struct bch_fs *, unsigned); +int bch2_dev_usage_init(struct bch_dev *); +void bch2_fs_accounting_exit(struct bch_fs *); + #endif /* _BCACHEFS_DISK_ACCOUNTING_H */ |
