1 // SPDX-License-Identifier: GPL-2.0
4 #include "buckets_waiting_for_journal.h"
5 #include <linux/random.h>
7 static inline struct bucket_hashed *
8 bucket_hash(struct buckets_waiting_for_journal_table *t,
9 unsigned hash_seed_idx, u64 dev_bucket)
11 unsigned h = siphash_1u64(dev_bucket, &t->hash_seeds[hash_seed_idx]);
13 BUG_ON(!is_power_of_2(t->size));
15 return t->d + (h & (t->size - 1));
18 static void bucket_table_init(struct buckets_waiting_for_journal_table *t, size_t size)
23 for (i = 0; i < ARRAY_SIZE(t->hash_seeds); i++)
24 get_random_bytes(&t->hash_seeds[i], sizeof(t->hash_seeds[i]));
25 memset(t->d, 0, sizeof(t->d[0]) * size);
28 bool bch2_bucket_needs_journal_commit(struct buckets_waiting_for_journal *b,
30 unsigned dev, u64 bucket)
32 struct buckets_waiting_for_journal_table *t;
33 u64 dev_bucket = (u64) dev << 56 | bucket;
40 for (i = 0; i < ARRAY_SIZE(t->hash_seeds); i++) {
41 struct bucket_hashed *h = bucket_hash(t, i, dev_bucket);
43 if (h->dev_bucket == dev_bucket) {
44 ret = h->journal_seq > flushed_seq;
49 mutex_unlock(&b->lock);
54 static bool bucket_table_insert(struct buckets_waiting_for_journal_table *t,
55 struct bucket_hashed *new,
58 struct bucket_hashed *last_evicted = NULL;
61 for (tries = 0; tries < 10; tries++) {
62 struct bucket_hashed *old, *victim = NULL;
64 for (i = 0; i < ARRAY_SIZE(t->hash_seeds); i++) {
65 old = bucket_hash(t, i, new->dev_bucket);
67 if (old->dev_bucket == new->dev_bucket ||
68 old->journal_seq <= flushed_seq) {
73 if (last_evicted != old)
77 /* hashed to same slot 3 times: */
81 /* Failed to find an empty slot: */
83 last_evicted = victim;
89 int bch2_set_bucket_needs_journal_commit(struct buckets_waiting_for_journal *b,
91 unsigned dev, u64 bucket,
94 struct buckets_waiting_for_journal_table *t, *n;
95 struct bucket_hashed tmp, new = {
96 .dev_bucket = (u64) dev << 56 | bucket,
97 .journal_seq = journal_seq,
99 size_t i, new_size, nr_elements = 1, nr_rehashes = 0;
102 mutex_lock(&b->lock);
104 if (likely(bucket_table_insert(b->t, &new, flushed_seq)))
108 for (i = 0; i < t->size; i++)
109 nr_elements += t->d[i].journal_seq > flushed_seq;
111 new_size = nr_elements < t->size / 3 ? t->size : t->size * 2;
113 n = kvmalloc(sizeof(*n) + sizeof(n->d[0]) * new_size, GFP_KERNEL);
121 bucket_table_init(n, new_size);
124 BUG_ON(!bucket_table_insert(n, &tmp, flushed_seq));
126 for (i = 0; i < t->size; i++) {
127 if (t->d[i].journal_seq <= flushed_seq)
131 if (!bucket_table_insert(n, &tmp, flushed_seq))
138 pr_debug("took %zu rehashes, table at %zu/%zu elements",
139 nr_rehashes, nr_elements, b->t->size);
141 mutex_unlock(&b->lock);
146 void bch2_fs_buckets_waiting_for_journal_exit(struct bch_fs *c)
148 struct buckets_waiting_for_journal *b = &c->buckets_waiting_for_journal;
153 #define INITIAL_TABLE_SIZE 8
155 int bch2_fs_buckets_waiting_for_journal_init(struct bch_fs *c)
157 struct buckets_waiting_for_journal *b = &c->buckets_waiting_for_journal;
159 mutex_init(&b->lock);
161 b->t = kvmalloc(sizeof(*b->t) + sizeof(b->t->d[0]) * INITIAL_TABLE_SIZE, GFP_KERNEL);
165 bucket_table_init(b->t, INITIAL_TABLE_SIZE);