From 8eb7f3ee46f23207d3e0ae6428b780a0708c53c1 Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Mon, 19 Nov 2018 01:16:07 -0500 Subject: [PATCH] bcachefs: move dirty into bucket_mark Signed-off-by: Kent Overstreet --- fs/bcachefs/alloc_background.c | 35 ++++++++++++++++++++++++---------- fs/bcachefs/bcachefs.h | 2 +- fs/bcachefs/btree_gc.c | 4 ++-- fs/bcachefs/buckets.c | 14 +++++++------- fs/bcachefs/buckets.h | 15 +++++++++++++-- fs/bcachefs/buckets_types.h | 2 +- 6 files changed, 49 insertions(+), 23 deletions(-) diff --git a/fs/bcachefs/alloc_background.c b/fs/bcachefs/alloc_background.c index bd3070539e28..8756b2efb53e 100644 --- a/fs/bcachefs/alloc_background.c +++ b/fs/bcachefs/alloc_background.c @@ -185,9 +185,9 @@ static void __alloc_read_key(struct bucket *g, const struct bch_alloc *a) g->_mark.cached_sectors = get_alloc_field(a, &d, idx++); } -static void __alloc_write_key(struct bkey_i_alloc *a, struct bucket *g) +static void __alloc_write_key(struct bkey_i_alloc *a, struct bucket *g, + struct bucket_mark m) { - struct bucket_mark m = READ_ONCE(g->mark); unsigned idx = 0; void *d = a->v.data; @@ -280,6 +280,8 @@ static int __bch2_alloc_write_key(struct bch_fs *c, struct bch_dev *ca, __BKEY_PADDED(k, 8) alloc_key; #endif struct bkey_i_alloc *a = bkey_alloc_init(&alloc_key.k); + struct bucket *g; + struct bucket_mark m; int ret; BUG_ON(BKEY_ALLOC_VAL_U64s_MAX > 8); @@ -287,7 +289,10 @@ static int __bch2_alloc_write_key(struct bch_fs *c, struct bch_dev *ca, a->k.p = POS(ca->dev_idx, b); percpu_down_read(&c->usage_lock); - __alloc_write_key(a, bucket(ca, b)); + g = bucket(ca, b); + m = bucket_cmpxchg(g, m, m.dirty = false); + + __alloc_write_key(a, g, m); percpu_up_read(&c->usage_lock); bch2_btree_iter_cond_resched(iter); @@ -350,19 +355,24 @@ int bch2_alloc_write(struct bch_fs *c) for_each_rw_member(ca, c, i) { struct btree_iter iter; - unsigned long bucket; + struct bucket_array *buckets; + size_t b; bch2_btree_iter_init(&iter, c, BTREE_ID_ALLOC, POS_MIN, BTREE_ITER_SLOTS|BTREE_ITER_INTENT); down_read(&ca->bucket_lock); - for_each_set_bit(bucket, ca->buckets_dirty, ca->mi.nbuckets) { - ret = __bch2_alloc_write_key(c, ca, bucket, - &iter, NULL, 0); + buckets = bucket_array(ca); + + for (b = buckets->first_bucket; + b < buckets->nbuckets; + b++) { + if (!buckets->b[b].mark.dirty) + continue; + + ret = __bch2_alloc_write_key(c, ca, b, &iter, NULL, 0); if (ret) break; - - clear_bit(bucket, ca->buckets_dirty); } up_read(&ca->bucket_lock); bch2_btree_iter_unlock(&iter); @@ -541,6 +551,10 @@ static bool bch2_can_invalidate_bucket(struct bch_dev *ca, if (!is_available_bucket(mark)) return false; + if (ca->buckets_nouse && + test_bit(bucket, ca->buckets_nouse)) + return false; + gc_gen = bucket_gc_gen(ca, bucket); if (gc_gen >= BUCKET_GC_GEN_MAX / 2) @@ -1340,6 +1354,7 @@ static int __bch2_fs_allocator_start(struct bch_fs *c) m = READ_ONCE(buckets->b[bu].mark); if (!buckets->b[bu].gen_valid || + !test_bit(bu, ca->buckets_nouse) || !is_available_bucket(m) || m.cached_sectors) continue; @@ -1378,7 +1393,7 @@ static int __bch2_fs_allocator_start(struct bch_fs *c) bch2_invalidate_one_bucket(c, ca, bu, &journal_seq); fifo_push(&ca->free[RESERVE_BTREE], bu); - set_bit(bu, ca->buckets_dirty); + bucket_set_dirty(ca, bu); } } diff --git a/fs/bcachefs/bcachefs.h b/fs/bcachefs/bcachefs.h index e9ae7e6d53b2..48926fda44ff 100644 --- a/fs/bcachefs/bcachefs.h +++ b/fs/bcachefs/bcachefs.h @@ -395,7 +395,7 @@ struct bch_dev { * Or rcu_read_lock(), but only for ptr_stale(): */ struct bucket_array __rcu *buckets[2]; - unsigned long *buckets_dirty; + unsigned long *buckets_nouse; unsigned long *buckets_written; /* most out of date gen in the btree */ u8 *oldest_gens; diff --git a/fs/bcachefs/btree_gc.c b/fs/bcachefs/btree_gc.c index 997e72aa4cb1..1f99c5cb3439 100644 --- a/fs/bcachefs/btree_gc.c +++ b/fs/bcachefs/btree_gc.c @@ -150,7 +150,7 @@ static int bch2_gc_mark_key(struct bch_fs *c, struct bkey_s_c k, k.k->type, ptr->gen)) { g->_mark.gen = ptr->gen; g->gen_valid = 1; - set_bit(b, ca->buckets_dirty); + bucket_set_dirty(ca, b); } if (mustfix_fsck_err_on(gen_cmp(ptr->gen, g->mark.gen) > 0, c, @@ -158,7 +158,7 @@ static int bch2_gc_mark_key(struct bch_fs *c, struct bkey_s_c k, k.k->type, ptr->gen, g->mark.gen)) { g->_mark.gen = ptr->gen; g->gen_valid = 1; - set_bit(b, ca->buckets_dirty); + bucket_set_dirty(ca, b); set_bit(BCH_FS_FIXED_GENS, &c->flags); } } diff --git a/fs/bcachefs/buckets.c b/fs/bcachefs/buckets.c index 8cbc1c5c8af5..cc0a318ff133 100644 --- a/fs/bcachefs/buckets.c +++ b/fs/bcachefs/buckets.c @@ -1132,7 +1132,7 @@ static void buckets_free_rcu(struct rcu_head *rcu) int bch2_dev_buckets_resize(struct bch_fs *c, struct bch_dev *ca, u64 nbuckets) { struct bucket_array *buckets = NULL, *old_buckets = NULL; - unsigned long *buckets_dirty = NULL; + unsigned long *buckets_nouse = NULL; unsigned long *buckets_written = NULL; u8 *oldest_gens = NULL; alloc_fifo free[RESERVE_NR]; @@ -1162,7 +1162,7 @@ int bch2_dev_buckets_resize(struct bch_fs *c, struct bch_dev *ca, u64 nbuckets) GFP_KERNEL|__GFP_ZERO)) || !(oldest_gens = kvpmalloc(nbuckets * sizeof(u8), GFP_KERNEL|__GFP_ZERO)) || - !(buckets_dirty = kvpmalloc(BITS_TO_LONGS(nbuckets) * + !(buckets_nouse = kvpmalloc(BITS_TO_LONGS(nbuckets) * sizeof(unsigned long), GFP_KERNEL|__GFP_ZERO)) || !(buckets_written = kvpmalloc(BITS_TO_LONGS(nbuckets) * @@ -1199,8 +1199,8 @@ int bch2_dev_buckets_resize(struct bch_fs *c, struct bch_dev *ca, u64 nbuckets) memcpy(oldest_gens, ca->oldest_gens, n * sizeof(u8)); - memcpy(buckets_dirty, - ca->buckets_dirty, + memcpy(buckets_nouse, + ca->buckets_nouse, BITS_TO_LONGS(n) * sizeof(unsigned long)); memcpy(buckets_written, ca->buckets_written, @@ -1211,7 +1211,7 @@ int bch2_dev_buckets_resize(struct bch_fs *c, struct bch_dev *ca, u64 nbuckets) buckets = old_buckets; swap(ca->oldest_gens, oldest_gens); - swap(ca->buckets_dirty, buckets_dirty); + swap(ca->buckets_nouse, buckets_nouse); swap(ca->buckets_written, buckets_written); if (resize) @@ -1250,7 +1250,7 @@ int bch2_dev_buckets_resize(struct bch_fs *c, struct bch_dev *ca, u64 nbuckets) free_fifo(&free_inc); for (i = 0; i < RESERVE_NR; i++) free_fifo(&free[i]); - kvpfree(buckets_dirty, + kvpfree(buckets_nouse, BITS_TO_LONGS(nbuckets) * sizeof(unsigned long)); kvpfree(buckets_written, BITS_TO_LONGS(nbuckets) * sizeof(unsigned long)); @@ -1273,7 +1273,7 @@ void bch2_dev_buckets_free(struct bch_dev *ca) free_fifo(&ca->free[i]); kvpfree(ca->buckets_written, BITS_TO_LONGS(ca->mi.nbuckets) * sizeof(unsigned long)); - kvpfree(ca->buckets_dirty, + kvpfree(ca->buckets_nouse, BITS_TO_LONGS(ca->mi.nbuckets) * sizeof(unsigned long)); kvpfree(ca->oldest_gens, ca->mi.nbuckets * sizeof(u8)); kvpfree(rcu_dereference_protected(ca->buckets[0], 1), diff --git a/fs/bcachefs/buckets.h b/fs/bcachefs/buckets.h index c584ad1b4375..d34181c78f9b 100644 --- a/fs/bcachefs/buckets.h +++ b/fs/bcachefs/buckets.h @@ -57,6 +57,18 @@ static inline struct bucket *bucket(struct bch_dev *ca, size_t b) return __bucket(ca, b, false); } +static inline void bucket_set_dirty(struct bch_dev *ca, size_t b) +{ + struct bucket *g; + struct bucket_mark m; + + rcu_read_lock(); + g = bucket(ca, b); + bucket_cmpxchg(g, m, m.dirty = true); + rcu_read_unlock(); + +} + static inline void bucket_io_clock_reset(struct bch_fs *c, struct bch_dev *ca, size_t b, int rw) { @@ -196,8 +208,7 @@ static inline bool is_available_bucket(struct bucket_mark mark) { return (!mark.owned_by_allocator && !mark.dirty_sectors && - !mark.stripe && - !mark.nouse); + !mark.stripe); } static inline bool bucket_needs_journal_commit(struct bucket_mark m, diff --git a/fs/bcachefs/buckets_types.h b/fs/bcachefs/buckets_types.h index a47a7856eee4..35d5cf48003b 100644 --- a/fs/bcachefs/buckets_types.h +++ b/fs/bcachefs/buckets_types.h @@ -15,7 +15,7 @@ struct bucket_mark { u8 gen; u8 data_type:3, owned_by_allocator:1, - nouse:1, + dirty:1, journal_seq_valid:1, stripe:1; u16 dirty_sectors;