From cb66fc5fe4cc806d60d8884cb82b67c357b49640 Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Tue, 13 Apr 2021 09:49:23 -0400 Subject: [PATCH] bcachefs: Fix copygc threshold Awhile back the meaning of is_available_bucket() and thus also bch_dev_usage->buckets_unavailable changed to include buckets that are owned by the allocator - this was so that the stat could be persisted like other allocation information, and wouldn't have to be regenerated by walking each bucket at mount time. This broke copygc, which needs to consider buckets that are reclaimable and haven't yet been grabbed by the allocator thread and moved onta freelist. This patch fixes that by adding dev_buckets_reclaimable() for copygc and the allocator thread, and cleans up some of the callers a bit. Signed-off-by: Kent Overstreet Signed-off-by: Kent Overstreet --- fs/bcachefs/alloc_background.c | 19 ++++--------------- fs/bcachefs/alloc_foreground.c | 5 ++++- fs/bcachefs/bcachefs.h | 2 +- fs/bcachefs/buckets.h | 26 ++++++++++++++++---------- fs/bcachefs/movinggc.c | 5 ++--- fs/bcachefs/sysfs.c | 9 ++++++--- 6 files changed, 33 insertions(+), 33 deletions(-) diff --git a/fs/bcachefs/alloc_background.c b/fs/bcachefs/alloc_background.c index f2117084f2fed..f603fd347d582 100644 --- a/fs/bcachefs/alloc_background.c +++ b/fs/bcachefs/alloc_background.c @@ -46,7 +46,7 @@ static void pd_controllers_update(struct work_struct *work) struct bch_dev_usage stats = bch2_dev_usage_read(ca); free += bucket_to_sector(ca, - __dev_buckets_free(ca, stats)) << 9; + __dev_buckets_available(ca, stats)) << 9; /* * Bytes of internal fragmentation, which can be * reclaimed by copy GC @@ -499,7 +499,6 @@ static int wait_buckets_available(struct bch_fs *c, struct bch_dev *ca) { unsigned long gc_count = c->gc_count; s64 available; - unsigned i; int ret = 0; ca->allocator_state = ALLOCATOR_BLOCKED; @@ -515,19 +514,12 @@ static int wait_buckets_available(struct bch_fs *c, struct bch_dev *ca) if (gc_count != c->gc_count) ca->inc_gen_really_needs_gc = 0; - available = dev_buckets_available(ca); + available = dev_buckets_reclaimable(ca); available -= ca->inc_gen_really_needs_gc; - spin_lock(&c->freelist_lock); - for (i = 0; i < RESERVE_NR; i++) - available -= fifo_used(&ca->free[i]); - spin_unlock(&c->freelist_lock); - available = max(available, 0LL); - if (available > fifo_free(&ca->free_inc) || - (available && - !fifo_full(&ca->free[RESERVE_MOVINGGC]))) + if (available) break; up_read(&c->gc_lock); @@ -1189,7 +1181,7 @@ stop: void bch2_recalc_capacity(struct bch_fs *c) { struct bch_dev *ca; - u64 capacity = 0, reserved_sectors = 0, gc_reserve, copygc_threshold = 0; + u64 capacity = 0, reserved_sectors = 0, gc_reserve; unsigned bucket_size_max = 0; unsigned long ra_pages = 0; unsigned i, j; @@ -1232,8 +1224,6 @@ void bch2_recalc_capacity(struct bch_fs *c) dev_reserve *= ca->mi.bucket_size; - copygc_threshold += dev_reserve; - capacity += bucket_to_sector(ca, ca->mi.nbuckets - ca->mi.first_bucket); @@ -1251,7 +1241,6 @@ void bch2_recalc_capacity(struct bch_fs *c) reserved_sectors = min(reserved_sectors, capacity); - c->copygc_threshold = copygc_threshold; c->capacity = capacity - reserved_sectors; c->bucket_size_max = bucket_size_max; diff --git a/fs/bcachefs/alloc_foreground.c b/fs/bcachefs/alloc_foreground.c index 97b692bcfe463..4834ac798b9e9 100644 --- a/fs/bcachefs/alloc_foreground.c +++ b/fs/bcachefs/alloc_foreground.c @@ -109,7 +109,9 @@ void __bch2_open_bucket_put(struct bch_fs *c, struct open_bucket *ob) spin_lock(&c->freelist_lock); ob->freelist = c->open_buckets_freelist; c->open_buckets_freelist = ob - c->open_buckets; + c->open_buckets_nr_free++; + ca->nr_open_buckets--; spin_unlock(&c->freelist_lock); closure_wake_up(&c->open_buckets_wait); @@ -316,6 +318,7 @@ out: c->blocked_allocate = 0; } + ca->nr_open_buckets++; spin_unlock(&c->freelist_lock); bch2_wake_allocator(ca); @@ -351,7 +354,7 @@ void bch2_dev_stripe_increment(struct bch_dev *ca, struct dev_stripe_state *stripe) { u64 *v = stripe->next_alloc + ca->dev_idx; - u64 free_space = dev_buckets_free(ca); + u64 free_space = dev_buckets_available(ca); u64 free_space_inv = free_space ? div64_u64(1ULL << 48, free_space) : 1ULL << 48; diff --git a/fs/bcachefs/bcachefs.h b/fs/bcachefs/bcachefs.h index cec5c3ddce342..76b72ed693a8f 100644 --- a/fs/bcachefs/bcachefs.h +++ b/fs/bcachefs/bcachefs.h @@ -447,6 +447,7 @@ struct bch_dev { */ alloc_fifo free[RESERVE_NR]; alloc_fifo free_inc; + unsigned nr_open_buckets; open_bucket_idx_t open_buckets_partial[OPEN_BUCKETS_COUNT]; open_bucket_idx_t open_buckets_partial_nr; @@ -772,7 +773,6 @@ mempool_t bio_bounce_pages; copygc_heap copygc_heap; struct bch_pd_controller copygc_pd; struct write_point copygc_write_point; - u64 copygc_threshold; /* STRIPES: */ GENRADIX(struct stripe) stripes[2]; diff --git a/fs/bcachefs/buckets.h b/fs/bcachefs/buckets.h index c965c4d48218e..e53cee27a7204 100644 --- a/fs/bcachefs/buckets.h +++ b/fs/bcachefs/buckets.h @@ -175,25 +175,31 @@ static inline u64 __dev_buckets_available(struct bch_dev *ca, return total - stats.buckets_unavailable; } -/* - * Number of reclaimable buckets - only for use by the allocator thread: - */ static inline u64 dev_buckets_available(struct bch_dev *ca) { return __dev_buckets_available(ca, bch2_dev_usage_read(ca)); } -static inline u64 __dev_buckets_free(struct bch_dev *ca, - struct bch_dev_usage stats) +static inline u64 __dev_buckets_reclaimable(struct bch_dev *ca, + struct bch_dev_usage stats) { - return __dev_buckets_available(ca, stats) + - fifo_used(&ca->free[RESERVE_NONE]) + - fifo_used(&ca->free_inc); + struct bch_fs *c = ca->fs; + s64 available = __dev_buckets_available(ca, stats); + unsigned i; + + spin_lock(&c->freelist_lock); + for (i = 0; i < RESERVE_NR; i++) + available -= fifo_used(&ca->free[i]); + available -= fifo_used(&ca->free_inc); + available -= ca->nr_open_buckets; + spin_unlock(&c->freelist_lock); + + return max(available, 0LL); } -static inline u64 dev_buckets_free(struct bch_dev *ca) +static inline u64 dev_buckets_reclaimable(struct bch_dev *ca) { - return __dev_buckets_free(ca, bch2_dev_usage_read(ca)); + return __dev_buckets_reclaimable(ca, bch2_dev_usage_read(ca)); } /* Filesystem usage: */ diff --git a/fs/bcachefs/movinggc.c b/fs/bcachefs/movinggc.c index 65a8cd14ee75d..b8da600cdc530 100644 --- a/fs/bcachefs/movinggc.c +++ b/fs/bcachefs/movinggc.c @@ -282,13 +282,12 @@ unsigned long bch2_copygc_wait_amount(struct bch_fs *c) { struct bch_dev *ca; unsigned dev_idx; - u64 fragmented_allowed = c->copygc_threshold; - u64 fragmented = 0; + u64 fragmented_allowed = 0, fragmented = 0; for_each_rw_member(ca, c, dev_idx) { struct bch_dev_usage usage = bch2_dev_usage_read(ca); - fragmented_allowed += ((__dev_buckets_available(ca, usage) * + fragmented_allowed += ((__dev_buckets_reclaimable(ca, usage) * ca->mi.bucket_size) >> 1); fragmented += usage.d[BCH_DATA_user].fragmented; } diff --git a/fs/bcachefs/sysfs.c b/fs/bcachefs/sysfs.c index 49c19873ad6f0..9f75f72f7b12f 100644 --- a/fs/bcachefs/sysfs.c +++ b/fs/bcachefs/sysfs.c @@ -805,7 +805,9 @@ static void dev_alloc_debug_to_text(struct printbuf *out, struct bch_dev *ca) "free[RESERVE_MOVINGGC]\t%zu/%zu\n" "free[RESERVE_NONE]\t%zu/%zu\n" "freelist_wait\t\t%s\n" - "open buckets\t\t%u/%u (reserved %u)\n" + "open buckets allocated\t%u\n" + "open buckets this dev\t%u\n" + "open buckets total\t%u\n" "open_buckets_wait\t%s\n" "open_buckets_btree\t%u\n" "open_buckets_user\t%u\n" @@ -816,8 +818,9 @@ static void dev_alloc_debug_to_text(struct printbuf *out, struct bch_dev *ca) fifo_used(&ca->free[RESERVE_MOVINGGC]), ca->free[RESERVE_MOVINGGC].size, fifo_used(&ca->free[RESERVE_NONE]), ca->free[RESERVE_NONE].size, c->freelist_wait.list.first ? "waiting" : "empty", - c->open_buckets_nr_free, OPEN_BUCKETS_COUNT, - BTREE_NODE_OPEN_BUCKET_RESERVE, + OPEN_BUCKETS_COUNT - c->open_buckets_nr_free, + ca->nr_open_buckets, + OPEN_BUCKETS_COUNT, c->open_buckets_wait.list.first ? "waiting" : "empty", nr[BCH_DATA_btree], nr[BCH_DATA_user], -- 2.30.2