1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
#include "hashtable.h"
#include "linux/random.h"
#include <linux/slab.h>
struct htable_free_rcu {
struct rcu_head rcu;
unsigned order;
unsigned long addr;
};
static void htable_free_rcu(struct rcu_head *rcu)
{
struct htable_free_rcu *free_rcu =
container_of(rcu, struct htable_free_rcu, rcu);
free_pages(free_rcu->addr, free_rcu->order);
kfree(free_rcu);
}
void bch2_htable_expand(struct htable *ht, const struct htable_params p)
{
struct htable_ptr old, new;
struct hlist_node *pos, *n;
struct htable_free_rcu *free_rcu;
unsigned shift = ht->table & ~PAGE_MASK;
unsigned i;
old = htable_read_ptr(ht);
new.size = old.size * 2;
free_rcu = kmalloc(sizeof(*free_rcu), GFP_KERNEL);
if (!free_rcu)
return;
free_rcu->order = shift;
free_rcu->addr = (unsigned long) old.table;
new.table = (void *) __get_free_pages(GFP_KERNEL|__GFP_ZERO, shift + 1);
if (!new.table) {
kfree(free_rcu);
return;
}
for (i = 0; i < old.size; i++) {
hlist_for_each_safe(pos, n, old.table + i) {
void *obj = htable_obj(pos, p);
unsigned hash = htable_obj_get_hash(obj, ht->hash_seed, p);
hlist_del_rcu(pos);
hlist_add_head_rcu(pos, htable_bucket(new, hash));
}
}
smp_store_release(&ht->table, (unsigned long) new.table | (shift + 1));
ht->max_chain = 1;
call_rcu(&free_rcu->rcu, htable_free_rcu);
}
void bch2_htable_exit(struct htable *ht)
{
unsigned long table = ht->table & PAGE_MASK;
unsigned order = ht->table & ~PAGE_MASK;
free_pages(table, order);
}
int bch2_htable_init(struct htable *ht)
{
mutex_init(&ht->lock);
ht->hash_seed = get_random_u32();
ht->nelems = 0;
ht->max_chain = 1;
ht->table = __get_free_page(GFP_KERNEL|__GFP_ZERO);
if (!ht->table)
return -ENOMEM;
return 0;
}
|