summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2021-12-27 23:56:13 -0500
committerKent Overstreet <kent.overstreet@linux.dev>2023-10-22 17:09:20 -0400
commite3ad29379e47014461d540629628c2cc158c025d (patch)
tree1a03c3467b88a65fd5e06b88d1bae9a6bd377299 /fs
parent8d65e475b20610854419fef8dba155200b45a687 (diff)
downloadlwn-e3ad29379e47014461d540629628c2cc158c025d.tar.gz
lwn-e3ad29379e47014461d540629628c2cc158c025d.zip
bcachefs: Optimize bucket reuse
If the btree updates pointing to a bucket were never flushed by the journal before the bucket became empty again, we can reuse the bucket without a journal flush. This tweaks the tracking of journal sequence numbers in alloc keys to implement this optimization: now, we only update the journal sequence number in alloc keys on transitions to and from empty. When a bucket becomes empty, we check if we can tell the journal not to flush entries starting from when the bucket was used. Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/bcachefs/buckets.c64
1 files changed, 28 insertions, 36 deletions
diff --git a/fs/bcachefs/buckets.c b/fs/bcachefs/buckets.c
index a0b455b343ac..869f6dd19d08 100644
--- a/fs/bcachefs/buckets.c
+++ b/fs/bcachefs/buckets.c
@@ -535,20 +535,6 @@ void bch2_mark_alloc_bucket(struct bch_fs *c, struct bch_dev *ca,
BUG_ON(owned_by_allocator == old.owned_by_allocator);
}
-static inline u8 bkey_alloc_gen(struct bkey_s_c k)
-{
- switch (k.k->type) {
- case KEY_TYPE_alloc:
- return bkey_s_c_to_alloc(k).v->gen;
- case KEY_TYPE_alloc_v2:
- return bkey_s_c_to_alloc_v2(k).v->gen;
- case KEY_TYPE_alloc_v3:
- return bkey_s_c_to_alloc_v3(k).v->gen;
- default:
- return 0;
- }
-}
-
static int bch2_mark_alloc(struct btree_trans *trans,
struct bkey_s_c old, struct bkey_s_c new,
unsigned flags)
@@ -556,16 +542,13 @@ static int bch2_mark_alloc(struct btree_trans *trans,
bool gc = flags & BTREE_TRIGGER_GC;
u64 journal_seq = trans->journal_res.seq;
struct bch_fs *c = trans->c;
- struct bkey_alloc_unpacked u;
+ struct bkey_alloc_unpacked old_u = bch2_alloc_unpack(old);
+ struct bkey_alloc_unpacked new_u = bch2_alloc_unpack(new);
struct bch_dev *ca;
struct bucket *g;
struct bucket_mark old_m, m;
int ret = 0;
- /* We don't do anything for deletions - do we?: */
- if (!bkey_is_alloc(new.k))
- return 0;
-
/*
* alloc btree is read in by bch2_alloc_read, not gc:
*/
@@ -573,13 +556,24 @@ static int bch2_mark_alloc(struct btree_trans *trans,
!(flags & BTREE_TRIGGER_BUCKET_INVALIDATE))
return 0;
- if (flags & BTREE_TRIGGER_INSERT) {
+ if ((flags & BTREE_TRIGGER_INSERT) &&
+ !old_u.data_type != !new_u.data_type &&
+ new.k->type == KEY_TYPE_alloc_v3) {
struct bch_alloc_v3 *v = (struct bch_alloc_v3 *) new.v;
+ u64 old_journal_seq = le64_to_cpu(v->journal_seq);
BUG_ON(!journal_seq);
- BUG_ON(new.k->type != KEY_TYPE_alloc_v3);
- v->journal_seq = cpu_to_le64(journal_seq);
+ /*
+ * If the btree updates referring to a bucket weren't flushed
+ * before the bucket became empty again, then the we don't have
+ * to wait on a journal flush before we can reuse the bucket:
+ */
+ new_u.journal_seq = !new_u.data_type &&
+ (journal_seq == old_journal_seq ||
+ bch2_journal_noflush_seq(&c->journal, old_journal_seq))
+ ? 0 : journal_seq;
+ v->journal_seq = cpu_to_le64(new_u.journal_seq);
}
ca = bch_dev_bkey_exists(c, new.k->p.inode);
@@ -587,20 +581,18 @@ static int bch2_mark_alloc(struct btree_trans *trans,
if (new.k->p.offset >= ca->mi.nbuckets)
return 0;
- u = bch2_alloc_unpack(new);
-
percpu_down_read(&c->mark_lock);
- if (!gc && u.gen != bkey_alloc_gen(old))
- *bucket_gen(ca, new.k->p.offset) = u.gen;
+ if (!gc && new_u.gen != old_u.gen)
+ *bucket_gen(ca, new.k->p.offset) = new_u.gen;
g = __bucket(ca, new.k->p.offset, gc);
old_m = bucket_cmpxchg(g, m, ({
- m.gen = u.gen;
- m.data_type = u.data_type;
- m.dirty_sectors = u.dirty_sectors;
- m.cached_sectors = u.cached_sectors;
- m.stripe = u.stripe != 0;
+ m.gen = new_u.gen;
+ m.data_type = new_u.data_type;
+ m.dirty_sectors = new_u.dirty_sectors;
+ m.cached_sectors = new_u.cached_sectors;
+ m.stripe = new_u.stripe != 0;
if (journal_seq) {
m.journal_seq_valid = 1;
@@ -610,12 +602,12 @@ static int bch2_mark_alloc(struct btree_trans *trans,
bch2_dev_usage_update(c, ca, old_m, m, journal_seq, gc);
- g->io_time[READ] = u.read_time;
- g->io_time[WRITE] = u.write_time;
- g->oldest_gen = u.oldest_gen;
+ g->io_time[READ] = new_u.read_time;
+ g->io_time[WRITE] = new_u.write_time;
+ g->oldest_gen = new_u.oldest_gen;
g->gen_valid = 1;
- g->stripe = u.stripe;
- g->stripe_redundancy = u.stripe_redundancy;
+ g->stripe = new_u.stripe;
+ g->stripe_redundancy = new_u.stripe_redundancy;
percpu_up_read(&c->mark_lock);
/*