1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright 2012 Google, Inc.
5 * Foreground allocator code: allocate buckets from freelist, and allocate in
6 * sector granularity from writepoints.
8 * bch2_bucket_alloc() allocates a single bucket from a specific device.
10 * bch2_bucket_alloc_set() allocates one or more buckets from different devices
11 * in a given filesystem.
15 #include "alloc_background.h"
16 #include "alloc_foreground.h"
21 #include "disk_groups.h"
25 #include <linux/math64.h>
26 #include <linux/rculist.h>
27 #include <linux/rcupdate.h>
28 #include <trace/events/bcachefs.h>
31 * Open buckets represent a bucket that's currently being allocated from. They
34 * - They track buckets that have been partially allocated, allowing for
35 * sub-bucket sized allocations - they're used by the sector allocator below
37 * - They provide a reference to the buckets they own that mark and sweep GC
38 * can find, until the new allocation has a pointer to it inserted into the
41 * When allocating some space with the sector allocator, the allocation comes
42 * with a reference to an open bucket - the caller is required to put that
43 * reference _after_ doing the index update that makes its allocation reachable.
46 static void bch2_open_bucket_hash_add(struct bch_fs *c, struct open_bucket *ob)
48 open_bucket_idx_t idx = ob - c->open_buckets;
49 open_bucket_idx_t *slot = open_bucket_hashslot(c, ob->dev, ob->bucket);
55 static void bch2_open_bucket_hash_remove(struct bch_fs *c, struct open_bucket *ob)
57 open_bucket_idx_t idx = ob - c->open_buckets;
58 open_bucket_idx_t *slot = open_bucket_hashslot(c, ob->dev, ob->bucket);
60 while (*slot != idx) {
62 slot = &c->open_buckets[*slot].hash;
69 void __bch2_open_bucket_put(struct bch_fs *c, struct open_bucket *ob)
71 struct bch_dev *ca = bch_dev_bkey_exists(c, ob->dev);
74 bch2_ec_bucket_written(c, ob);
78 percpu_down_read(&c->mark_lock);
81 bch2_mark_alloc_bucket(c, ca, ob->bucket, false);
85 spin_unlock(&ob->lock);
86 percpu_up_read(&c->mark_lock);
88 spin_lock(&c->freelist_lock);
89 bch2_open_bucket_hash_remove(c, ob);
91 ob->freelist = c->open_buckets_freelist;
92 c->open_buckets_freelist = ob - c->open_buckets;
94 c->open_buckets_nr_free++;
95 ca->nr_open_buckets--;
96 spin_unlock(&c->freelist_lock);
98 closure_wake_up(&c->open_buckets_wait);
101 void bch2_open_bucket_write_error(struct bch_fs *c,
102 struct open_buckets *obs,
105 struct open_bucket *ob;
108 open_bucket_for_each(c, obs, ob, i)
109 if (ob->dev == dev && ob->ec)
110 bch2_ec_bucket_cancel(c, ob);
113 static struct open_bucket *bch2_open_bucket_alloc(struct bch_fs *c)
115 struct open_bucket *ob;
117 BUG_ON(!c->open_buckets_freelist || !c->open_buckets_nr_free);
119 ob = c->open_buckets + c->open_buckets_freelist;
120 c->open_buckets_freelist = ob->freelist;
121 atomic_set(&ob->pin, 1);
124 c->open_buckets_nr_free--;
128 static void open_bucket_free_unused(struct bch_fs *c,
129 struct write_point *wp,
130 struct open_bucket *ob)
132 struct bch_dev *ca = bch_dev_bkey_exists(c, ob->dev);
133 bool may_realloc = wp->data_type == BCH_DATA_user;
135 BUG_ON(ca->open_buckets_partial_nr >
136 ARRAY_SIZE(ca->open_buckets_partial));
138 if (ca->open_buckets_partial_nr <
139 ARRAY_SIZE(ca->open_buckets_partial) &&
141 spin_lock(&c->freelist_lock);
142 ob->on_partial_list = true;
143 ca->open_buckets_partial[ca->open_buckets_partial_nr++] =
144 ob - c->open_buckets;
145 spin_unlock(&c->freelist_lock);
147 closure_wake_up(&c->open_buckets_wait);
148 closure_wake_up(&c->freelist_wait);
150 bch2_open_bucket_put(c, ob);
154 static void verify_not_stale(struct bch_fs *c, const struct open_buckets *obs)
156 #ifdef CONFIG_BCACHEFS_DEBUG
157 struct open_bucket *ob;
161 open_bucket_for_each(c, obs, ob, i) {
162 struct bch_dev *ca = bch_dev_bkey_exists(c, ob->dev);
164 BUG_ON(*bucket_gen(ca, ob->bucket) != ob->gen);
170 /* _only_ for allocating the journal on a new device: */
171 long bch2_bucket_alloc_new_fs(struct bch_dev *ca)
173 while (ca->new_fs_bucket_idx < ca->mi.nbuckets) {
174 u64 b = ca->new_fs_bucket_idx++;
176 if (!is_superblock_bucket(ca, b) &&
177 (!ca->buckets_nouse || !test_bit(b, ca->buckets_nouse)))
184 static inline unsigned open_buckets_reserved(enum alloc_reserve reserve)
188 case RESERVE_BTREE_MOVINGGC:
190 case RESERVE_MOVINGGC:
191 return OPEN_BUCKETS_COUNT / 4;
193 return OPEN_BUCKETS_COUNT / 2;
198 * bch_bucket_alloc - allocate a single bucket from a specific device
200 * Returns index of bucket on success, 0 on failure
202 struct open_bucket *bch2_bucket_alloc(struct bch_fs *c, struct bch_dev *ca,
203 enum alloc_reserve reserve,
204 bool may_alloc_partial,
207 struct open_bucket *ob;
210 spin_lock(&c->freelist_lock);
212 if (may_alloc_partial) {
215 for (i = ca->open_buckets_partial_nr - 1; i >= 0; --i) {
216 ob = c->open_buckets + ca->open_buckets_partial[i];
218 if (reserve <= ob->alloc_reserve) {
219 array_remove_item(ca->open_buckets_partial,
220 ca->open_buckets_partial_nr,
222 ob->on_partial_list = false;
223 ob->alloc_reserve = reserve;
224 spin_unlock(&c->freelist_lock);
230 if (unlikely(c->open_buckets_nr_free <= open_buckets_reserved(reserve))) {
232 closure_wait(&c->open_buckets_wait, cl);
234 if (!c->blocked_allocate_open_bucket)
235 c->blocked_allocate_open_bucket = local_clock();
237 spin_unlock(&c->freelist_lock);
238 trace_open_bucket_alloc_fail(ca, reserve);
239 return ERR_PTR(-OPEN_BUCKETS_EMPTY);
242 if (likely(fifo_pop(&ca->free[RESERVE_NONE], b)))
246 case RESERVE_BTREE_MOVINGGC:
247 case RESERVE_MOVINGGC:
248 if (fifo_pop(&ca->free[RESERVE_MOVINGGC], b))
256 closure_wait(&c->freelist_wait, cl);
258 if (!c->blocked_allocate)
259 c->blocked_allocate = local_clock();
261 spin_unlock(&c->freelist_lock);
263 trace_bucket_alloc_fail(ca, reserve);
264 return ERR_PTR(-FREELIST_EMPTY);
266 verify_not_on_freelist(c, ca, b);
268 ob = bch2_open_bucket_alloc(c);
270 spin_lock(&ob->lock);
273 ob->sectors_free = ca->mi.bucket_size;
274 ob->alloc_reserve = reserve;
275 ob->dev = ca->dev_idx;
276 ob->gen = *bucket_gen(ca, b);
278 spin_unlock(&ob->lock);
280 ca->nr_open_buckets++;
281 bch2_open_bucket_hash_add(c, ob);
283 if (c->blocked_allocate_open_bucket) {
284 bch2_time_stats_update(
285 &c->times[BCH_TIME_blocked_allocate_open_bucket],
286 c->blocked_allocate_open_bucket);
287 c->blocked_allocate_open_bucket = 0;
290 if (c->blocked_allocate) {
291 bch2_time_stats_update(
292 &c->times[BCH_TIME_blocked_allocate],
293 c->blocked_allocate);
294 c->blocked_allocate = 0;
297 spin_unlock(&c->freelist_lock);
299 bch2_wake_allocator(ca);
301 trace_bucket_alloc(ca, reserve);
305 static int __dev_stripe_cmp(struct dev_stripe_state *stripe,
306 unsigned l, unsigned r)
308 return ((stripe->next_alloc[l] > stripe->next_alloc[r]) -
309 (stripe->next_alloc[l] < stripe->next_alloc[r]));
312 #define dev_stripe_cmp(l, r) __dev_stripe_cmp(stripe, l, r)
314 struct dev_alloc_list bch2_dev_alloc_list(struct bch_fs *c,
315 struct dev_stripe_state *stripe,
316 struct bch_devs_mask *devs)
318 struct dev_alloc_list ret = { .nr = 0 };
321 for_each_set_bit(i, devs->d, BCH_SB_MEMBERS_MAX)
322 ret.devs[ret.nr++] = i;
324 bubble_sort(ret.devs, ret.nr, dev_stripe_cmp);
328 void bch2_dev_stripe_increment(struct bch_dev *ca,
329 struct dev_stripe_state *stripe)
331 u64 *v = stripe->next_alloc + ca->dev_idx;
332 u64 free_space = dev_buckets_available(ca);
333 u64 free_space_inv = free_space
334 ? div64_u64(1ULL << 48, free_space)
338 if (*v + free_space_inv >= *v)
339 *v += free_space_inv;
343 for (v = stripe->next_alloc;
344 v < stripe->next_alloc + ARRAY_SIZE(stripe->next_alloc); v++)
345 *v = *v < scale ? 0 : *v - scale;
348 #define BUCKET_MAY_ALLOC_PARTIAL (1 << 0)
349 #define BUCKET_ALLOC_USE_DURABILITY (1 << 1)
351 static void add_new_bucket(struct bch_fs *c,
352 struct open_buckets *ptrs,
353 struct bch_devs_mask *devs_may_alloc,
354 unsigned *nr_effective,
357 struct open_bucket *ob)
359 unsigned durability =
360 bch_dev_bkey_exists(c, ob->dev)->mi.durability;
362 __clear_bit(ob->dev, devs_may_alloc->d);
363 *nr_effective += (flags & BUCKET_ALLOC_USE_DURABILITY)
365 *have_cache |= !durability;
367 ob_push(c, ptrs, ob);
370 int bch2_bucket_alloc_set(struct bch_fs *c,
371 struct open_buckets *ptrs,
372 struct dev_stripe_state *stripe,
373 struct bch_devs_mask *devs_may_alloc,
374 unsigned nr_replicas,
375 unsigned *nr_effective,
377 enum alloc_reserve reserve,
381 struct dev_alloc_list devs_sorted =
382 bch2_dev_alloc_list(c, stripe, devs_may_alloc);
384 int ret = -INSUFFICIENT_DEVICES;
387 BUG_ON(*nr_effective >= nr_replicas);
389 for (i = 0; i < devs_sorted.nr; i++) {
390 struct open_bucket *ob;
392 ca = rcu_dereference(c->devs[devs_sorted.devs[i]]);
396 if (!ca->mi.durability && *have_cache)
399 ob = bch2_bucket_alloc(c, ca, reserve,
400 flags & BUCKET_MAY_ALLOC_PARTIAL, cl);
409 add_new_bucket(c, ptrs, devs_may_alloc,
410 nr_effective, have_cache, flags, ob);
412 bch2_dev_stripe_increment(ca, stripe);
414 if (*nr_effective >= nr_replicas)
421 /* Allocate from stripes: */
424 * if we can't allocate a new stripe because there are already too many
425 * partially filled stripes, force allocating from an existing stripe even when
426 * it's to a device we don't want:
429 static int bucket_alloc_from_stripe(struct bch_fs *c,
430 struct open_buckets *ptrs,
431 struct write_point *wp,
432 struct bch_devs_mask *devs_may_alloc,
434 unsigned erasure_code,
435 unsigned nr_replicas,
436 unsigned *nr_effective,
441 struct dev_alloc_list devs_sorted;
442 struct ec_stripe_head *h;
443 struct open_bucket *ob;
453 if (ec_open_bucket(c, ptrs))
456 h = bch2_ec_stripe_head_get(c, target, 0, nr_replicas - 1,
457 wp == &c->copygc_write_point,
464 devs_sorted = bch2_dev_alloc_list(c, &wp->stripe, devs_may_alloc);
466 for (i = 0; i < devs_sorted.nr; i++)
467 for (ec_idx = 0; ec_idx < h->s->nr_data; ec_idx++) {
468 if (!h->s->blocks[ec_idx])
471 ob = c->open_buckets + h->s->blocks[ec_idx];
472 if (ob->dev == devs_sorted.devs[i] &&
473 !test_and_set_bit(ec_idx, h->s->blocks_allocated))
478 ca = bch_dev_bkey_exists(c, ob->dev);
483 add_new_bucket(c, ptrs, devs_may_alloc,
484 nr_effective, have_cache, flags, ob);
485 atomic_inc(&h->s->pin);
487 bch2_ec_stripe_head_put(c, h);
491 /* Sector allocator */
493 static void get_buckets_from_writepoint(struct bch_fs *c,
494 struct open_buckets *ptrs,
495 struct write_point *wp,
496 struct bch_devs_mask *devs_may_alloc,
497 unsigned nr_replicas,
498 unsigned *nr_effective,
503 struct open_buckets ptrs_skip = { .nr = 0 };
504 struct open_bucket *ob;
507 open_bucket_for_each(c, &wp->ptrs, ob, i) {
508 struct bch_dev *ca = bch_dev_bkey_exists(c, ob->dev);
510 if (*nr_effective < nr_replicas &&
511 test_bit(ob->dev, devs_may_alloc->d) &&
512 (ca->mi.durability ||
513 (wp->data_type == BCH_DATA_user && !*have_cache)) &&
514 (ob->ec || !need_ec)) {
515 add_new_bucket(c, ptrs, devs_may_alloc,
516 nr_effective, have_cache,
519 ob_push(c, &ptrs_skip, ob);
522 wp->ptrs = ptrs_skip;
525 static int open_bucket_add_buckets(struct bch_fs *c,
526 struct open_buckets *ptrs,
527 struct write_point *wp,
528 struct bch_devs_list *devs_have,
530 unsigned erasure_code,
531 unsigned nr_replicas,
532 unsigned *nr_effective,
534 enum alloc_reserve reserve,
538 struct bch_devs_mask devs;
539 struct open_bucket *ob;
540 struct closure *cl = NULL;
545 devs = target_rw_devs(c, wp->data_type, target);
548 /* Don't allocate from devices we already have pointers to: */
549 for (i = 0; i < devs_have->nr; i++)
550 __clear_bit(devs_have->devs[i], devs.d);
552 open_bucket_for_each(c, ptrs, ob, i)
553 __clear_bit(ob->dev, devs.d);
556 if (!ec_open_bucket(c, ptrs)) {
557 get_buckets_from_writepoint(c, ptrs, wp, &devs,
558 nr_replicas, nr_effective,
559 have_cache, flags, true);
560 if (*nr_effective >= nr_replicas)
564 if (!ec_open_bucket(c, ptrs)) {
565 ret = bucket_alloc_from_stripe(c, ptrs, wp, &devs,
566 target, erasure_code,
567 nr_replicas, nr_effective,
568 have_cache, flags, _cl);
569 if (ret == -FREELIST_EMPTY ||
570 ret == -OPEN_BUCKETS_EMPTY)
572 if (*nr_effective >= nr_replicas)
577 get_buckets_from_writepoint(c, ptrs, wp, &devs,
578 nr_replicas, nr_effective,
579 have_cache, flags, false);
580 if (*nr_effective >= nr_replicas)
583 percpu_down_read(&c->mark_lock);
588 * Try nonblocking first, so that if one device is full we'll try from
591 ret = bch2_bucket_alloc_set(c, ptrs, &wp->stripe, &devs,
592 nr_replicas, nr_effective, have_cache,
594 if (ret && ret != -INSUFFICIENT_DEVICES && !cl && _cl) {
600 percpu_up_read(&c->mark_lock);
605 void bch2_open_buckets_stop_dev(struct bch_fs *c, struct bch_dev *ca,
606 struct open_buckets *obs)
608 struct open_buckets ptrs = { .nr = 0 };
609 struct open_bucket *ob, *ob2;
612 open_bucket_for_each(c, obs, ob, i) {
613 bool drop = !ca || ob->dev == ca->dev_idx;
615 if (!drop && ob->ec) {
616 mutex_lock(&ob->ec->lock);
617 for (j = 0; j < ob->ec->new_stripe.key.v.nr_blocks; j++) {
618 if (!ob->ec->blocks[j])
621 ob2 = c->open_buckets + ob->ec->blocks[j];
622 drop |= ob2->dev == ca->dev_idx;
624 mutex_unlock(&ob->ec->lock);
628 bch2_open_bucket_put(c, ob);
630 ob_push(c, &ptrs, ob);
636 void bch2_writepoint_stop(struct bch_fs *c, struct bch_dev *ca,
637 struct write_point *wp)
639 mutex_lock(&wp->lock);
640 bch2_open_buckets_stop_dev(c, ca, &wp->ptrs);
641 mutex_unlock(&wp->lock);
644 static inline struct hlist_head *writepoint_hash(struct bch_fs *c,
645 unsigned long write_point)
648 hash_long(write_point, ilog2(ARRAY_SIZE(c->write_points_hash)));
650 return &c->write_points_hash[hash];
653 static struct write_point *__writepoint_find(struct hlist_head *head,
654 unsigned long write_point)
656 struct write_point *wp;
659 hlist_for_each_entry_rcu(wp, head, node)
660 if (wp->write_point == write_point)
668 static inline bool too_many_writepoints(struct bch_fs *c, unsigned factor)
670 u64 stranded = c->write_points_nr * c->bucket_size_max;
671 u64 free = bch2_fs_usage_read_short(c).free;
673 return stranded * factor > free;
676 static bool try_increase_writepoints(struct bch_fs *c)
678 struct write_point *wp;
680 if (c->write_points_nr == ARRAY_SIZE(c->write_points) ||
681 too_many_writepoints(c, 32))
684 wp = c->write_points + c->write_points_nr++;
685 hlist_add_head_rcu(&wp->node, writepoint_hash(c, wp->write_point));
689 static bool try_decrease_writepoints(struct bch_fs *c,
692 struct write_point *wp;
694 mutex_lock(&c->write_points_hash_lock);
695 if (c->write_points_nr < old_nr) {
696 mutex_unlock(&c->write_points_hash_lock);
700 if (c->write_points_nr == 1 ||
701 !too_many_writepoints(c, 8)) {
702 mutex_unlock(&c->write_points_hash_lock);
706 wp = c->write_points + --c->write_points_nr;
708 hlist_del_rcu(&wp->node);
709 mutex_unlock(&c->write_points_hash_lock);
711 bch2_writepoint_stop(c, NULL, wp);
715 static struct write_point *writepoint_find(struct bch_fs *c,
716 unsigned long write_point)
718 struct write_point *wp, *oldest;
719 struct hlist_head *head;
721 if (!(write_point & 1UL)) {
722 wp = (struct write_point *) write_point;
723 mutex_lock(&wp->lock);
727 head = writepoint_hash(c, write_point);
729 wp = __writepoint_find(head, write_point);
732 mutex_lock(&wp->lock);
733 if (wp->write_point == write_point)
735 mutex_unlock(&wp->lock);
740 for (wp = c->write_points;
741 wp < c->write_points + c->write_points_nr; wp++)
742 if (!oldest || time_before64(wp->last_used, oldest->last_used))
745 mutex_lock(&oldest->lock);
746 mutex_lock(&c->write_points_hash_lock);
747 if (oldest >= c->write_points + c->write_points_nr ||
748 try_increase_writepoints(c)) {
749 mutex_unlock(&c->write_points_hash_lock);
750 mutex_unlock(&oldest->lock);
751 goto restart_find_oldest;
754 wp = __writepoint_find(head, write_point);
755 if (wp && wp != oldest) {
756 mutex_unlock(&c->write_points_hash_lock);
757 mutex_unlock(&oldest->lock);
762 hlist_del_rcu(&wp->node);
763 wp->write_point = write_point;
764 hlist_add_head_rcu(&wp->node, head);
765 mutex_unlock(&c->write_points_hash_lock);
767 wp->last_used = sched_clock();
772 * Get us an open_bucket we can allocate from, return with it locked:
774 struct write_point *bch2_alloc_sectors_start(struct bch_fs *c,
776 unsigned erasure_code,
777 struct write_point_specifier write_point,
778 struct bch_devs_list *devs_have,
779 unsigned nr_replicas,
780 unsigned nr_replicas_required,
781 enum alloc_reserve reserve,
785 struct write_point *wp;
786 struct open_bucket *ob;
787 struct open_buckets ptrs;
788 unsigned nr_effective, write_points_nr;
789 unsigned ob_flags = 0;
794 if (!(flags & BCH_WRITE_ONLY_SPECIFIED_DEVS))
795 ob_flags |= BUCKET_ALLOC_USE_DURABILITY;
797 BUG_ON(!nr_replicas || !nr_replicas_required);
801 write_points_nr = c->write_points_nr;
804 wp = writepoint_find(c, write_point.v);
806 if (wp->data_type == BCH_DATA_user)
807 ob_flags |= BUCKET_MAY_ALLOC_PARTIAL;
809 /* metadata may not allocate on cache devices: */
810 if (wp->data_type != BCH_DATA_user)
813 if (!target || (flags & BCH_WRITE_ONLY_SPECIFIED_DEVS)) {
814 ret = open_bucket_add_buckets(c, &ptrs, wp, devs_have,
815 target, erasure_code,
816 nr_replicas, &nr_effective,
817 &have_cache, reserve,
820 ret = open_bucket_add_buckets(c, &ptrs, wp, devs_have,
821 target, erasure_code,
822 nr_replicas, &nr_effective,
823 &have_cache, reserve,
828 ret = open_bucket_add_buckets(c, &ptrs, wp, devs_have,
830 nr_replicas, &nr_effective,
831 &have_cache, reserve,
835 BUG_ON(!ret && nr_effective < nr_replicas);
837 if (erasure_code && !ec_open_bucket(c, &ptrs))
838 pr_debug("failed to get ec bucket: ret %u", ret);
840 if (ret == -INSUFFICIENT_DEVICES &&
841 nr_effective >= nr_replicas_required)
847 /* Free buckets we didn't use: */
848 open_bucket_for_each(c, &wp->ptrs, ob, i)
849 open_bucket_free_unused(c, wp, ob);
853 wp->sectors_free = UINT_MAX;
855 open_bucket_for_each(c, &wp->ptrs, ob, i)
856 wp->sectors_free = min(wp->sectors_free, ob->sectors_free);
858 BUG_ON(!wp->sectors_free || wp->sectors_free == UINT_MAX);
860 verify_not_stale(c, &wp->ptrs);
864 open_bucket_for_each(c, &wp->ptrs, ob, i)
865 if (ptrs.nr < ARRAY_SIZE(ptrs.v))
866 ob_push(c, &ptrs, ob);
868 open_bucket_free_unused(c, wp, ob);
871 mutex_unlock(&wp->lock);
873 if (ret == -FREELIST_EMPTY &&
874 try_decrease_writepoints(c, write_points_nr))
878 case -OPEN_BUCKETS_EMPTY:
879 case -FREELIST_EMPTY:
880 return cl ? ERR_PTR(-EAGAIN) : ERR_PTR(-ENOSPC);
881 case -INSUFFICIENT_DEVICES:
882 return ERR_PTR(-EROFS);
888 struct bch_extent_ptr bch2_ob_ptr(struct bch_fs *c, struct open_bucket *ob)
890 struct bch_dev *ca = bch_dev_bkey_exists(c, ob->dev);
892 return (struct bch_extent_ptr) {
893 .type = 1 << BCH_EXTENT_ENTRY_ptr,
896 .offset = bucket_to_sector(ca, ob->bucket) +
903 * Append pointers to the space we just allocated to @k, and mark @sectors space
904 * as allocated out of @ob
906 void bch2_alloc_sectors_append_ptrs(struct bch_fs *c, struct write_point *wp,
907 struct bkey_i *k, unsigned sectors,
911 struct open_bucket *ob;
914 BUG_ON(sectors > wp->sectors_free);
915 wp->sectors_free -= sectors;
917 open_bucket_for_each(c, &wp->ptrs, ob, i) {
918 struct bch_dev *ca = bch_dev_bkey_exists(c, ob->dev);
919 struct bch_extent_ptr ptr = bch2_ob_ptr(c, ob);
921 ptr.cached = cached ||
922 (!ca->mi.durability &&
923 wp->data_type == BCH_DATA_user);
925 bch2_bkey_append_ptr(k, ptr);
927 BUG_ON(sectors > ob->sectors_free);
928 ob->sectors_free -= sectors;
933 * Append pointers to the space we just allocated to @k, and mark @sectors space
934 * as allocated out of @ob
936 void bch2_alloc_sectors_done(struct bch_fs *c, struct write_point *wp)
938 struct open_buckets ptrs = { .nr = 0 }, keep = { .nr = 0 };
939 struct open_bucket *ob;
942 open_bucket_for_each(c, &wp->ptrs, ob, i)
943 ob_push(c, !ob->sectors_free ? &ptrs : &keep, ob);
946 mutex_unlock(&wp->lock);
948 bch2_open_buckets_put(c, &ptrs);
951 static inline void writepoint_init(struct write_point *wp,
952 enum bch_data_type type)
954 mutex_init(&wp->lock);
955 wp->data_type = type;
958 void bch2_fs_allocator_foreground_init(struct bch_fs *c)
960 struct open_bucket *ob;
961 struct write_point *wp;
963 mutex_init(&c->write_points_hash_lock);
964 c->write_points_nr = ARRAY_SIZE(c->write_points);
966 /* open bucket 0 is a sentinal NULL: */
967 spin_lock_init(&c->open_buckets[0].lock);
969 for (ob = c->open_buckets + 1;
970 ob < c->open_buckets + ARRAY_SIZE(c->open_buckets); ob++) {
971 spin_lock_init(&ob->lock);
972 c->open_buckets_nr_free++;
974 ob->freelist = c->open_buckets_freelist;
975 c->open_buckets_freelist = ob - c->open_buckets;
978 writepoint_init(&c->btree_write_point, BCH_DATA_btree);
979 writepoint_init(&c->rebalance_write_point, BCH_DATA_user);
980 writepoint_init(&c->copygc_write_point, BCH_DATA_user);
982 for (wp = c->write_points;
983 wp < c->write_points + c->write_points_nr; wp++) {
984 writepoint_init(wp, BCH_DATA_user);
986 wp->last_used = sched_clock();
987 wp->write_point = (unsigned long) wp;
988 hlist_add_head_rcu(&wp->node,
989 writepoint_hash(c, wp->write_point));
993 void bch2_open_buckets_to_text(struct printbuf *out, struct bch_fs *c)
995 struct open_bucket *ob;
997 for (ob = c->open_buckets;
998 ob < c->open_buckets + ARRAY_SIZE(c->open_buckets);
1000 spin_lock(&ob->lock);
1001 if (ob->valid && !ob->on_partial_list) {
1002 pr_buf(out, "%zu ref %u type %s\n",
1003 ob - c->open_buckets,
1004 atomic_read(&ob->pin),
1005 bch2_data_types[ob->data_type]);
1007 spin_unlock(&ob->lock);