+// SPDX-License-Identifier: GPL-2.0
/*
* Moving/copying garbage collector
*
*/
#include "bcachefs.h"
+#include "alloc_foreground.h"
#include "btree_iter.h"
#include "btree_update.h"
#include "buckets.h"
struct copygc_heap_entry l,
struct copygc_heap_entry r)
{
- return (l.sectors > r.sectors) - (l.sectors < r.sectors);
+ return cmp_int(l.sectors, r.sectors);
}
static int bucket_offset_cmp(const void *_l, const void *_r, size_t size)
const struct copygc_heap_entry *l = _l;
const struct copygc_heap_entry *r = _r;
- return (l->offset > r->offset) - (l->offset < r->offset);
+ return cmp_int(l->offset, r->offset);
}
static bool __copygc_pred(struct bch_dev *ca,
- struct bkey_s_c_extent e)
+ struct bkey_s_c k)
{
copygc_heap *h = &ca->copygc_heap;
const struct bch_extent_ptr *ptr =
- bch2_extent_has_device(e, ca->dev_idx);
+ bch2_bkey_has_device(k, ca->dev_idx);
if (ptr) {
struct copygc_heap_entry search = { .offset = ptr->offset };
}
static enum data_cmd copygc_pred(struct bch_fs *c, void *arg,
- enum bkey_type type,
- struct bkey_s_c_extent e,
+ struct bkey_s_c k,
struct bch_io_opts *io_opts,
struct data_opts *data_opts)
{
struct bch_dev *ca = arg;
- if (!__copygc_pred(ca, e))
+ if (!__copygc_pred(ca, k))
return DATA_SKIP;
data_opts->target = dev_to_target(ca->dev_idx);
{
bool ret;
- spin_lock(&ca->freelist_lock);
+ spin_lock(&ca->fs->freelist_lock);
ret = fifo_full(&ca->free[RESERVE_MOVINGGC]) ||
- ca->allocator_blocked;
- spin_unlock(&ca->freelist_lock);
+ ca->allocator_state != ALLOCATOR_RUNNING;
+ spin_unlock(&ca->fs->freelist_lock);
return ret;
}
.sectors = bucket_sectors_used(m),
.offset = bucket_to_sector(ca, b),
};
- heap_add_or_replace(h, e, -sectors_used_cmp);
+ heap_add_or_replace(h, e, -sectors_used_cmp, NULL);
}
up_read(&ca->bucket_lock);
up_read(&c->gc_lock);
sectors_to_move += i->sectors;
while (sectors_to_move > COPYGC_SECTORS_PER_ITER(ca)) {
- BUG_ON(!heap_pop(h, e, -sectors_used_cmp));
+ BUG_ON(!heap_pop(h, e, -sectors_used_cmp, NULL));
sectors_to_move -= e.sectors;
}
up_read(&ca->bucket_lock);
if (sectors_not_moved && !ret)
- bch_warn(c, "copygc finished but %llu/%llu sectors, %llu/%llu buckets not moved",
+ bch_warn_ratelimited(c,
+ "copygc finished but %llu/%llu sectors, %llu/%llu buckets not moved",
sectors_not_moved, sectors_to_move,
buckets_not_moved, buckets_to_move);
last = atomic_long_read(&clock->now);
- reserve = div64_u64((ca->mi.nbuckets - ca->mi.first_bucket) *
- ca->mi.bucket_size *
- c->opts.gc_reserve_percent, 200);
+ reserve = ca->copygc_threshold;
usage = bch2_dev_usage_read(c, ca);
- /*
- * don't start copygc until less than half the gc reserve is
- * available:
- */
available = __dev_buckets_available(ca, usage) *
ca->mi.bucket_size;
if (available > reserve) {
next = last + available - reserve;
- bch2_kthread_io_clock_wait(clock, next);
+ bch2_kthread_io_clock_wait(clock, next,
+ MAX_SCHEDULE_TIMEOUT);
continue;
}
fragmented = usage.sectors_fragmented;
if (fragmented < reserve) {
next = last + reserve - fragmented;
- bch2_kthread_io_clock_wait(clock, next);
+ bch2_kthread_io_clock_wait(clock, next,
+ MAX_SCHEDULE_TIMEOUT);
continue;
}
{
struct task_struct *t;
- BUG_ON(ca->copygc_thread);
+ if (ca->copygc_thread)
+ return 0;
if (c->opts.nochanges)
return 0;