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

bcachefs: Allocation code refactoring

bch2_alloc_sectors_start() was a nightmare to work with - it's got some
tricky stuff to do, since it wants to use the buckets the writepoint
already has, unless they're not in the target it wants to write to,
unless it can't allocate from any other devices in which case it will
use those buckets if it has to - et cetera.

This restructures the code to start with a new empty list of open
buckets we're going to use for the new allocation, pulling buckets from
the write point's list as we decide that we really are going to use
them - making the code somewhat more functional and drastically easier
to understand.

Also fixes a bug where we could end up waiting on c->freelist_wait
(because allocating from one device failed) but return success from
bch2_bucket_alloc(), because allocating from a different device
succeeded.
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 7b3f84ea
......@@ -1101,7 +1101,7 @@ void bch2_dev_allocator_remove(struct bch_fs *c, struct bch_dev *ca)
struct btree_alloc *a =
&c->btree_reserve_cache[--c->btree_reserve_cache_nr];
bch2_open_bucket_put_refs(c, &a->ob.nr, a->ob.refs);
bch2_open_buckets_put(c, &a->ob);
}
mutex_unlock(&c->btree_reserve_cache_lock);
......
This diff is collapsed.
......@@ -23,19 +23,23 @@ void bch2_wp_rescale(struct bch_fs *, struct bch_dev *,
long bch2_bucket_alloc_new_fs(struct bch_dev *);
int bch2_bucket_alloc(struct bch_fs *, struct bch_dev *, enum alloc_reserve, bool,
struct closure *);
struct open_bucket *bch2_bucket_alloc(struct bch_fs *, struct bch_dev *,
enum alloc_reserve, bool,
struct closure *);
#define __writepoint_for_each_ptr(_wp, _ob, _i, _start) \
for ((_i) = (_start); \
(_i) < (_wp)->nr_ptrs && ((_ob) = (_wp)->ptrs[_i], true); \
(_i)++)
static inline void ob_push(struct bch_fs *c, struct open_buckets *obs,
struct open_bucket *ob)
{
BUG_ON(obs->nr >= ARRAY_SIZE(obs->v));
#define writepoint_for_each_ptr_all(_wp, _ob, _i) \
__writepoint_for_each_ptr(_wp, _ob, _i, 0)
obs->v[obs->nr++] = ob - c->open_buckets;
}
#define writepoint_for_each_ptr(_wp, _ob, _i) \
__writepoint_for_each_ptr(_wp, _ob, _i, wp->first_ptr)
#define open_bucket_for_each(_c, _obs, _ob, _i) \
for ((_i) = 0; \
(_i) < (_obs)->nr && \
((_ob) = (_c)->open_buckets + (_obs)->v[_i], true); \
(_i)++)
void __bch2_open_bucket_put(struct bch_fs *, struct open_bucket *);
......@@ -45,26 +49,27 @@ static inline void bch2_open_bucket_put(struct bch_fs *c, struct open_bucket *ob
__bch2_open_bucket_put(c, ob);
}
static inline void bch2_open_bucket_put_refs(struct bch_fs *c, u8 *nr, u8 *refs)
static inline void bch2_open_buckets_put(struct bch_fs *c,
struct open_buckets *ptrs)
{
struct open_bucket *ob;
unsigned i;
for (i = 0; i < *nr; i++)
bch2_open_bucket_put(c, c->open_buckets + refs[i]);
*nr = 0;
open_bucket_for_each(c, ptrs, ob, i)
bch2_open_bucket_put(c, ob);
ptrs->nr = 0;
}
static inline void bch2_open_bucket_get(struct bch_fs *c,
struct write_point *wp,
u8 *nr, u8 *refs)
struct open_buckets *ptrs)
{
struct open_bucket *ob;
unsigned i;
writepoint_for_each_ptr(wp, ob, i) {
open_bucket_for_each(c, &wp->ptrs, ob, i) {
atomic_inc(&ob->pin);
refs[(*nr)++] = ob - c->open_buckets;
ob_push(c, ptrs, ob);
}
}
......@@ -84,9 +89,6 @@ void bch2_alloc_sectors_done(struct bch_fs *, struct write_point *);
void bch2_writepoint_stop(struct bch_fs *, struct bch_dev *,
struct write_point *);
void bch2_writepoint_drop_ptrs(struct bch_fs *, struct write_point *,
u16, bool);
static inline struct hlist_head *writepoint_hash(struct bch_fs *c,
unsigned long write_point)
{
......
......@@ -58,6 +58,13 @@ struct open_bucket {
struct bch_extent_ptr ptr;
};
#define OPEN_BUCKET_LIST_MAX 15
struct open_buckets {
u8 nr;
u8 v[OPEN_BUCKET_LIST_MAX];
};
struct write_point {
struct hlist_node node;
struct mutex lock;
......@@ -65,13 +72,10 @@ struct write_point {
unsigned long write_point;
enum bch_data_type type;
u8 nr_ptrs;
u8 first_ptr;
/* calculated based on how many pointers we're actually going to use: */
unsigned sectors_free;
struct open_bucket *ptrs[BCH_REPLICAS_MAX * 2];
struct open_buckets ptrs;
u64 next_alloc[BCH_SB_MEMBERS_MAX];
};
......
......@@ -6,6 +6,7 @@
#include "bcachefs.h"
#include "alloc_background.h"
#include "alloc_foreground.h"
#include "bkey_methods.h"
#include "btree_locking.h"
#include "btree_update_interior.h"
......@@ -803,7 +804,7 @@ static void bch2_coalesce_nodes(struct bch_fs *c, struct btree_iter *iter,
bch2_btree_iter_node_replace(iter, new_nodes[0]);
for (i = 0; i < nr_new_nodes; i++)
bch2_btree_open_bucket_put(c, new_nodes[i]);
bch2_open_buckets_put(c, &new_nodes[i]->ob);
/* Free the old nodes and update our sliding window */
for (i = 0; i < nr_old_nodes; i++) {
......
......@@ -54,13 +54,8 @@ struct btree_write {
struct closure_waitlist wait;
};
struct btree_ob_ref {
u8 nr;
u8 refs[BCH_REPLICAS_MAX];
};
struct btree_alloc {
struct btree_ob_ref ob;
struct open_buckets ob;
BKEY_PADDED(k);
};
......@@ -127,7 +122,7 @@ struct btree {
*/
unsigned long will_make_reachable;
struct btree_ob_ref ob;
struct open_buckets ob;
/* lru list */
struct list_head list;
......
......@@ -247,7 +247,7 @@ static void __btree_node_free(struct bch_fs *c, struct btree *b)
void bch2_btree_node_free_never_inserted(struct bch_fs *c, struct btree *b)
{
struct btree_ob_ref ob = b->ob;
struct open_buckets ob = b->ob;
btree_update_drop_new_node(c, b);
......@@ -259,7 +259,7 @@ void bch2_btree_node_free_never_inserted(struct bch_fs *c, struct btree *b)
__btree_node_free(c, b);
six_unlock_write(&b->lock);
bch2_open_bucket_put_refs(c, &ob.nr, ob.refs);
bch2_open_buckets_put(c, &ob);
}
void bch2_btree_node_free_inmem(struct bch_fs *c, struct btree *b,
......@@ -300,11 +300,6 @@ static void bch2_btree_node_free_ondisk(struct bch_fs *c,
*/
}
void bch2_btree_open_bucket_put(struct bch_fs *c, struct btree *b)
{
bch2_open_bucket_put_refs(c, &b->ob.nr, b->ob.refs);
}
static struct btree *__bch2_btree_node_alloc(struct bch_fs *c,
struct disk_reservation *res,
struct closure *cl,
......@@ -314,7 +309,7 @@ static struct btree *__bch2_btree_node_alloc(struct bch_fs *c,
struct btree *b;
BKEY_PADDED(k) tmp;
struct bkey_i_extent *e;
struct btree_ob_ref ob;
struct open_buckets ob = { .nr = 0 };
struct bch_devs_list devs_have = (struct bch_devs_list) { 0 };
unsigned nr_reserve;
enum alloc_reserve alloc_reserve;
......@@ -356,7 +351,7 @@ static struct btree *__bch2_btree_node_alloc(struct bch_fs *c,
struct open_bucket *ob;
unsigned i;
writepoint_for_each_ptr(wp, ob, i)
open_bucket_for_each(c, &wp->ptrs, ob, i)
if (ob->sectors_free < c->opts.btree_node_size)
ob->sectors_free = 0;
......@@ -367,8 +362,7 @@ static struct btree *__bch2_btree_node_alloc(struct bch_fs *c,
e = bkey_extent_init(&tmp.k);
bch2_alloc_sectors_append_ptrs(c, wp, e, c->opts.btree_node_size);
ob.nr = 0;
bch2_open_bucket_get(c, wp, &ob.nr, ob.refs);
bch2_open_bucket_get(c, wp, &ob);
bch2_alloc_sectors_done(c, wp);
mem_alloc:
b = bch2_btree_node_mem_alloc(c);
......@@ -489,7 +483,7 @@ static void bch2_btree_reserve_put(struct bch_fs *c, struct btree_reserve *reser
b->ob.nr = 0;
bkey_copy(&a->k, &b->key);
} else {
bch2_btree_open_bucket_put(c, b);
bch2_open_buckets_put(c, &b->ob);
}
btree_node_lock_type(c, b, SIX_LOCK_write);
......@@ -1432,11 +1426,11 @@ static void btree_split(struct btree_update *as, struct btree *b,
bch2_btree_set_root(as, n1, iter);
}
bch2_btree_open_bucket_put(c, n1);
bch2_open_buckets_put(c, &n1->ob);
if (n2)
bch2_btree_open_bucket_put(c, n2);
bch2_open_buckets_put(c, &n2->ob);
if (n3)
bch2_btree_open_bucket_put(c, n3);
bch2_open_buckets_put(c, &n3->ob);
/*
* Note - at this point other linked iterators could still have @b read
......@@ -1751,7 +1745,7 @@ void __bch2_foreground_maybe_merge(struct bch_fs *c,
bch2_btree_insert_node(as, parent, iter, &as->parent_keys, flags);
bch2_btree_open_bucket_put(c, n);
bch2_open_buckets_put(c, &n->ob);
bch2_btree_node_free_inmem(c, b, iter);
bch2_btree_node_free_inmem(c, m, iter);
bch2_btree_iter_node_replace(iter, n);
......@@ -1843,7 +1837,7 @@ static int __btree_node_rewrite(struct bch_fs *c, struct btree_iter *iter,
bch2_btree_set_root(as, n, iter);
}
bch2_btree_open_bucket_put(c, n);
bch2_open_buckets_put(c, &n->ob);
bch2_btree_node_free_inmem(c, b, iter);
......
......@@ -132,7 +132,6 @@ struct btree_update {
void bch2_btree_node_free_inmem(struct bch_fs *, struct btree *,
struct btree_iter *);
void bch2_btree_node_free_never_inserted(struct bch_fs *, struct btree *);
void bch2_btree_open_bucket_put(struct bch_fs *, struct btree *);
struct btree *__bch2_btree_node_alloc_replacement(struct btree_update *,
struct btree *,
......
......@@ -369,7 +369,7 @@ static void __bch2_write_index(struct bch_write_op *op)
}
}
out:
bch2_open_bucket_put_refs(c, &op->open_buckets_nr, op->open_buckets);
bch2_open_buckets_put(c, &op->open_buckets);
return;
err:
keys->top = keys->keys;
......@@ -816,8 +816,8 @@ static void __bch2_write(struct closure *cl)
again:
do {
/* +1 for possible cache device: */
if (op->open_buckets_nr + op->nr_replicas + 1 >
ARRAY_SIZE(op->open_buckets))
if (op->open_buckets.nr + op->nr_replicas + 1 >
ARRAY_SIZE(op->open_buckets.v))
goto flush_io;
if (bch2_keylist_realloc(&op->insert_keys,
......@@ -848,11 +848,7 @@ static void __bch2_write(struct closure *cl)
ret = bch2_write_extent(op, wp);
BUG_ON(op->open_buckets_nr + wp->nr_ptrs - wp->first_ptr >
ARRAY_SIZE(op->open_buckets));
bch2_open_bucket_get(c, wp,
&op->open_buckets_nr,
op->open_buckets);
bch2_open_bucket_get(c, wp, &op->open_buckets);
bch2_alloc_sectors_done(c, wp);
if (ret < 0)
......
......@@ -75,7 +75,7 @@ static inline void bch2_write_op_init(struct bch_write_op *op, struct bch_fs *c,
op->nr_replicas = 0;
op->nr_replicas_required = c->opts.data_replicas_required;
op->alloc_reserve = RESERVE_NONE;
op->open_buckets_nr = 0;
op->open_buckets.nr = 0;
op->devs_have.nr = 0;
op->target = 0;
op->opts = opts;
......
......@@ -106,7 +106,6 @@ struct bch_write_op {
unsigned nr_replicas_required:4;
unsigned alloc_reserve:4;
u8 open_buckets_nr;
struct bch_devs_list devs_have;
u16 target;
u16 nonce;
......@@ -123,7 +122,7 @@ struct bch_write_op {
struct disk_reservation res;
u8 open_buckets[16];
struct open_buckets open_buckets;
/*
* If caller wants to flush but hasn't passed us a journal_seq ptr, we
......
......@@ -717,13 +717,13 @@ static int __bch2_set_nr_journal_buckets(struct bch_dev *ca, unsigned nr,
goto err;
}
} else {
int ob_idx = bch2_bucket_alloc(c, ca, RESERVE_ALLOC, false, cl);
if (ob_idx < 0) {
ob = bch2_bucket_alloc(c, ca, RESERVE_ALLOC,
false, cl);
if (IS_ERR(ob)) {
ret = cl ? -EAGAIN : -ENOSPC;
goto err;
}
ob = c->open_buckets + ob_idx;
bucket = sector_to_bucket(ca, ob->ptr.offset);
}
......
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