summaryrefslogtreecommitdiff
path: root/fs/bcachefs/alloc_background.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/bcachefs/alloc_background.c')
-rw-r--r--fs/bcachefs/alloc_background.c212
1 files changed, 86 insertions, 126 deletions
diff --git a/fs/bcachefs/alloc_background.c b/fs/bcachefs/alloc_background.c
index 43dc2f270dc6..9814179a6406 100644
--- a/fs/bcachefs/alloc_background.c
+++ b/fs/bcachefs/alloc_background.c
@@ -205,20 +205,6 @@ void bch2_alloc_to_text(struct printbuf *out, struct bch_fs *c,
get_alloc_field(a.v, &d, i));
}
-static inline struct bkey_alloc_unpacked
-alloc_mem_to_key(struct bucket *g, struct bucket_mark m)
-{
- return (struct bkey_alloc_unpacked) {
- .gen = m.gen,
- .oldest_gen = g->oldest_gen,
- .data_type = m.data_type,
- .dirty_sectors = m.dirty_sectors,
- .cached_sectors = m.cached_sectors,
- .read_time = g->io_time[READ],
- .write_time = g->io_time[WRITE],
- };
-}
-
int bch2_alloc_read(struct bch_fs *c, struct journal_keys *journal_keys)
{
struct btree_trans trans;
@@ -232,7 +218,7 @@ int bch2_alloc_read(struct bch_fs *c, struct journal_keys *journal_keys)
bch2_trans_init(&trans, c, 0, 0);
for_each_btree_key(&trans, iter, BTREE_ID_ALLOC, POS_MIN, 0, k, ret)
- bch2_mark_key(c, k, 0, NULL, 0,
+ bch2_mark_key(c, k, 0, 0, NULL, 0,
BCH_BUCKET_MARK_ALLOC_READ|
BCH_BUCKET_MARK_NOATOMIC);
@@ -244,7 +230,8 @@ int bch2_alloc_read(struct bch_fs *c, struct journal_keys *journal_keys)
for_each_journal_key(*journal_keys, j)
if (j->btree_id == BTREE_ID_ALLOC)
- bch2_mark_key(c, bkey_i_to_s_c(j->k), 0, NULL, 0,
+ bch2_mark_key(c, bkey_i_to_s_c(j->k),
+ 0, 0, NULL, 0,
BCH_BUCKET_MARK_ALLOC_READ|
BCH_BUCKET_MARK_NOATOMIC);
@@ -271,46 +258,68 @@ int bch2_alloc_read(struct bch_fs *c, struct journal_keys *journal_keys)
return 0;
}
-int bch2_alloc_replay_key(struct bch_fs *c, struct bkey_i *k)
+enum alloc_write_ret {
+ ALLOC_WROTE,
+ ALLOC_NOWROTE,
+ ALLOC_END,
+};
+
+static int bch2_alloc_write_key(struct btree_trans *trans,
+ struct btree_iter *iter,
+ unsigned flags)
{
- struct btree_trans trans;
- struct btree_iter *iter;
+ struct bch_fs *c = trans->c;
+ struct bkey_s_c k;
struct bch_dev *ca;
+ struct bucket_array *ba;
+ struct bucket *g;
+ struct bucket_mark m;
+ struct bkey_alloc_unpacked old_u, new_u;
+ __BKEY_PADDED(k, 8) alloc_key; /* hack: */
+ struct bkey_i_alloc *a;
int ret;
+retry:
+ k = bch2_btree_iter_peek_slot(iter);
+ ret = bkey_err(k);
+ if (ret)
+ goto err;
- if (k->k.p.inode >= c->sb.nr_devices ||
- !c->devs[k->k.p.inode])
- return 0;
-
- ca = bch_dev_bkey_exists(c, k->k.p.inode);
+ old_u = bch2_alloc_unpack(k);
- if (k->k.p.offset >= ca->mi.nbuckets)
- return 0;
+ if (iter->pos.inode >= c->sb.nr_devices ||
+ !c->devs[iter->pos.inode])
+ return ALLOC_END;
- bch2_trans_init(&trans, c, 0, 0);
+ percpu_down_read(&c->mark_lock);
+ ca = bch_dev_bkey_exists(c, iter->pos.inode);
+ ba = bucket_array(ca);
- iter = bch2_trans_get_iter(&trans, BTREE_ID_ALLOC, k->k.p,
- BTREE_ITER_INTENT);
+ if (iter->pos.offset >= ba->nbuckets) {
+ percpu_up_read(&c->mark_lock);
+ return ALLOC_END;
+ }
- ret = bch2_btree_iter_traverse(iter);
- if (ret)
- goto err;
+ g = &ba->b[iter->pos.offset];
+ m = READ_ONCE(g->mark);
+ new_u = alloc_mem_to_key(g, m);
+ percpu_up_read(&c->mark_lock);
- /* check buckets_written with btree node locked: */
- if (test_bit(k->k.p.offset, ca->buckets_written)) {
- ret = 0;
- goto err;
- }
+ if (!bkey_alloc_unpacked_cmp(old_u, new_u))
+ return ALLOC_NOWROTE;
- bch2_trans_update(&trans, BTREE_INSERT_ENTRY(iter, k));
+ a = bkey_alloc_init(&alloc_key.k);
+ a->k.p = iter->pos;
+ bch2_alloc_pack(a, new_u);
- ret = bch2_trans_commit(&trans, NULL, NULL,
+ bch2_trans_update(trans, BTREE_INSERT_ENTRY(iter, &a->k_i));
+ ret = bch2_trans_commit(trans, NULL, NULL,
+ BTREE_INSERT_ATOMIC|
BTREE_INSERT_NOFAIL|
- BTREE_INSERT_LAZY_RW|
- BTREE_INSERT_JOURNAL_REPLAY|
- BTREE_INSERT_NOMARK);
+ BTREE_INSERT_NOMARK|
+ flags);
err:
- bch2_trans_exit(&trans);
+ if (ret == -EINTR)
+ goto retry;
return ret;
}
@@ -318,16 +327,8 @@ int bch2_alloc_write(struct bch_fs *c, unsigned flags, bool *wrote)
{
struct btree_trans trans;
struct btree_iter *iter;
- struct bucket_array *buckets;
struct bch_dev *ca;
- struct bucket *g;
- struct bucket_mark m, new;
- struct bkey_alloc_unpacked old_u, new_u;
- __BKEY_PADDED(k, 8) alloc_key; /* hack: */
- struct bkey_i_alloc *a;
- struct bkey_s_c k;
unsigned i;
- size_t b;
int ret = 0;
BUG_ON(BKEY_ALLOC_VAL_U64s_MAX > 8);
@@ -338,81 +339,24 @@ int bch2_alloc_write(struct bch_fs *c, unsigned flags, bool *wrote)
BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
for_each_rw_member(ca, c, i) {
- down_read(&ca->bucket_lock);
-restart:
- buckets = bucket_array(ca);
+ unsigned first_bucket;
- for (b = buckets->first_bucket;
- b < buckets->nbuckets;
- b++) {
- if (!buckets->b[b].mark.dirty)
- continue;
-
- bch2_btree_iter_set_pos(iter, POS(i, b));
- k = bch2_btree_iter_peek_slot(iter);
- ret = bkey_err(k);
- if (ret)
- goto err;
-
- old_u = bch2_alloc_unpack(k);
-
- percpu_down_read(&c->mark_lock);
- g = bucket(ca, b);
- m = READ_ONCE(g->mark);
- new_u = alloc_mem_to_key(g, m);
- percpu_up_read(&c->mark_lock);
-
- if (!m.dirty)
- continue;
-
- if ((flags & BTREE_INSERT_LAZY_RW) &&
- percpu_ref_is_zero(&c->writes)) {
- up_read(&ca->bucket_lock);
- bch2_trans_unlock(&trans);
-
- ret = bch2_fs_read_write_early(c);
- down_read(&ca->bucket_lock);
-
- if (ret)
- goto err;
- goto restart;
- }
+ percpu_down_read(&c->mark_lock);
+ first_bucket = bucket_array(ca)->first_bucket;
+ percpu_up_read(&c->mark_lock);
- a = bkey_alloc_init(&alloc_key.k);
- a->k.p = iter->pos;
- bch2_alloc_pack(a, new_u);
+ bch2_btree_iter_set_pos(iter, POS(i, first_bucket));
- bch2_trans_update(&trans, BTREE_INSERT_ENTRY(iter, &a->k_i));
- ret = bch2_trans_commit(&trans, NULL, NULL,
- BTREE_INSERT_NOFAIL|
- BTREE_INSERT_NOMARK|
- flags);
-err:
- if (ret && !test_bit(BCH_FS_EMERGENCY_RO, &c->flags)) {
- bch_err(c, "error %i writing alloc info", ret);
- printk(KERN_CONT "dev %llu bucket %llu\n",
- iter->pos.inode, iter->pos.offset);
- printk(KERN_CONT "gen %u -> %u\n", old_u.gen, new_u.gen);
-#define x(_name, _bits) printk(KERN_CONT #_name " %u -> %u\n", old_u._name, new_u._name);
- BCH_ALLOC_FIELDS()
-#undef x
- }
- if (ret)
+ while (1) {
+ ret = bch2_alloc_write_key(&trans, iter, flags);
+ if (ret < 0 || ret == ALLOC_END)
break;
-
- new = m;
- new.dirty = false;
- atomic64_cmpxchg(&g->_mark.v, m.v.counter, new.v.counter);
-
- if (ca->buckets_written)
- set_bit(b, ca->buckets_written);
-
- bch2_trans_cond_resched(&trans);
- *wrote = true;
+ if (ret == ALLOC_WROTE)
+ *wrote = true;
+ bch2_btree_iter_next_slot(iter);
}
- up_read(&ca->bucket_lock);
- if (ret) {
+ if (ret < 0) {
percpu_ref_put(&ca->io_ref);
break;
}
@@ -420,7 +364,27 @@ err:
bch2_trans_exit(&trans);
- return ret;
+ return ret < 0 ? ret : 0;
+}
+
+int bch2_alloc_replay_key(struct bch_fs *c, struct bkey_i *k)
+{
+ struct btree_trans trans;
+ struct btree_iter *iter;
+ int ret;
+
+ bch2_trans_init(&trans, c, 0, 0);
+
+ iter = bch2_trans_get_iter(&trans, BTREE_ID_ALLOC, k->k.p,
+ BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
+
+ ret = bch2_alloc_write_key(&trans, iter,
+ BTREE_INSERT_NOFAIL|
+ BTREE_INSERT_LAZY_RW|
+ BTREE_INSERT_JOURNAL_REPLAY|
+ BTREE_INSERT_NOMARK);
+ bch2_trans_exit(&trans);
+ return ret < 0 ? ret : 0;
}
/* Bucket IO clocks: */
@@ -967,10 +931,6 @@ retry:
if (!top->nr)
heap_pop(&ca->alloc_heap, e, bucket_alloc_cmp, NULL);
- /* with btree still locked: */
- if (ca->buckets_written)
- set_bit(b, ca->buckets_written);
-
/*
* Make sure we flush the last journal entry that updated this
* bucket (i.e. deleting the last reference) before writing to
@@ -1204,7 +1164,7 @@ static int bch2_allocator_thread(void *arg)
*/
if (!nr ||
(nr < ALLOC_SCAN_BATCH(ca) &&
- !fifo_full(&ca->free[RESERVE_MOVINGGC]))) {
+ !fifo_empty(&ca->free[RESERVE_NONE]))) {
ret = wait_buckets_available(c, ca);
if (ret) {
up_read(&c->gc_lock);