mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-09 14:56:54 -04:00
bcachefs: Kill old allocator startup code
It's not needed anymore since we can now write to buckets before updating the alloc btree. Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com> Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
committed by
Kent Overstreet
parent
9ef846a7a1
commit
a27443bc76
@@ -968,31 +968,6 @@ static int bch2_invalidate_one_bucket2(struct btree_trans *trans,
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
||||
static bool bch2_invalidate_one_bucket(struct bch_fs *c, struct bch_dev *ca,
|
||||
size_t bucket, u64 *flush_seq)
|
||||
{
|
||||
struct bucket_mark m;
|
||||
|
||||
percpu_down_read(&c->mark_lock);
|
||||
spin_lock(&c->freelist_lock);
|
||||
|
||||
bch2_invalidate_bucket(c, ca, bucket, &m);
|
||||
|
||||
verify_not_on_freelist(c, ca, bucket);
|
||||
BUG_ON(!fifo_push(&ca->free_inc, bucket));
|
||||
|
||||
spin_unlock(&c->freelist_lock);
|
||||
|
||||
bucket_io_clock_reset(c, ca, bucket, READ);
|
||||
bucket_io_clock_reset(c, ca, bucket, WRITE);
|
||||
|
||||
percpu_up_read(&c->mark_lock);
|
||||
|
||||
*flush_seq = max(*flush_seq, bucket_journal_seq(c, m));
|
||||
|
||||
return m.cached_sectors != 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Pull buckets off ca->alloc_heap, invalidate them, move them to ca->free_inc:
|
||||
*/
|
||||
@@ -1448,216 +1423,6 @@ int bch2_dev_allocator_start(struct bch_dev *ca)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool flush_held_btree_writes(struct bch_fs *c)
|
||||
{
|
||||
struct bucket_table *tbl;
|
||||
struct rhash_head *pos;
|
||||
struct btree *b;
|
||||
bool nodes_unwritten;
|
||||
size_t i;
|
||||
again:
|
||||
cond_resched();
|
||||
nodes_unwritten = false;
|
||||
|
||||
if (bch2_journal_error(&c->journal))
|
||||
return true;
|
||||
|
||||
rcu_read_lock();
|
||||
for_each_cached_btree(b, c, tbl, i, pos)
|
||||
if (btree_node_need_write(b)) {
|
||||
if (btree_node_may_write(b)) {
|
||||
rcu_read_unlock();
|
||||
btree_node_lock_type(c, b, SIX_LOCK_read);
|
||||
bch2_btree_node_write(c, b, SIX_LOCK_read);
|
||||
six_unlock_read(&b->c.lock);
|
||||
goto again;
|
||||
} else {
|
||||
nodes_unwritten = true;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
return !nodes_unwritten &&
|
||||
!bch2_btree_interior_updates_nr_pending(c);
|
||||
}
|
||||
|
||||
static void allocator_start_issue_discards(struct bch_fs *c)
|
||||
{
|
||||
struct bch_dev *ca;
|
||||
unsigned dev_iter;
|
||||
size_t bu;
|
||||
|
||||
for_each_rw_member(ca, c, dev_iter)
|
||||
while (fifo_pop(&ca->free_inc, bu))
|
||||
blkdev_issue_discard(ca->disk_sb.bdev,
|
||||
bucket_to_sector(ca, bu),
|
||||
ca->mi.bucket_size, GFP_NOIO);
|
||||
}
|
||||
|
||||
static int resize_free_inc(struct bch_dev *ca)
|
||||
{
|
||||
alloc_fifo free_inc;
|
||||
|
||||
if (!fifo_full(&ca->free_inc))
|
||||
return 0;
|
||||
|
||||
if (!init_fifo(&free_inc,
|
||||
ca->free_inc.size * 2,
|
||||
GFP_KERNEL))
|
||||
return -ENOMEM;
|
||||
|
||||
fifo_move(&free_inc, &ca->free_inc);
|
||||
swap(free_inc, ca->free_inc);
|
||||
free_fifo(&free_inc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool bch2_fs_allocator_start_fast(struct bch_fs *c)
|
||||
{
|
||||
struct bch_dev *ca;
|
||||
unsigned dev_iter;
|
||||
bool ret = true;
|
||||
|
||||
if (test_alloc_startup(c))
|
||||
return false;
|
||||
|
||||
down_read(&c->gc_lock);
|
||||
|
||||
/* Scan for buckets that are already invalidated: */
|
||||
for_each_rw_member(ca, c, dev_iter) {
|
||||
struct bucket_array *buckets;
|
||||
struct bucket_mark m;
|
||||
long bu;
|
||||
|
||||
down_read(&ca->bucket_lock);
|
||||
buckets = bucket_array(ca);
|
||||
|
||||
for (bu = buckets->first_bucket;
|
||||
bu < buckets->nbuckets; bu++) {
|
||||
m = READ_ONCE(buckets->b[bu].mark);
|
||||
|
||||
if (!buckets->b[bu].gen_valid ||
|
||||
!is_available_bucket(m) ||
|
||||
m.cached_sectors ||
|
||||
(ca->buckets_nouse &&
|
||||
test_bit(bu, ca->buckets_nouse)))
|
||||
continue;
|
||||
|
||||
percpu_down_read(&c->mark_lock);
|
||||
bch2_mark_alloc_bucket(c, ca, bu, true,
|
||||
gc_pos_alloc(c, NULL), 0);
|
||||
percpu_up_read(&c->mark_lock);
|
||||
|
||||
fifo_push(&ca->free_inc, bu);
|
||||
|
||||
discard_invalidated_buckets(c, ca);
|
||||
|
||||
if (fifo_full(&ca->free[RESERVE_BTREE]))
|
||||
break;
|
||||
}
|
||||
up_read(&ca->bucket_lock);
|
||||
}
|
||||
|
||||
up_read(&c->gc_lock);
|
||||
|
||||
/* did we find enough buckets? */
|
||||
for_each_rw_member(ca, c, dev_iter)
|
||||
if (!fifo_full(&ca->free[RESERVE_BTREE]))
|
||||
ret = false;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (!test_alloc_startup(c) &&
|
||||
bch2_fs_allocator_start_fast(c))
|
||||
return 0;
|
||||
|
||||
pr_debug("not enough empty buckets; scanning for reclaimable buckets");
|
||||
|
||||
/*
|
||||
* We're moving buckets to freelists _before_ they've been marked as
|
||||
* invalidated on disk - we have to so that we can allocate new btree
|
||||
* nodes to mark them as invalidated on disk.
|
||||
*
|
||||
* However, we can't _write_ to any of these buckets yet - they might
|
||||
* have cached data in them, which is live until they're marked as
|
||||
* invalidated on disk:
|
||||
*/
|
||||
set_bit(BCH_FS_HOLD_BTREE_WRITES, &c->flags);
|
||||
|
||||
down_read(&c->gc_lock);
|
||||
do {
|
||||
wrote = false;
|
||||
|
||||
for_each_rw_member(ca, c, dev_iter) {
|
||||
find_reclaimable_buckets(c, ca);
|
||||
|
||||
while (!fifo_full(&ca->free[RESERVE_BTREE]) &&
|
||||
(bu = next_alloc_bucket(ca)) >= 0) {
|
||||
ret = resize_free_inc(ca);
|
||||
if (ret) {
|
||||
percpu_ref_put(&ca->io_ref);
|
||||
up_read(&c->gc_lock);
|
||||
goto err;
|
||||
}
|
||||
|
||||
bch2_invalidate_one_bucket(c, ca, bu,
|
||||
&journal_seq);
|
||||
|
||||
fifo_push(&ca->free[RESERVE_BTREE], bu);
|
||||
}
|
||||
}
|
||||
|
||||
pr_debug("done scanning for reclaimable buckets");
|
||||
|
||||
/*
|
||||
* XXX: it's possible for this to deadlock waiting on journal reclaim,
|
||||
* since we're holding btree writes. What then?
|
||||
*/
|
||||
ret = bch2_alloc_write(c,
|
||||
BTREE_INSERT_NOCHECK_RW|
|
||||
BTREE_INSERT_USE_ALLOC_RESERVE|
|
||||
BTREE_INSERT_NOWAIT, &wrote);
|
||||
|
||||
/*
|
||||
* If bch2_alloc_write() did anything, it may have used some
|
||||
* buckets, and we need the RESERVE_BTREE freelist full - so we
|
||||
* need to loop and scan again.
|
||||
* And if it errored, it may have been because there weren't
|
||||
* enough buckets, so just scan and loop again as long as it
|
||||
* made some progress:
|
||||
*/
|
||||
} while (wrote);
|
||||
up_read(&c->gc_lock);
|
||||
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
pr_debug("flushing journal");
|
||||
|
||||
ret = bch2_journal_flush(&c->journal);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
pr_debug("issuing discards");
|
||||
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));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void bch2_fs_allocator_background_init(struct bch_fs *c)
|
||||
{
|
||||
spin_lock_init(&c->freelist_lock);
|
||||
|
||||
@@ -70,8 +70,7 @@ static inline void bch2_wake_allocator(struct bch_dev *ca)
|
||||
static inline void verify_not_on_freelist(struct bch_fs *c, struct bch_dev *ca,
|
||||
size_t bucket)
|
||||
{
|
||||
if (expensive_debug_checks(c) &&
|
||||
test_bit(BCH_FS_ALLOCATOR_STARTED, &c->flags)) {
|
||||
if (expensive_debug_checks(c)) {
|
||||
size_t iter;
|
||||
long i;
|
||||
unsigned j;
|
||||
@@ -94,7 +93,6 @@ void bch2_dev_allocator_stop(struct bch_dev *);
|
||||
int bch2_dev_allocator_start(struct bch_dev *);
|
||||
|
||||
int bch2_alloc_write(struct bch_fs *, unsigned, bool *);
|
||||
int bch2_fs_allocator_start(struct bch_fs *);
|
||||
void bch2_fs_allocator_background_init(struct bch_fs *);
|
||||
|
||||
#endif /* _BCACHEFS_ALLOC_BACKGROUND_H */
|
||||
|
||||
@@ -480,7 +480,6 @@ enum {
|
||||
/* startup: */
|
||||
BCH_FS_ALLOC_READ_DONE,
|
||||
BCH_FS_ALLOC_CLEAN,
|
||||
BCH_FS_ALLOCATOR_STARTED,
|
||||
BCH_FS_ALLOCATOR_RUNNING,
|
||||
BCH_FS_ALLOCATOR_STOPPING,
|
||||
BCH_FS_INITIAL_GC_DONE,
|
||||
|
||||
@@ -28,17 +28,9 @@ unsigned bch2_journal_dev_buckets_available(struct journal *j,
|
||||
struct journal_device *ja,
|
||||
enum journal_space_from from)
|
||||
{
|
||||
struct bch_fs *c = container_of(j, struct bch_fs, journal);
|
||||
unsigned available = (journal_space_from(ja, from) -
|
||||
ja->cur_idx - 1 + ja->nr) % ja->nr;
|
||||
|
||||
/*
|
||||
* Allocator startup needs some journal space before we can do journal
|
||||
* replay:
|
||||
*/
|
||||
if (available && test_bit(BCH_FS_ALLOCATOR_STARTED, &c->flags))
|
||||
--available;
|
||||
|
||||
/*
|
||||
* Don't use the last bucket unless writing the new last_seq
|
||||
* will make another bucket available:
|
||||
|
||||
@@ -423,16 +423,6 @@ static int __bch2_fs_read_write(struct bch_fs *c, bool early)
|
||||
bch2_dev_allocator_add(c, ca);
|
||||
bch2_recalc_capacity(c);
|
||||
|
||||
if (!test_bit(BCH_FS_ALLOCATOR_STARTED, &c->flags)) {
|
||||
ret = bch2_fs_allocator_start(c);
|
||||
if (ret) {
|
||||
bch_err(c, "error initializing allocator");
|
||||
goto err;
|
||||
}
|
||||
|
||||
set_bit(BCH_FS_ALLOCATOR_STARTED, &c->flags);
|
||||
}
|
||||
|
||||
for_each_rw_member(ca, c, i) {
|
||||
ret = bch2_dev_allocator_start(ca);
|
||||
if (ret) {
|
||||
|
||||
Reference in New Issue
Block a user