1 // SPDX-License-Identifier: GPL-2.0
4 #include "buckets_waiting_for_journal.h"
5 #include <linux/hash.h>
6 #include <linux/random.h>
8 static inline struct bucket_hashed
*
9 bucket_hash(struct buckets_waiting_for_journal_table
*t
,
10 unsigned hash_seed_idx
, u64 dev_bucket
)
12 return t
->d
+ hash_64(dev_bucket
^ t
->hash_seeds
[hash_seed_idx
], t
->bits
);
15 static void bucket_table_init(struct buckets_waiting_for_journal_table
*t
, size_t bits
)
20 for (i
= 0; i
< ARRAY_SIZE(t
->hash_seeds
); i
++)
21 get_random_bytes(&t
->hash_seeds
[i
], sizeof(t
->hash_seeds
[i
]));
22 memset(t
->d
, 0, sizeof(t
->d
[0]) << t
->bits
);
25 bool bch2_bucket_needs_journal_commit(struct buckets_waiting_for_journal
*b
,
27 unsigned dev
, u64 bucket
)
29 struct buckets_waiting_for_journal_table
*t
;
30 u64 dev_bucket
= (u64
) dev
<< 56 | bucket
;
37 for (i
= 0; i
< ARRAY_SIZE(t
->hash_seeds
); i
++) {
38 struct bucket_hashed
*h
= bucket_hash(t
, i
, dev_bucket
);
40 if (h
->dev_bucket
== dev_bucket
) {
41 ret
= h
->journal_seq
> flushed_seq
;
46 mutex_unlock(&b
->lock
);
51 static bool bucket_table_insert(struct buckets_waiting_for_journal_table
*t
,
52 struct bucket_hashed
*new,
55 struct bucket_hashed
*last_evicted
= NULL
;
58 for (tries
= 0; tries
< 10; tries
++) {
59 struct bucket_hashed
*old
, *victim
= NULL
;
61 for (i
= 0; i
< ARRAY_SIZE(t
->hash_seeds
); i
++) {
62 old
= bucket_hash(t
, i
, new->dev_bucket
);
64 if (old
->dev_bucket
== new->dev_bucket
||
65 old
->journal_seq
<= flushed_seq
) {
70 if (last_evicted
!= old
)
74 /* hashed to same slot 3 times: */
78 /* Failed to find an empty slot: */
80 last_evicted
= victim
;
86 int bch2_set_bucket_needs_journal_commit(struct buckets_waiting_for_journal
*b
,
88 unsigned dev
, u64 bucket
,
91 struct buckets_waiting_for_journal_table
*t
, *n
;
92 struct bucket_hashed tmp
, new = {
93 .dev_bucket
= (u64
) dev
<< 56 | bucket
,
94 .journal_seq
= journal_seq
,
96 size_t i
, size
, new_bits
, nr_elements
= 1, nr_rehashes
= 0, nr_rehashes_this_size
= 0;
101 if (likely(bucket_table_insert(b
->t
, &new, flushed_seq
)))
105 size
= 1UL << t
->bits
;
106 for (i
= 0; i
< size
; i
++)
107 nr_elements
+= t
->d
[i
].journal_seq
> flushed_seq
;
109 new_bits
= ilog2(roundup_pow_of_two(nr_elements
* 3));
111 n
= kvmalloc(sizeof(*n
) + (sizeof(n
->d
[0]) << new_bits
), GFP_KERNEL
);
113 ret
= -BCH_ERR_ENOMEM_buckets_waiting_for_journal_set
;
118 if (nr_rehashes_this_size
== 3) {
120 nr_rehashes_this_size
= 0;
126 nr_rehashes_this_size
++;
128 bucket_table_init(n
, new_bits
);
131 BUG_ON(!bucket_table_insert(n
, &tmp
, flushed_seq
));
133 for (i
= 0; i
< 1UL << t
->bits
; i
++) {
134 if (t
->d
[i
].journal_seq
<= flushed_seq
)
138 if (!bucket_table_insert(n
, &tmp
, flushed_seq
))
145 pr_debug("took %zu rehashes, table at %zu/%lu elements",
146 nr_rehashes
, nr_elements
, 1UL << b
->t
->bits
);
148 mutex_unlock(&b
->lock
);
153 void bch2_fs_buckets_waiting_for_journal_exit(struct bch_fs
*c
)
155 struct buckets_waiting_for_journal
*b
= &c
->buckets_waiting_for_journal
;
160 #define INITIAL_TABLE_BITS 3
162 int bch2_fs_buckets_waiting_for_journal_init(struct bch_fs
*c
)
164 struct buckets_waiting_for_journal
*b
= &c
->buckets_waiting_for_journal
;
166 mutex_init(&b
->lock
);
168 b
->t
= kvmalloc(sizeof(*b
->t
) +
169 (sizeof(b
->t
->d
[0]) << INITIAL_TABLE_BITS
), GFP_KERNEL
);
171 return -BCH_ERR_ENOMEM_buckets_waiting_for_journal_init
;
173 bucket_table_init(b
->t
, INITIAL_TABLE_BITS
);