mirror of
https://github.com/torvalds/linux
synced 2024-11-05 18:23:50 +00:00
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 <kent.overstreet@gmail.com> Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
006d69aa26
commit
cb66fc5fe4
6 changed files with 33 additions and 33 deletions
|
@ -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 @@ static int bch2_allocator_thread(void *arg)
|
|||
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;
|
||||
|
|
|
@ -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 @@ struct open_bucket *bch2_bucket_alloc(struct bch_fs *c, struct bch_dev *ca,
|
|||
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;
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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: */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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],
|
||||
|
|
Loading…
Reference in a new issue