Commit fcbf3e50 authored by Kent Overstreet's avatar Kent Overstreet Committed by Kent Overstreet

bcachefs: Allocator startup fixes/refactoring

Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent dc9aa178
...@@ -1467,7 +1467,7 @@ int bch2_dev_allocator_start(struct bch_dev *ca) ...@@ -1467,7 +1467,7 @@ int bch2_dev_allocator_start(struct bch_dev *ca)
return 0; return 0;
} }
static bool flush_done(struct bch_fs *c) static bool flush_held_btree_writes(struct bch_fs *c)
{ {
struct bucket_table *tbl; struct bucket_table *tbl;
struct rhash_head *pos; struct rhash_head *pos;
...@@ -1502,13 +1502,6 @@ static bool flush_done(struct bch_fs *c) ...@@ -1502,13 +1502,6 @@ static bool flush_done(struct bch_fs *c)
!bch2_btree_interior_updates_nr_pending(c); !bch2_btree_interior_updates_nr_pending(c);
} }
static void flush_held_btree_writes(struct bch_fs *c)
{
clear_bit(BCH_FS_HOLD_BTREE_WRITES, &c->flags);
closure_wait_event(&c->btree_interior_update_wait, flush_done(c));
}
static void allocator_start_issue_discards(struct bch_fs *c) static void allocator_start_issue_discards(struct bch_fs *c)
{ {
struct bch_dev *ca; struct bch_dev *ca;
...@@ -1540,25 +1533,24 @@ static int resize_free_inc(struct bch_dev *ca) ...@@ -1540,25 +1533,24 @@ static int resize_free_inc(struct bch_dev *ca)
return 0; return 0;
} }
static int __bch2_fs_allocator_start(struct bch_fs *c) static bool bch2_fs_allocator_start_fast(struct bch_fs *c)
{ {
struct bch_dev *ca; struct bch_dev *ca;
unsigned dev_iter; unsigned dev_iter;
u64 journal_seq = 0; bool ret = true;
long bu;
int ret = 0;
if (test_alloc_startup(c)) if (test_alloc_startup(c))
goto not_enough; return false;
down_read(&c->gc_lock);
/* Scan for buckets that are already invalidated: */ /* Scan for buckets that are already invalidated: */
for_each_rw_member(ca, c, dev_iter) { for_each_rw_member(ca, c, dev_iter) {
struct bucket_array *buckets; struct bucket_array *buckets;
struct bucket_mark m; struct bucket_mark m;
long bu;
down_read(&ca->bucket_lock); down_read(&ca->bucket_lock);
percpu_down_read(&c->mark_lock);
buckets = bucket_array(ca); buckets = bucket_array(ca);
for (bu = buckets->first_bucket; for (bu = buckets->first_bucket;
...@@ -1566,13 +1558,16 @@ static int __bch2_fs_allocator_start(struct bch_fs *c) ...@@ -1566,13 +1558,16 @@ static int __bch2_fs_allocator_start(struct bch_fs *c)
m = READ_ONCE(buckets->b[bu].mark); m = READ_ONCE(buckets->b[bu].mark);
if (!buckets->b[bu].gen_valid || if (!buckets->b[bu].gen_valid ||
!test_bit(bu, ca->buckets_nouse) ||
!is_available_bucket(m) || !is_available_bucket(m) ||
m.cached_sectors) m.cached_sectors ||
(ca->buckets_nouse &&
test_bit(bu, ca->buckets_nouse)))
continue; continue;
percpu_down_read(&c->mark_lock);
bch2_mark_alloc_bucket(c, ca, bu, true, bch2_mark_alloc_bucket(c, ca, bu, true,
gc_pos_alloc(c, NULL), 0); gc_pos_alloc(c, NULL), 0);
percpu_up_read(&c->mark_lock);
fifo_push(&ca->free_inc, bu); fifo_push(&ca->free_inc, bu);
...@@ -1581,19 +1576,28 @@ static int __bch2_fs_allocator_start(struct bch_fs *c) ...@@ -1581,19 +1576,28 @@ static int __bch2_fs_allocator_start(struct bch_fs *c)
if (fifo_full(&ca->free[RESERVE_BTREE])) if (fifo_full(&ca->free[RESERVE_BTREE]))
break; break;
} }
percpu_up_read(&c->mark_lock);
up_read(&ca->bucket_lock); up_read(&ca->bucket_lock);
} }
up_read(&c->gc_lock);
/* did we find enough buckets? */ /* did we find enough buckets? */
for_each_rw_member(ca, c, dev_iter) for_each_rw_member(ca, c, dev_iter)
if (!fifo_full(&ca->free[RESERVE_BTREE])) { if (!fifo_full(&ca->free[RESERVE_BTREE]))
percpu_ref_put(&ca->io_ref); ret = false;
goto not_enough;
} return ret;
}
static int __bch2_fs_allocator_start(struct bch_fs *c)
{
struct bch_dev *ca;
unsigned dev_iter;
u64 journal_seq = 0;
bool wrote;
long bu;
int ret = 0;
return 0;
not_enough:
pr_debug("not enough empty buckets; scanning for reclaimable buckets"); pr_debug("not enough empty buckets; scanning for reclaimable buckets");
/* /*
...@@ -1607,8 +1611,9 @@ static int __bch2_fs_allocator_start(struct bch_fs *c) ...@@ -1607,8 +1611,9 @@ static int __bch2_fs_allocator_start(struct bch_fs *c)
*/ */
set_bit(BCH_FS_HOLD_BTREE_WRITES, &c->flags); set_bit(BCH_FS_HOLD_BTREE_WRITES, &c->flags);
while (1) { down_read(&c->gc_lock);
bool wrote = false; do {
wrote = false;
for_each_rw_member(ca, c, dev_iter) { for_each_rw_member(ca, c, dev_iter) {
find_reclaimable_buckets(c, ca); find_reclaimable_buckets(c, ca);
...@@ -1618,7 +1623,8 @@ static int __bch2_fs_allocator_start(struct bch_fs *c) ...@@ -1618,7 +1623,8 @@ static int __bch2_fs_allocator_start(struct bch_fs *c)
ret = resize_free_inc(ca); ret = resize_free_inc(ca);
if (ret) { if (ret) {
percpu_ref_put(&ca->io_ref); percpu_ref_put(&ca->io_ref);
return ret; up_read(&c->gc_lock);
goto err;
} }
bch2_invalidate_one_bucket(c, ca, bu, bch2_invalidate_one_bucket(c, ca, bu,
...@@ -1644,27 +1650,26 @@ static int __bch2_fs_allocator_start(struct bch_fs *c) ...@@ -1644,27 +1650,26 @@ static int __bch2_fs_allocator_start(struct bch_fs *c)
* enough buckets, so just scan and loop again as long as it * enough buckets, so just scan and loop again as long as it
* made some progress: * made some progress:
*/ */
if (!wrote && ret) } while (wrote);
return ret; up_read(&c->gc_lock);
if (!wrote && !ret)
break; if (ret)
} goto err;
pr_debug("flushing journal"); pr_debug("flushing journal");
ret = bch2_journal_flush(&c->journal); ret = bch2_journal_flush(&c->journal);
if (ret) if (ret)
return ret; goto err;
pr_debug("issuing discards"); pr_debug("issuing discards");
allocator_start_issue_discards(c); allocator_start_issue_discards(c);
err:
clear_bit(BCH_FS_HOLD_BTREE_WRITES, &c->flags);
closure_wait_event(&c->btree_interior_update_wait,
flush_held_btree_writes(c));
set_bit(BCH_FS_ALLOCATOR_STARTED, &c->flags); return ret;
/* now flush dirty btree nodes: */
flush_held_btree_writes(c);
return 0;
} }
int bch2_fs_allocator_start(struct bch_fs *c) int bch2_fs_allocator_start(struct bch_fs *c)
...@@ -1673,13 +1678,13 @@ int bch2_fs_allocator_start(struct bch_fs *c) ...@@ -1673,13 +1678,13 @@ int bch2_fs_allocator_start(struct bch_fs *c)
unsigned i; unsigned i;
int ret; int ret;
down_read(&c->gc_lock); ret = bch2_fs_allocator_start_fast(c) ? 0 :
ret = __bch2_fs_allocator_start(c); __bch2_fs_allocator_start(c);
up_read(&c->gc_lock);
if (ret) if (ret)
return ret; return ret;
set_bit(BCH_FS_ALLOCATOR_STARTED, &c->flags);
for_each_rw_member(ca, c, i) { for_each_rw_member(ca, c, i) {
ret = bch2_dev_allocator_start(ca); ret = bch2_dev_allocator_start(ca);
if (ret) { if (ret) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment