diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2019-01-21 15:32:13 -0500 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2023-10-22 17:08:14 -0400 |
commit | 7ef2a73a5881323d53453cc3be7261fe1a49af1d (patch) | |
tree | 85e8d67b00a6c28dd8691e79d1674c111e8a1328 /fs/bcachefs/replicas.c | |
parent | dbaee468461bfa82e6453ca0e009e9661cc570da (diff) | |
download | lwn-7ef2a73a5881323d53453cc3be7261fe1a49af1d.tar.gz lwn-7ef2a73a5881323d53453cc3be7261fe1a49af1d.zip |
bcachefs: Fix check for if extent update is allocating
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Diffstat (limited to 'fs/bcachefs/replicas.c')
-rw-r--r-- | fs/bcachefs/replicas.c | 280 |
1 files changed, 188 insertions, 92 deletions
diff --git a/fs/bcachefs/replicas.c b/fs/bcachefs/replicas.c index b63da1bef760..34a5475cfaba 100644 --- a/fs/bcachefs/replicas.c +++ b/fs/bcachefs/replicas.c @@ -4,11 +4,6 @@ #include "replicas.h" #include "super-io.h" -struct bch_replicas_padded { - struct bch_replicas_entry e; - u8 pad[BCH_SB_MEMBERS_MAX]; -}; - static int bch2_cpu_replicas_to_sb_replicas(struct bch_fs *, struct bch_replicas_cpu *); @@ -19,6 +14,16 @@ static inline int u8_cmp(u8 l, u8 r) return (l > r) - (l < r); } +static void verify_replicas_entry_sorted(struct bch_replicas_entry *e) +{ +#ifdef CONFIG_BCACHES_DEBUG + unsigned i; + + for (i = 0; i + 1 < e->nr_devs; i++) + BUG_ON(e->devs[i] >= e->devs[i + 1]); +#endif +} + static void replicas_entry_sort(struct bch_replicas_entry *e) { bubble_sort(e->devs, e->nr_devs, u8_cmp); @@ -29,19 +34,13 @@ static void replicas_entry_sort(struct bch_replicas_entry *e) (void *) (_i) < (void *) (_r)->entries + (_r)->nr * (_r)->entry_size;\ _i = (void *) (_i) + (_r)->entry_size) -static inline struct bch_replicas_entry * -cpu_replicas_entry(struct bch_replicas_cpu *r, unsigned i) -{ - return (void *) r->entries + r->entry_size * i; -} - static void bch2_cpu_replicas_sort(struct bch_replicas_cpu *r) { eytzinger0_sort(r->entries, r->nr, r->entry_size, memcmp, NULL); } -static void replicas_entry_to_text(struct printbuf *out, - struct bch_replicas_entry *e) +void bch2_replicas_entry_to_text(struct printbuf *out, + struct bch_replicas_entry *e) { unsigned i; @@ -66,7 +65,7 @@ void bch2_cpu_replicas_to_text(struct printbuf *out, pr_buf(out, " "); first = false; - replicas_entry_to_text(out, e); + bch2_replicas_entry_to_text(out, e); } } @@ -106,8 +105,8 @@ static void stripe_to_replicas(struct bkey_s_c k, r->devs[r->nr_devs++] = ptr->dev; } -static void bkey_to_replicas(struct bkey_s_c k, - struct bch_replicas_entry *e) +static void bkey_to_replicas(struct bch_replicas_entry *e, + struct bkey_s_c k) { e->nr_devs = 0; @@ -129,9 +128,9 @@ static void bkey_to_replicas(struct bkey_s_c k, replicas_entry_sort(e); } -static inline void devlist_to_replicas(struct bch_devs_list devs, - enum bch_data_type data_type, - struct bch_replicas_entry *e) +void bch2_devlist_to_replicas(struct bch_replicas_entry *e, + enum bch_data_type data_type, + struct bch_devs_list devs) { unsigned i; @@ -160,6 +159,9 @@ cpu_replicas_add_entry(struct bch_replicas_cpu *old, replicas_entry_bytes(new_entry)), }; + BUG_ON(!new_entry->data_type); + verify_replicas_entry_sorted(new_entry); + new.entries = kcalloc(new.nr, new.entry_size, GFP_NOIO); if (!new.entries) return new; @@ -177,21 +179,49 @@ cpu_replicas_add_entry(struct bch_replicas_cpu *old, return new; } +static inline int __replicas_entry_idx(struct bch_replicas_cpu *r, + struct bch_replicas_entry *search) +{ + int idx, entry_size = replicas_entry_bytes(search); + + if (unlikely(entry_size > r->entry_size)) + return -1; + + verify_replicas_entry_sorted(search); + +#define entry_cmp(_l, _r, size) memcmp(_l, _r, entry_size) + idx = eytzinger0_find(r->entries, r->nr, r->entry_size, + entry_cmp, search); +#undef entry_cmp + + return idx < r->nr ? idx : -1; +} + +int bch2_replicas_entry_idx(struct bch_fs *c, + struct bch_replicas_entry *search) +{ + replicas_entry_sort(search); + + return __replicas_entry_idx(&c->replicas, search); +} + static bool __replicas_has_entry(struct bch_replicas_cpu *r, struct bch_replicas_entry *search) { - return replicas_entry_bytes(search) <= r->entry_size && - eytzinger0_find(r->entries, r->nr, - r->entry_size, - memcmp, search) < r->nr; + return __replicas_entry_idx(r, search) >= 0; } -static bool replicas_has_entry(struct bch_fs *c, - struct bch_replicas_entry *search, - bool check_gc_replicas) +bool bch2_replicas_marked(struct bch_fs *c, + struct bch_replicas_entry *search, + bool check_gc_replicas) { bool marked; + if (!search->nr_devs) + return true; + + verify_replicas_entry_sorted(search); + percpu_down_read(&c->mark_lock); marked = __replicas_has_entry(&c->replicas, search) && (!check_gc_replicas || @@ -202,6 +232,76 @@ static bool replicas_has_entry(struct bch_fs *c, return marked; } +static void __replicas_table_update(struct bch_fs_usage __percpu *dst_p, + struct bch_replicas_cpu *dst_r, + struct bch_fs_usage __percpu *src_p, + struct bch_replicas_cpu *src_r) +{ + unsigned src_nr = sizeof(struct bch_fs_usage) / sizeof(u64) + src_r->nr; + struct bch_fs_usage *dst, *src = (void *) + bch2_acc_percpu_u64s((void *) src_p, src_nr); + int src_idx, dst_idx; + + preempt_disable(); + dst = this_cpu_ptr(dst_p); + preempt_enable(); + + *dst = *src; + + for (src_idx = 0; src_idx < src_r->nr; src_idx++) { + if (!src->data[src_idx]) + continue; + + dst_idx = __replicas_entry_idx(dst_r, + cpu_replicas_entry(src_r, src_idx)); + BUG_ON(dst_idx < 0); + + dst->data[dst_idx] = src->data[src_idx]; + } +} + +/* + * Resize filesystem accounting: + */ +static int replicas_table_update(struct bch_fs *c, + struct bch_replicas_cpu *new_r) +{ + struct bch_fs_usage __percpu *new_usage[3] = { NULL, NULL, NULL }; + unsigned bytes = sizeof(struct bch_fs_usage) + + sizeof(u64) * new_r->nr; + unsigned i; + int ret = -ENOMEM; + + for (i = 0; i < 3; i++) { + if (i < 2 && !c->usage[i]) + continue; + + new_usage[i] = __alloc_percpu_gfp(bytes, sizeof(u64), + GFP_NOIO); + if (!new_usage[i]) + goto err; + } + + for (i = 0; i < 2; i++) { + if (!c->usage[i]) + continue; + + __replicas_table_update(new_usage[i], new_r, + c->usage[i], &c->replicas); + + swap(c->usage[i], new_usage[i]); + } + + swap(c->usage_scratch, new_usage[2]); + + swap(c->replicas, *new_r); + ret = 0; +err: + for (i = 0; i < 3; i++) + free_percpu(new_usage[i]); + return ret; +} + noinline static int bch2_mark_replicas_slowpath(struct bch_fs *c, struct bch_replicas_entry *new_entry) @@ -243,7 +343,7 @@ static int bch2_mark_replicas_slowpath(struct bch_fs *c, /* don't update in memory replicas until changes are persistent */ percpu_down_write(&c->mark_lock); if (new_r.entries) - swap(new_r, c->replicas); + ret = replicas_table_update(c, &new_r); if (new_gc.entries) swap(new_gc, c->replicas_gc); percpu_up_write(&c->mark_lock); @@ -258,30 +358,32 @@ err: return ret; } -static int __bch2_mark_replicas(struct bch_fs *c, - struct bch_replicas_entry *devs) +int bch2_mark_replicas(struct bch_fs *c, + struct bch_replicas_entry *r) { - return likely(replicas_has_entry(c, devs, true)) + return likely(bch2_replicas_marked(c, r, true)) ? 0 - : bch2_mark_replicas_slowpath(c, devs); + : bch2_mark_replicas_slowpath(c, r); } -int bch2_mark_replicas(struct bch_fs *c, - enum bch_data_type data_type, - struct bch_devs_list devs) +bool bch2_bkey_replicas_marked(struct bch_fs *c, + struct bkey_s_c k, + bool check_gc_replicas) { struct bch_replicas_padded search; + struct bch_devs_list cached = bch2_bkey_cached_devs(k); + unsigned i; - if (!devs.nr) - return 0; - - memset(&search, 0, sizeof(search)); + for (i = 0; i < cached.nr; i++) { + bch2_replicas_entry_cached(&search.e, cached.devs[i]); - BUG_ON(devs.nr >= BCH_REPLICAS_MAX); + if (!bch2_replicas_marked(c, &search.e, check_gc_replicas)) + return false; + } - devlist_to_replicas(devs, data_type, &search.e); + bkey_to_replicas(&search.e, k); - return __bch2_mark_replicas(c, &search.e); + return bch2_replicas_marked(c, &search.e, check_gc_replicas); } int bch2_mark_bkey_replicas(struct bch_fs *c, struct bkey_s_c k) @@ -291,22 +393,23 @@ int bch2_mark_bkey_replicas(struct bch_fs *c, struct bkey_s_c k) unsigned i; int ret; - memset(&search, 0, sizeof(search)); + for (i = 0; i < cached.nr; i++) { + bch2_replicas_entry_cached(&search.e, cached.devs[i]); - for (i = 0; i < cached.nr; i++) - if ((ret = bch2_mark_replicas(c, BCH_DATA_CACHED, - bch2_dev_list_single(cached.devs[i])))) + ret = bch2_mark_replicas(c, &search.e); + if (ret) return ret; + } - bkey_to_replicas(k, &search.e); + bkey_to_replicas(&search.e, k); - return search.e.nr_devs - ? __bch2_mark_replicas(c, &search.e) - : 0; + return bch2_mark_replicas(c, &search.e); } int bch2_replicas_gc_end(struct bch_fs *c, int ret) { + unsigned i; + lockdep_assert_held(&c->replicas_gc_lock); mutex_lock(&c->sb_lock); @@ -314,6 +417,39 @@ int bch2_replicas_gc_end(struct bch_fs *c, int ret) if (ret) goto err; + /* + * this is kind of crappy; the replicas gc mechanism needs to be ripped + * out + */ + + for (i = 0; i < c->replicas.nr; i++) { + struct bch_replicas_entry *e = + cpu_replicas_entry(&c->replicas, i); + struct bch_replicas_cpu n; + u64 v = 0; + int cpu; + + if (__replicas_has_entry(&c->replicas_gc, e)) + continue; + + for_each_possible_cpu(cpu) + v += *per_cpu_ptr(&c->usage[0]->data[i], cpu); + if (!v) + continue; + + n = cpu_replicas_add_entry(&c->replicas_gc, e); + if (!n.entries) { + ret = -ENOSPC; + goto err; + } + + percpu_down_write(&c->mark_lock); + swap(n, c->replicas_gc); + percpu_up_write(&c->mark_lock); + + kfree(n.entries); + } + if (bch2_cpu_replicas_to_sb_replicas(c, &c->replicas_gc)) { ret = -ENOSPC; goto err; @@ -325,7 +461,7 @@ int bch2_replicas_gc_end(struct bch_fs *c, int ret) err: percpu_down_write(&c->mark_lock); if (!ret) - swap(c->replicas, c->replicas_gc); + ret = replicas_table_update(c, &c->replicas_gc); kfree(c->replicas_gc.entries); c->replicas_gc.entries = NULL; @@ -461,7 +597,7 @@ int bch2_sb_replicas_to_cpu_replicas(struct bch_fs *c) bch2_cpu_replicas_sort(&new_r); percpu_down_write(&c->mark_lock); - swap(c->replicas, new_r); + ret = replicas_table_update(c, &new_r); percpu_up_write(&c->mark_lock); kfree(new_r.entries); @@ -628,7 +764,7 @@ static void bch2_sb_replicas_to_text(struct printbuf *out, pr_buf(out, " "); first = false; - replicas_entry_to_text(out, e); + bch2_replicas_entry_to_text(out, e); } } @@ -677,46 +813,6 @@ const struct bch_sb_field_ops bch_sb_field_ops_replicas_v0 = { /* Query replicas: */ -bool bch2_replicas_marked(struct bch_fs *c, - enum bch_data_type data_type, - struct bch_devs_list devs, - bool check_gc_replicas) -{ - struct bch_replicas_padded search; - - if (!devs.nr) - return true; - - memset(&search, 0, sizeof(search)); - - devlist_to_replicas(devs, data_type, &search.e); - - return replicas_has_entry(c, &search.e, check_gc_replicas); -} - -bool bch2_bkey_replicas_marked(struct bch_fs *c, - struct bkey_s_c k, - bool check_gc_replicas) -{ - struct bch_replicas_padded search; - struct bch_devs_list cached = bch2_bkey_cached_devs(k); - unsigned i; - - memset(&search, 0, sizeof(search)); - - for (i = 0; i < cached.nr; i++) - if (!bch2_replicas_marked(c, BCH_DATA_CACHED, - bch2_dev_list_single(cached.devs[i]), - check_gc_replicas)) - return false; - - bkey_to_replicas(k, &search.e); - - return search.e.nr_devs - ? replicas_has_entry(c, &search.e, check_gc_replicas) - : true; -} - struct replicas_status __bch2_replicas_status(struct bch_fs *c, struct bch_devs_mask online_devs) { |