diff options
author | Marek Lindner <lindner_marek@yahoo.de> | 2011-02-18 07:28:09 -0500 |
---|---|---|
committer | Marek Lindner <lindner_marek@yahoo.de> | 2011-03-05 06:52:00 -0500 |
commit | 7aadf889e897155c45cda230d2a6701ad1fbff61 (patch) | |
tree | 4a31df411c29844afe25ccde17d2ff9e618241c1 /net/batman-adv/hash.h | |
parent | 39901e716275da4e831b40f9e45a1b61d6a776dc (diff) |
batman-adv: remove extra layer between hash and hash element - hash bucket
Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
Diffstat (limited to 'net/batman-adv/hash.h')
-rw-r--r-- | net/batman-adv/hash.h | 95 |
1 files changed, 24 insertions, 71 deletions
diff --git a/net/batman-adv/hash.h b/net/batman-adv/hash.h index 3c48c6bb1acd..434822b27473 100644 --- a/net/batman-adv/hash.h +++ b/net/batman-adv/hash.h | |||
@@ -28,19 +28,13 @@ | |||
28 | * compare 2 element datas for their keys, | 28 | * compare 2 element datas for their keys, |
29 | * return 0 if same and not 0 if not | 29 | * return 0 if same and not 0 if not |
30 | * same */ | 30 | * same */ |
31 | typedef int (*hashdata_compare_cb)(void *, void *); | 31 | typedef int (*hashdata_compare_cb)(struct hlist_node *, void *); |
32 | 32 | ||
33 | /* the hashfunction, should return an index | 33 | /* the hashfunction, should return an index |
34 | * based on the key in the data of the first | 34 | * based on the key in the data of the first |
35 | * argument and the size the second */ | 35 | * argument and the size the second */ |
36 | typedef int (*hashdata_choose_cb)(void *, int); | 36 | typedef int (*hashdata_choose_cb)(void *, int); |
37 | typedef void (*hashdata_free_cb)(void *, void *); | 37 | typedef void (*hashdata_free_cb)(struct hlist_node *, void *); |
38 | |||
39 | struct element_t { | ||
40 | void *data; /* pointer to the data */ | ||
41 | struct hlist_node hlist; /* bucket list pointer */ | ||
42 | struct rcu_head rcu; | ||
43 | }; | ||
44 | 38 | ||
45 | struct hashtable_t { | 39 | struct hashtable_t { |
46 | struct hlist_head *table; /* the hashtable itself with the buckets */ | 40 | struct hlist_head *table; /* the hashtable itself with the buckets */ |
@@ -54,8 +48,6 @@ struct hashtable_t *hash_new(int size); | |||
54 | /* free only the hashtable and the hash itself. */ | 48 | /* free only the hashtable and the hash itself. */ |
55 | void hash_destroy(struct hashtable_t *hash); | 49 | void hash_destroy(struct hashtable_t *hash); |
56 | 50 | ||
57 | void bucket_free_rcu(struct rcu_head *rcu); | ||
58 | |||
59 | /* remove the hash structure. if hashdata_free_cb != NULL, this function will be | 51 | /* remove the hash structure. if hashdata_free_cb != NULL, this function will be |
60 | * called to remove the elements inside of the hash. if you don't remove the | 52 | * called to remove the elements inside of the hash. if you don't remove the |
61 | * elements, memory might be leaked. */ | 53 | * elements, memory might be leaked. */ |
@@ -63,8 +55,7 @@ static inline void hash_delete(struct hashtable_t *hash, | |||
63 | hashdata_free_cb free_cb, void *arg) | 55 | hashdata_free_cb free_cb, void *arg) |
64 | { | 56 | { |
65 | struct hlist_head *head; | 57 | struct hlist_head *head; |
66 | struct hlist_node *walk, *safe; | 58 | struct hlist_node *node, *node_tmp; |
67 | struct element_t *bucket; | ||
68 | spinlock_t *list_lock; /* spinlock to protect write access */ | 59 | spinlock_t *list_lock; /* spinlock to protect write access */ |
69 | int i; | 60 | int i; |
70 | 61 | ||
@@ -73,12 +64,11 @@ static inline void hash_delete(struct hashtable_t *hash, | |||
73 | list_lock = &hash->list_locks[i]; | 64 | list_lock = &hash->list_locks[i]; |
74 | 65 | ||
75 | spin_lock_bh(list_lock); | 66 | spin_lock_bh(list_lock); |
76 | hlist_for_each_entry_safe(bucket, walk, safe, head, hlist) { | 67 | hlist_for_each_safe(node, node_tmp, head) { |
77 | if (free_cb) | 68 | hlist_del_rcu(node); |
78 | free_cb(bucket->data, arg); | ||
79 | 69 | ||
80 | hlist_del_rcu(walk); | 70 | if (free_cb) |
81 | call_rcu(&bucket->rcu, bucket_free_rcu); | 71 | free_cb(node, arg); |
82 | } | 72 | } |
83 | spin_unlock_bh(list_lock); | 73 | spin_unlock_bh(list_lock); |
84 | } | 74 | } |
@@ -89,12 +79,12 @@ static inline void hash_delete(struct hashtable_t *hash, | |||
89 | /* adds data to the hashtable. returns 0 on success, -1 on error */ | 79 | /* adds data to the hashtable. returns 0 on success, -1 on error */ |
90 | static inline int hash_add(struct hashtable_t *hash, | 80 | static inline int hash_add(struct hashtable_t *hash, |
91 | hashdata_compare_cb compare, | 81 | hashdata_compare_cb compare, |
92 | hashdata_choose_cb choose, void *data) | 82 | hashdata_choose_cb choose, |
83 | void *data, struct hlist_node *data_node) | ||
93 | { | 84 | { |
94 | int index; | 85 | int index; |
95 | struct hlist_head *head; | 86 | struct hlist_head *head; |
96 | struct hlist_node *walk, *safe; | 87 | struct hlist_node *node; |
97 | struct element_t *bucket; | ||
98 | spinlock_t *list_lock; /* spinlock to protect write access */ | 88 | spinlock_t *list_lock; /* spinlock to protect write access */ |
99 | 89 | ||
100 | if (!hash) | 90 | if (!hash) |
@@ -105,21 +95,17 @@ static inline int hash_add(struct hashtable_t *hash, | |||
105 | list_lock = &hash->list_locks[index]; | 95 | list_lock = &hash->list_locks[index]; |
106 | 96 | ||
107 | rcu_read_lock(); | 97 | rcu_read_lock(); |
108 | hlist_for_each_entry_safe(bucket, walk, safe, head, hlist) { | 98 | __hlist_for_each_rcu(node, head) { |
109 | if (compare(bucket->data, data)) | 99 | if (!compare(node, data)) |
110 | goto err_unlock; | 100 | continue; |
101 | |||
102 | goto err_unlock; | ||
111 | } | 103 | } |
112 | rcu_read_unlock(); | 104 | rcu_read_unlock(); |
113 | 105 | ||
114 | /* no duplicate found in list, add new element */ | 106 | /* no duplicate found in list, add new element */ |
115 | bucket = kmalloc(sizeof(struct element_t), GFP_ATOMIC); | ||
116 | if (!bucket) | ||
117 | goto err; | ||
118 | |||
119 | bucket->data = data; | ||
120 | |||
121 | spin_lock_bh(list_lock); | 107 | spin_lock_bh(list_lock); |
122 | hlist_add_head_rcu(&bucket->hlist, head); | 108 | hlist_add_head_rcu(data_node, head); |
123 | spin_unlock_bh(list_lock); | 109 | spin_unlock_bh(list_lock); |
124 | 110 | ||
125 | return 0; | 111 | return 0; |
@@ -139,8 +125,7 @@ static inline void *hash_remove(struct hashtable_t *hash, | |||
139 | hashdata_choose_cb choose, void *data) | 125 | hashdata_choose_cb choose, void *data) |
140 | { | 126 | { |
141 | size_t index; | 127 | size_t index; |
142 | struct hlist_node *walk; | 128 | struct hlist_node *node; |
143 | struct element_t *bucket; | ||
144 | struct hlist_head *head; | 129 | struct hlist_head *head; |
145 | void *data_save = NULL; | 130 | void *data_save = NULL; |
146 | 131 | ||
@@ -148,49 +133,17 @@ static inline void *hash_remove(struct hashtable_t *hash, | |||
148 | head = &hash->table[index]; | 133 | head = &hash->table[index]; |
149 | 134 | ||
150 | spin_lock_bh(&hash->list_locks[index]); | 135 | spin_lock_bh(&hash->list_locks[index]); |
151 | hlist_for_each_entry(bucket, walk, head, hlist) { | 136 | hlist_for_each(node, head) { |
152 | if (compare(bucket->data, data)) { | 137 | if (!compare(node, data)) |
153 | data_save = bucket->data; | 138 | continue; |
154 | hlist_del_rcu(walk); | 139 | |
155 | call_rcu(&bucket->rcu, bucket_free_rcu); | 140 | data_save = node; |
156 | break; | 141 | hlist_del_rcu(node); |
157 | } | 142 | break; |
158 | } | 143 | } |
159 | spin_unlock_bh(&hash->list_locks[index]); | 144 | spin_unlock_bh(&hash->list_locks[index]); |
160 | 145 | ||
161 | return data_save; | 146 | return data_save; |
162 | } | 147 | } |
163 | 148 | ||
164 | /** | ||
165 | * finds data, based on the key in keydata. returns the found data on success, | ||
166 | * or NULL on error | ||
167 | * | ||
168 | * caller must lock with rcu_read_lock() / rcu_read_unlock() | ||
169 | **/ | ||
170 | static inline void *hash_find(struct hashtable_t *hash, | ||
171 | hashdata_compare_cb compare, | ||
172 | hashdata_choose_cb choose, void *keydata) | ||
173 | { | ||
174 | int index; | ||
175 | struct hlist_head *head; | ||
176 | struct hlist_node *walk; | ||
177 | struct element_t *bucket; | ||
178 | void *bucket_data = NULL; | ||
179 | |||
180 | if (!hash) | ||
181 | return NULL; | ||
182 | |||
183 | index = choose(keydata , hash->size); | ||
184 | head = &hash->table[index]; | ||
185 | |||
186 | hlist_for_each_entry(bucket, walk, head, hlist) { | ||
187 | if (compare(bucket->data, keydata)) { | ||
188 | bucket_data = bucket->data; | ||
189 | break; | ||
190 | } | ||
191 | } | ||
192 | |||
193 | return bucket_data; | ||
194 | } | ||
195 | |||
196 | #endif /* _NET_BATMAN_ADV_HASH_H_ */ | 149 | #endif /* _NET_BATMAN_ADV_HASH_H_ */ |