1 // SPDX-License-Identifier: GPL-2.0
4 #include "buckets_waiting_for_journal.h"
5 #include <linux/jhash.h>
7 static u32 hash_seeds[] = {
13 static inline unsigned bucket_hash(u64 dev_bucket, unsigned hash_seed_idx)
15 return jhash_2words(dev_bucket << 32, dev_bucket, hash_seeds[hash_seed_idx]);
18 bool bch2_bucket_needs_journal_commit(struct bch_fs *c,
20 unsigned dev, u64 bucket)
22 struct buckets_waiting_for_journal *b = &c->buckets_waiting_for_journal;
23 u64 dev_bucket = (u64) dev << 56 | bucket;
28 BUG_ON(!is_power_of_2(b->nr));
30 for (i = 0; i < ARRAY_SIZE(hash_seeds); i++) {
31 u32 h = bucket_hash(dev_bucket, i) & (b->nr - 1);
33 if (b->d[h].dev_bucket == dev_bucket) {
34 ret = b->d[h].journal_seq > flushed_seq;
39 mutex_unlock(&b->lock);
44 static int bch2_buckets_waiting_for_journal_rehash(struct bch_fs *c)
46 struct buckets_waiting_for_journal *b = &c->buckets_waiting_for_journal;
47 u64 flushed_seq = c->journal.flushed_seq_ondisk;
48 unsigned i, j, h, new_nr = b->nr * 2, elements = 0;
49 struct bucket_hashed *new_table;
51 new_table = kvmalloc_array(new_nr, sizeof(*new_table), __GFP_ZERO);
55 for (i = 0; i < b->nr; i++) {
56 if (b->d[i].journal_seq < flushed_seq)
59 for (j = 0; j < ARRAY_SIZE(hash_seeds); j++) {
60 h = bucket_hash(b->d[i].dev_bucket, j);
61 if ((h & (b->nr - 1)) == i)
65 BUG_ON(j == ARRAY_SIZE(hash_seeds));
66 BUG_ON(new_table[h & (new_nr - 1)].dev_bucket);
68 new_table[h & (new_nr - 1)] = b->d[i];
79 int bch2_set_bucket_needs_journal_commit(struct bch_fs *c, unsigned dev, u64 bucket,
82 struct buckets_waiting_for_journal *b = &c->buckets_waiting_for_journal;
83 struct bucket_hashed new = {
84 .dev_bucket = (u64) dev << 56 | bucket,
85 .journal_seq = journal_seq,
86 }, *last_evicted = NULL;
87 u64 flushed_seq = c->journal.flushed_seq_ondisk;
92 BUG_ON(!is_power_of_2(b->nr));
94 for (tries = 0; tries < 5; tries++) {
95 struct bucket_hashed *old, *victim = NULL;
97 for (i = 0; i < ARRAY_SIZE(hash_seeds); i++) {
98 old = b->d + (bucket_hash(new.dev_bucket, i) & (b->nr - 1));
100 if (old->dev_bucket == new.dev_bucket ||
101 old->journal_seq <= flushed_seq) {
106 if (last_evicted != old)
110 /* hashed to same slot 3 times: */
114 /* Failed to find an empty slot: */
116 last_evicted = victim;
119 ret = bch2_buckets_waiting_for_journal_rehash(c);
123 mutex_unlock(&b->lock);
128 void bch2_fs_buckets_waiting_for_journal_exit(struct bch_fs *c)
130 struct buckets_waiting_for_journal *b = &c->buckets_waiting_for_journal;
135 int bch2_fs_buckets_waiting_for_journal_init(struct bch_fs *c)
137 struct buckets_waiting_for_journal *b = &c->buckets_waiting_for_journal;
139 mutex_init(&b->lock);
142 b->d = kvmalloc_array(b->nr, sizeof(*b->d), __GFP_ZERO);