mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-25 02:09:42 +00:00
bcachefs: Redo copygc throttling
The code that checked the current free space and waited if it was too big was causing issues - btree node allocations do not increment the write IO clock (perhaps they should); but more broadly the check wouldn't run copygc at all until the device was mostly full, at which point it might have to do a bunch of work. This redoes that logic so that copygc starts to run earlier, smoothly running more and more often as the device becomes closer to full. Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com> Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
5873efbfd9
commit
309c54c3f4
1 changed files with 28 additions and 24 deletions
|
@ -212,14 +212,36 @@ static void bch2_copygc(struct bch_fs *c, struct bch_dev *ca)
|
||||||
buckets_to_move, buckets_not_moved);
|
buckets_to_move, buckets_not_moved);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copygc runs when the amount of fragmented data is above some arbitrary
|
||||||
|
* threshold:
|
||||||
|
*
|
||||||
|
* The threshold at the limit - when the device is full - is the amount of space
|
||||||
|
* we reserved in bch2_recalc_capacity; we can't have more than that amount of
|
||||||
|
* disk space stranded due to fragmentation and store everything we have
|
||||||
|
* promised to store.
|
||||||
|
*
|
||||||
|
* But we don't want to be running copygc unnecessarily when the device still
|
||||||
|
* has plenty of free space - rather, we want copygc to smoothly run every so
|
||||||
|
* often and continually reduce the amount of fragmented space as the device
|
||||||
|
* fills up. So, we increase the threshold by half the current free space.
|
||||||
|
*/
|
||||||
|
unsigned long bch2_copygc_wait_amount(struct bch_dev *ca)
|
||||||
|
{
|
||||||
|
struct bch_fs *c = ca->fs;
|
||||||
|
struct bch_dev_usage usage = bch2_dev_usage_read(c, ca);
|
||||||
|
u64 fragmented_allowed = ca->copygc_threshold +
|
||||||
|
((__dev_buckets_available(ca, usage) * ca->mi.bucket_size) >> 1);
|
||||||
|
|
||||||
|
return max_t(s64, 0, fragmented_allowed - usage.sectors_fragmented);
|
||||||
|
}
|
||||||
|
|
||||||
static int bch2_copygc_thread(void *arg)
|
static int bch2_copygc_thread(void *arg)
|
||||||
{
|
{
|
||||||
struct bch_dev *ca = arg;
|
struct bch_dev *ca = arg;
|
||||||
struct bch_fs *c = ca->fs;
|
struct bch_fs *c = ca->fs;
|
||||||
struct io_clock *clock = &c->io_clock[WRITE];
|
struct io_clock *clock = &c->io_clock[WRITE];
|
||||||
struct bch_dev_usage usage;
|
unsigned long last, wait;
|
||||||
unsigned long last;
|
|
||||||
u64 available, fragmented, reserve, next;
|
|
||||||
|
|
||||||
set_freezable();
|
set_freezable();
|
||||||
|
|
||||||
|
@ -228,28 +250,10 @@ static int bch2_copygc_thread(void *arg)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
last = atomic_long_read(&clock->now);
|
last = atomic_long_read(&clock->now);
|
||||||
|
wait = bch2_copygc_wait_amount(ca);
|
||||||
|
|
||||||
reserve = ca->copygc_threshold;
|
if (wait > clock->max_slop) {
|
||||||
|
bch2_kthread_io_clock_wait(clock, last + wait,
|
||||||
usage = bch2_dev_usage_read(c, ca);
|
|
||||||
|
|
||||||
available = __dev_buckets_available(ca, usage) *
|
|
||||||
ca->mi.bucket_size;
|
|
||||||
if (available > reserve) {
|
|
||||||
next = last + available - reserve;
|
|
||||||
bch2_kthread_io_clock_wait(clock, next,
|
|
||||||
MAX_SCHEDULE_TIMEOUT);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* don't start copygc until there's more than half the copygc
|
|
||||||
* reserve of fragmented space:
|
|
||||||
*/
|
|
||||||
fragmented = usage.sectors_fragmented;
|
|
||||||
if (fragmented < reserve) {
|
|
||||||
next = last + reserve - fragmented;
|
|
||||||
bch2_kthread_io_clock_wait(clock, next,
|
|
||||||
MAX_SCHEDULE_TIMEOUT);
|
MAX_SCHEDULE_TIMEOUT);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue