aboutsummaryrefslogtreecommitdiffstats
path: root/net/batman-adv/hash.h
diff options
context:
space:
mode:
authorMarek Lindner <lindner_marek@yahoo.de>2011-02-18 07:28:09 -0500
committerMarek Lindner <lindner_marek@yahoo.de>2011-03-05 06:52:00 -0500
commit7aadf889e897155c45cda230d2a6701ad1fbff61 (patch)
tree4a31df411c29844afe25ccde17d2ff9e618241c1 /net/batman-adv/hash.h
parent39901e716275da4e831b40f9e45a1b61d6a776dc (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.h95
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 */
31typedef int (*hashdata_compare_cb)(void *, void *); 31typedef 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 */
36typedef int (*hashdata_choose_cb)(void *, int); 36typedef int (*hashdata_choose_cb)(void *, int);
37typedef void (*hashdata_free_cb)(void *, void *); 37typedef void (*hashdata_free_cb)(struct hlist_node *, void *);
38
39struct 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
45struct hashtable_t { 39struct 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. */
55void hash_destroy(struct hashtable_t *hash); 49void hash_destroy(struct hashtable_t *hash);
56 50
57void 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 */
90static inline int hash_add(struct hashtable_t *hash, 80static 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 **/
170static 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_ */