diff options
-rw-r--r-- | fs/bcachefs/alloc_background.c | 2 | ||||
-rw-r--r-- | fs/bcachefs/alloc_foreground.c | 415 | ||||
-rw-r--r-- | fs/bcachefs/alloc_foreground.h | 44 | ||||
-rw-r--r-- | fs/bcachefs/alloc_types.h | 12 | ||||
-rw-r--r-- | fs/bcachefs/btree_gc.c | 3 | ||||
-rw-r--r-- | fs/bcachefs/btree_types.h | 9 | ||||
-rw-r--r-- | fs/bcachefs/btree_update_interior.c | 28 | ||||
-rw-r--r-- | fs/bcachefs/btree_update_interior.h | 1 | ||||
-rw-r--r-- | fs/bcachefs/io.c | 12 | ||||
-rw-r--r-- | fs/bcachefs/io.h | 2 | ||||
-rw-r--r-- | fs/bcachefs/io_types.h | 3 | ||||
-rw-r--r-- | fs/bcachefs/journal.c | 6 |
12 files changed, 238 insertions, 299 deletions
diff --git a/fs/bcachefs/alloc_background.c b/fs/bcachefs/alloc_background.c index d22b2b72b0d1..45e8b124a9f3 100644 --- a/fs/bcachefs/alloc_background.c +++ b/fs/bcachefs/alloc_background.c @@ -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); diff --git a/fs/bcachefs/alloc_foreground.c b/fs/bcachefs/alloc_foreground.c index be25e01a7d00..562c1317aa9e 100644 --- a/fs/bcachefs/alloc_foreground.c +++ b/fs/bcachefs/alloc_foreground.c @@ -70,10 +70,9 @@ #include <linux/rcupdate.h> enum bucket_alloc_ret { - ALLOC_SUCCESS = 0, - OPEN_BUCKETS_EMPTY = -1, - FREELIST_EMPTY = -2, /* Allocator thread not keeping up */ - NO_DEVICES = -3, /* -EROFS */ + ALLOC_SUCCESS, + OPEN_BUCKETS_EMPTY, + FREELIST_EMPTY, /* Allocator thread not keeping up */ }; /* @@ -129,6 +128,43 @@ static struct open_bucket *bch2_open_bucket_alloc(struct bch_fs *c) return ob; } +static void open_bucket_free_unused(struct bch_fs *c, + struct write_point *wp, + struct open_bucket *ob) +{ + struct bch_dev *ca = bch_dev_bkey_exists(c, ob->ptr.dev); + + BUG_ON(ca->open_buckets_partial_nr >= + ARRAY_SIZE(ca->open_buckets_partial)); + + if (wp->type == BCH_DATA_USER) { + spin_lock(&c->freelist_lock); + ob->on_partial_list = true; + ca->open_buckets_partial[ca->open_buckets_partial_nr++] = + ob - c->open_buckets; + spin_unlock(&c->freelist_lock); + + closure_wake_up(&c->open_buckets_wait); + closure_wake_up(&c->freelist_wait); + } else { + bch2_open_bucket_put(c, ob); + } +} + +static void verify_not_stale(struct bch_fs *c, const struct open_buckets *obs) +{ +#ifdef CONFIG_BCACHEFS_DEBUG + struct open_bucket *ob; + unsigned i; + + open_bucket_for_each(c, obs, ob, i) { + struct bch_dev *ca = bch_dev_bkey_exists(c, ob->ptr.dev); + + BUG_ON(ptr_stale(ca, &ob->ptr)); + } +#endif +} + /* _only_ for allocating the journal on a new device: */ long bch2_bucket_alloc_new_fs(struct bch_dev *ca) { @@ -164,10 +200,10 @@ static inline unsigned open_buckets_reserved(enum alloc_reserve reserve) * * Returns index of bucket on success, 0 on failure * */ -int bch2_bucket_alloc(struct bch_fs *c, struct bch_dev *ca, - enum alloc_reserve reserve, - bool may_alloc_partial, - struct closure *cl) +struct open_bucket *bch2_bucket_alloc(struct bch_fs *c, struct bch_dev *ca, + enum alloc_reserve reserve, + bool may_alloc_partial, + struct closure *cl) { struct bucket_array *buckets; struct open_bucket *ob; @@ -177,10 +213,11 @@ int bch2_bucket_alloc(struct bch_fs *c, struct bch_dev *ca, if (may_alloc_partial && ca->open_buckets_partial_nr) { - int ret = ca->open_buckets_partial[--ca->open_buckets_partial_nr]; - c->open_buckets[ret].on_partial_list = false; + ob = c->open_buckets + + ca->open_buckets_partial[--ca->open_buckets_partial_nr]; + ob->on_partial_list = false; spin_unlock(&c->freelist_lock); - return ret; + return ob; } if (unlikely(c->open_buckets_nr_free <= open_buckets_reserved(reserve))) { @@ -188,7 +225,7 @@ int bch2_bucket_alloc(struct bch_fs *c, struct bch_dev *ca, closure_wait(&c->open_buckets_wait, cl); spin_unlock(&c->freelist_lock); trace_open_bucket_alloc_fail(ca, reserve); - return OPEN_BUCKETS_EMPTY; + return ERR_PTR(-OPEN_BUCKETS_EMPTY); } if (likely(fifo_pop(&ca->free[RESERVE_NONE], bucket))) @@ -219,7 +256,7 @@ int bch2_bucket_alloc(struct bch_fs *c, struct bch_dev *ca, spin_unlock(&c->freelist_lock); trace_bucket_alloc_fail(ca, reserve); - return FREELIST_EMPTY; + return ERR_PTR(-FREELIST_EMPTY); out: verify_not_on_freelist(c, ca, bucket); @@ -245,7 +282,7 @@ out: bch2_wake_allocator(ca); trace_bucket_alloc(ca, reserve); - return ob - c->open_buckets; + return ob; } static int __dev_alloc_cmp(struct write_point *wp, @@ -292,155 +329,114 @@ void bch2_wp_rescale(struct bch_fs *c, struct bch_dev *ca, *v = *v < scale ? 0 : *v - scale; } -static enum bucket_alloc_ret bch2_bucket_alloc_set(struct bch_fs *c, - struct write_point *wp, - unsigned nr_replicas, - enum alloc_reserve reserve, - struct bch_devs_mask *devs, - struct closure *cl) +static int bch2_bucket_alloc_set(struct bch_fs *c, + struct open_buckets *ptrs, + struct write_point *wp, + struct bch_devs_mask *devs_may_alloc, + unsigned nr_replicas, + unsigned *nr_effective, + bool *have_cache, + enum alloc_reserve reserve, + struct closure *cl) { - enum bucket_alloc_ret ret = NO_DEVICES; - struct dev_alloc_list devs_sorted; + struct dev_alloc_list devs_sorted = + bch2_wp_alloc_list(c, wp, devs_may_alloc); struct bch_dev *ca; - unsigned i, nr_ptrs_effective = 0; - bool have_cache_dev = false; - - BUG_ON(nr_replicas > ARRAY_SIZE(wp->ptrs)); - - for (i = wp->first_ptr; i < wp->nr_ptrs; i++) { - ca = bch_dev_bkey_exists(c, wp->ptrs[i]->ptr.dev); - - nr_ptrs_effective += ca->mi.durability; - have_cache_dev |= !ca->mi.durability; - } - - if (nr_ptrs_effective >= nr_replicas) - return ALLOC_SUCCESS; + bool alloc_failure = false; + unsigned i; - devs_sorted = bch2_wp_alloc_list(c, wp, devs); + BUG_ON(*nr_effective >= nr_replicas); for (i = 0; i < devs_sorted.nr; i++) { - int ob; + struct open_bucket *ob; ca = rcu_dereference(c->devs[devs_sorted.devs[i]]); if (!ca) continue; if (!ca->mi.durability && - (have_cache_dev || + (*have_cache || wp->type != BCH_DATA_USER)) continue; ob = bch2_bucket_alloc(c, ca, reserve, wp->type == BCH_DATA_USER, cl); - if (ob < 0) { - ret = ob; + if (IS_ERR(ob)) { + enum bucket_alloc_ret ret = -PTR_ERR(ob); + + WARN_ON(reserve == RESERVE_MOVINGGC && + ret != OPEN_BUCKETS_EMPTY); + + if (cl) + return -EAGAIN; if (ret == OPEN_BUCKETS_EMPTY) - break; + return -ENOSPC; + alloc_failure = true; continue; } - BUG_ON(ob <= 0 || ob > U8_MAX); - BUG_ON(wp->nr_ptrs >= ARRAY_SIZE(wp->ptrs)); + __clear_bit(ca->dev_idx, devs_may_alloc->d); + *nr_effective += ca->mi.durability; + *have_cache |= !ca->mi.durability; - wp->ptrs[wp->nr_ptrs++] = c->open_buckets + ob; + ob_push(c, ptrs, ob); bch2_wp_rescale(c, ca, wp); - nr_ptrs_effective += ca->mi.durability; - have_cache_dev |= !ca->mi.durability; - - __clear_bit(ca->dev_idx, devs->d); - - if (nr_ptrs_effective >= nr_replicas) { - ret = ALLOC_SUCCESS; - break; - } + if (*nr_effective >= nr_replicas) + return 0; } - EBUG_ON(reserve == RESERVE_MOVINGGC && - ret != ALLOC_SUCCESS && - ret != OPEN_BUCKETS_EMPTY); - - switch (ret) { - case ALLOC_SUCCESS: - return 0; - case NO_DEVICES: - return -EROFS; - case FREELIST_EMPTY: - case OPEN_BUCKETS_EMPTY: - return cl ? -EAGAIN : -ENOSPC; - default: - BUG(); - } + return alloc_failure ? -ENOSPC : -EROFS; } /* Sector allocator */ -static void bch2_writepoint_drop_ptr(struct bch_fs *c, - struct write_point *wp, - unsigned i) +static int get_buckets_from_writepoint(struct bch_fs *c, + struct open_buckets *ptrs, + struct write_point *wp, + struct bch_devs_mask *devs_may_alloc, + unsigned nr_replicas, + unsigned *nr_effective, + bool *have_cache) { - struct open_bucket *ob = wp->ptrs[i]; - struct bch_dev *ca = bch_dev_bkey_exists(c, ob->ptr.dev); - - BUG_ON(ca->open_buckets_partial_nr >= - ARRAY_SIZE(ca->open_buckets_partial)); - - if (wp->type == BCH_DATA_USER) { - spin_lock(&c->freelist_lock); - ob->on_partial_list = true; - ca->open_buckets_partial[ca->open_buckets_partial_nr++] = - ob - c->open_buckets; - spin_unlock(&c->freelist_lock); - - closure_wake_up(&c->open_buckets_wait); - closure_wake_up(&c->freelist_wait); - } else { - bch2_open_bucket_put(c, ob); - } - - array_remove_item(wp->ptrs, wp->nr_ptrs, i); - - if (i < wp->first_ptr) - wp->first_ptr--; -} - -void bch2_writepoint_drop_ptrs(struct bch_fs *c, - struct write_point *wp, - u16 target, bool in_target) -{ - int i; - - for (i = wp->first_ptr - 1; i >= 0; --i) - if (bch2_dev_in_target(c, wp->ptrs[i]->ptr.dev, - target) == in_target) - bch2_writepoint_drop_ptr(c, wp, i); -} - -static void verify_not_stale(struct bch_fs *c, const struct write_point *wp) -{ -#ifdef CONFIG_BCACHEFS_DEBUG + struct open_buckets ptrs_skip = { .nr = 0 }; struct open_bucket *ob; unsigned i; - writepoint_for_each_ptr_all(wp, ob, i) { + open_bucket_for_each(c, &wp->ptrs, ob, i) { struct bch_dev *ca = bch_dev_bkey_exists(c, ob->ptr.dev); - BUG_ON(ptr_stale(ca, &ob->ptr)); + if (*nr_effective < nr_replicas && + test_bit(ob->ptr.dev, devs_may_alloc->d) && + (ca->mi.durability || + (wp->type == BCH_DATA_USER && !*have_cache))) { + __clear_bit(ob->ptr.dev, devs_may_alloc->d); + *nr_effective += ca->mi.durability; + *have_cache |= !ca->mi.durability; + + ob_push(c, ptrs, ob); + } else { + ob_push(c, &ptrs_skip, ob); + } } -#endif + wp->ptrs = ptrs_skip; + + return *nr_effective < nr_replicas ? -ENOSPC : 0; } static int open_bucket_add_buckets(struct bch_fs *c, - u16 target, + struct open_buckets *ptrs, struct write_point *wp, struct bch_devs_list *devs_have, + u16 target, unsigned nr_replicas, + unsigned *nr_effective, + bool *have_cache, enum alloc_reserve reserve, struct closure *cl) { - struct bch_devs_mask devs = c->rw_devs[wp->type]; + struct bch_devs_mask devs; const struct bch_devs_mask *t; struct open_bucket *ob; unsigned i; @@ -449,19 +445,38 @@ static int open_bucket_add_buckets(struct bch_fs *c, percpu_down_read(&c->usage_lock); rcu_read_lock(); + devs = c->rw_devs[wp->type]; + /* Don't allocate from devices we already have pointers to: */ for (i = 0; i < devs_have->nr; i++) __clear_bit(devs_have->devs[i], devs.d); - writepoint_for_each_ptr_all(wp, ob, i) + open_bucket_for_each(c, ptrs, ob, i) __clear_bit(ob->ptr.dev, devs.d); t = bch2_target_to_mask(c, target); if (t) bitmap_and(devs.d, devs.d, t->d, BCH_SB_MEMBERS_MAX); - ret = bch2_bucket_alloc_set(c, wp, nr_replicas, reserve, &devs, cl); + ret = get_buckets_from_writepoint(c, ptrs, wp, &devs, + nr_replicas, nr_effective, have_cache); + if (!ret) + goto out; + /* + * Try nonblocking first, so that if one device is full we'll try from + * other devices: + */ + ret = bch2_bucket_alloc_set(c, ptrs, wp, &devs, + nr_replicas, nr_effective, have_cache, + reserve, NULL); + if (!ret || ret == -EROFS || !cl) + goto out; + + ret = bch2_bucket_alloc_set(c, ptrs, wp, &devs, + nr_replicas, nr_effective, have_cache, + reserve, cl); +out: rcu_read_unlock(); percpu_up_read(&c->usage_lock); @@ -471,13 +486,18 @@ static int open_bucket_add_buckets(struct bch_fs *c, void bch2_writepoint_stop(struct bch_fs *c, struct bch_dev *ca, struct write_point *wp) { - struct bch_devs_mask not_self; - - bitmap_complement(not_self.d, ca->self.d, BCH_SB_MEMBERS_MAX); + struct open_buckets ptrs = { .nr = 0 }; + struct open_bucket *ob; + unsigned i; mutex_lock(&wp->lock); - wp->first_ptr = wp->nr_ptrs; - bch2_writepoint_drop_ptrs(c, wp, dev_to_target(ca->dev_idx), true); + open_bucket_for_each(c, &wp->ptrs, ob, i) + if (ob->ptr.dev == ca->dev_idx) + open_bucket_free_unused(c, wp, ob); + else + ob_push(c, &ptrs, ob); + + wp->ptrs = ptrs; mutex_unlock(&wp->lock); } @@ -558,134 +578,64 @@ struct write_point *bch2_alloc_sectors_start(struct bch_fs *c, { struct write_point *wp; struct open_bucket *ob; - struct bch_dev *ca; - unsigned nr_ptrs_have, nr_ptrs_effective; - int ret, i, cache_idx = -1; + unsigned nr_effective = 0; + struct open_buckets ptrs = { .nr = 0 }; + bool have_cache = false; + int ret = 0, i; BUG_ON(!nr_replicas || !nr_replicas_required); wp = writepoint_find(c, write_point.v); - wp->first_ptr = 0; - - /* does writepoint have ptrs we can't use? */ - writepoint_for_each_ptr(wp, ob, i) - if (bch2_dev_list_has_dev(*devs_have, ob->ptr.dev)) { - swap(wp->ptrs[i], wp->ptrs[wp->first_ptr]); - wp->first_ptr++; - } - - nr_ptrs_have = wp->first_ptr; - - /* does writepoint have ptrs we don't want to use? */ - if (target) - writepoint_for_each_ptr(wp, ob, i) - if (!bch2_dev_in_target(c, ob->ptr.dev, target)) { - swap(wp->ptrs[i], wp->ptrs[wp->first_ptr]); - wp->first_ptr++; - } - - if (flags & BCH_WRITE_ONLY_SPECIFIED_DEVS) { - ret = open_bucket_add_buckets(c, target, wp, devs_have, - nr_replicas, reserve, cl); + if (!target || (flags & BCH_WRITE_ONLY_SPECIFIED_DEVS)) { + ret = open_bucket_add_buckets(c, &ptrs, wp, devs_have, target, + nr_replicas, &nr_effective, + &have_cache, reserve, cl); } else { - ret = open_bucket_add_buckets(c, target, wp, devs_have, - nr_replicas, reserve, NULL); + ret = open_bucket_add_buckets(c, &ptrs, wp, devs_have, target, + nr_replicas, &nr_effective, + &have_cache, reserve, NULL); if (!ret) goto alloc_done; - wp->first_ptr = nr_ptrs_have; - - ret = open_bucket_add_buckets(c, 0, wp, devs_have, - nr_replicas, reserve, cl); + ret = open_bucket_add_buckets(c, &ptrs, wp, devs_have, 0, + nr_replicas, &nr_effective, + &have_cache, reserve, cl); } - - if (ret && ret != -EROFS) - goto err; alloc_done: - /* check for more than one cache: */ - for (i = wp->nr_ptrs - 1; i >= wp->first_ptr; --i) { - ca = bch_dev_bkey_exists(c, wp->ptrs[i]->ptr.dev); - - if (ca->mi.durability) - continue; - - /* - * if we ended up with more than one cache device, prefer the - * one in the target we want: - */ - if (cache_idx >= 0) { - if (!bch2_dev_in_target(c, wp->ptrs[i]->ptr.dev, - target)) { - bch2_writepoint_drop_ptr(c, wp, i); - } else { - bch2_writepoint_drop_ptr(c, wp, cache_idx); - cache_idx = i; - } - } else { - cache_idx = i; - } - } - - /* we might have more effective replicas than required: */ - nr_ptrs_effective = 0; - writepoint_for_each_ptr(wp, ob, i) { - ca = bch_dev_bkey_exists(c, ob->ptr.dev); - nr_ptrs_effective += ca->mi.durability; - } + BUG_ON(!ret && nr_effective < nr_replicas); if (ret == -EROFS && - nr_ptrs_effective >= nr_replicas_required) + nr_effective >= nr_replicas_required) ret = 0; if (ret) goto err; - if (nr_ptrs_effective > nr_replicas) { - writepoint_for_each_ptr(wp, ob, i) { - ca = bch_dev_bkey_exists(c, ob->ptr.dev); - - if (ca->mi.durability && - ca->mi.durability <= nr_ptrs_effective - nr_replicas && - !bch2_dev_in_target(c, ob->ptr.dev, target)) { - swap(wp->ptrs[i], wp->ptrs[wp->first_ptr]); - wp->first_ptr++; - nr_ptrs_effective -= ca->mi.durability; - } - } - } - - if (nr_ptrs_effective > nr_replicas) { - writepoint_for_each_ptr(wp, ob, i) { - ca = bch_dev_bkey_exists(c, ob->ptr.dev); - - if (ca->mi.durability && - ca->mi.durability <= nr_ptrs_effective - nr_replicas) { - swap(wp->ptrs[i], wp->ptrs[wp->first_ptr]); - wp->first_ptr++; - nr_ptrs_effective -= ca->mi.durability; - } - } - } - - /* Remove pointers we don't want to use: */ - if (target) - bch2_writepoint_drop_ptrs(c, wp, target, false); + /* Free buckets we didn't use: */ + open_bucket_for_each(c, &wp->ptrs, ob, i) + open_bucket_free_unused(c, wp, ob); - BUG_ON(wp->first_ptr >= wp->nr_ptrs); - BUG_ON(nr_ptrs_effective < nr_replicas_required); + wp->ptrs = ptrs; wp->sectors_free = UINT_MAX; - writepoint_for_each_ptr(wp, ob, i) + open_bucket_for_each(c, &wp->ptrs, ob, i) wp->sectors_free = min(wp->sectors_free, ob->sectors_free); BUG_ON(!wp->sectors_free || wp->sectors_free == UINT_MAX); - verify_not_stale(c, wp); + verify_not_stale(c, &wp->ptrs); return wp; err: + open_bucket_for_each(c, &wp->ptrs, ob, i) + if (ptrs.nr < ARRAY_SIZE(ptrs.v)) + ob_push(c, &ptrs, ob); + else + open_bucket_free_unused(c, wp, ob); + wp->ptrs = ptrs; + mutex_unlock(&wp->lock); return ERR_PTR(ret); } @@ -703,7 +653,7 @@ void bch2_alloc_sectors_append_ptrs(struct bch_fs *c, struct write_point *wp, BUG_ON(sectors > wp->sectors_free); wp->sectors_free -= sectors; - writepoint_for_each_ptr(wp, ob, i) { + open_bucket_for_each(c, &wp->ptrs, ob, i) { struct bch_dev *ca = bch_dev_bkey_exists(c, ob->ptr.dev); struct bch_extent_ptr tmp = ob->ptr; @@ -726,16 +676,15 @@ void bch2_alloc_sectors_append_ptrs(struct bch_fs *c, struct write_point *wp, */ void bch2_alloc_sectors_done(struct bch_fs *c, struct write_point *wp) { - int i; + struct open_buckets ptrs = { .nr = 0 }, keep = { .nr = 0 }; + struct open_bucket *ob; + unsigned i; - for (i = wp->nr_ptrs - 1; i >= 0; --i) { - struct open_bucket *ob = wp->ptrs[i]; - - if (!ob->sectors_free) { - array_remove_item(wp->ptrs, wp->nr_ptrs, i); - bch2_open_bucket_put(c, ob); - } - } + open_bucket_for_each(c, &wp->ptrs, ob, i) + ob_push(c, !ob->sectors_free ? &ptrs : &keep, ob); + wp->ptrs = keep; mutex_unlock(&wp->lock); + + bch2_open_buckets_put(c, &ptrs); } diff --git a/fs/bcachefs/alloc_foreground.h b/fs/bcachefs/alloc_foreground.h index 1c738e4ba6c9..609685d08642 100644 --- a/fs/bcachefs/alloc_foreground.h +++ b/fs/bcachefs/alloc_foreground.h @@ -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) { diff --git a/fs/bcachefs/alloc_types.h b/fs/bcachefs/alloc_types.h index 035c50052167..e0306d68ae9f 100644 --- a/fs/bcachefs/alloc_types.h +++ b/fs/bcachefs/alloc_types.h @@ -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]; }; diff --git a/fs/bcachefs/btree_gc.c b/fs/bcachefs/btree_gc.c index 7fd75435542b..d07a6b297078 100644 --- a/fs/bcachefs/btree_gc.c +++ b/fs/bcachefs/btree_gc.c @@ -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 @@ next: 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++) { diff --git a/fs/bcachefs/btree_types.h b/fs/bcachefs/btree_types.h index 5053ed5f2762..dd9660a9f12b 100644 --- a/fs/bcachefs/btree_types.h +++ b/fs/bcachefs/btree_types.h @@ -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; diff --git a/fs/bcachefs/btree_update_interior.c b/fs/bcachefs/btree_update_interior.c index 0ca998035bab..26721c5a871c 100644 --- a/fs/bcachefs/btree_update_interior.c +++ b/fs/bcachefs/btree_update_interior.c @@ -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 @@ retry: 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 @@ retry: 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 @@ retry: 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); diff --git a/fs/bcachefs/btree_update_interior.h b/fs/bcachefs/btree_update_interior.h index b24988352b03..e5156e908110 100644 --- a/fs/bcachefs/btree_update_interior.h +++ b/fs/bcachefs/btree_update_interior.h @@ -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 *, diff --git a/fs/bcachefs/io.c b/fs/bcachefs/io.c index dfd2d3b708c5..d5c17024c884 100644 --- a/fs/bcachefs/io.c +++ b/fs/bcachefs/io.c @@ -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 @@ again: 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) diff --git a/fs/bcachefs/io.h b/fs/bcachefs/io.h index 62f5861005ea..1cc040a413ee 100644 --- a/fs/bcachefs/io.h +++ b/fs/bcachefs/io.h @@ -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; diff --git a/fs/bcachefs/io_types.h b/fs/bcachefs/io_types.h index b313128ed857..48273bb68c94 100644 --- a/fs/bcachefs/io_types.h +++ b/fs/bcachefs/io_types.h @@ -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 diff --git a/fs/bcachefs/journal.c b/fs/bcachefs/journal.c index 97fbc2698dc0..7499e15a2982 100644 --- a/fs/bcachefs/journal.c +++ b/fs/bcachefs/journal.c @@ -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); } |