aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarek Lindner <lindner_marek@yahoo.de>2011-01-19 15:01:40 -0500
committerMarek Lindner <lindner_marek@yahoo.de>2011-03-05 06:49:58 -0500
commitfb778ea173fcd58b8fc3d75c674f07fab187b55f (patch)
treeb14cfc99b7ca61ddcb49cc56c9a8e2822675debc
parenta775eb847ae66211577d4fd2c46749b77c9993c9 (diff)
batman-adv: protect each hash row with rcu locks
Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
-rw-r--r--net/batman-adv/hash.c34
-rw-r--r--net/batman-adv/hash.h73
-rw-r--r--net/batman-adv/icmp_socket.c2
-rw-r--r--net/batman-adv/originator.c27
-rw-r--r--net/batman-adv/routing.c16
-rw-r--r--net/batman-adv/translation-table.c14
-rw-r--r--net/batman-adv/unicast.c2
-rw-r--r--net/batman-adv/vis.c18
8 files changed, 141 insertions, 45 deletions
diff --git a/net/batman-adv/hash.c b/net/batman-adv/hash.c
index fa2693973ab8..02653666a26b 100644
--- a/net/batman-adv/hash.c
+++ b/net/batman-adv/hash.c
@@ -27,13 +27,16 @@ static void hash_init(struct hashtable_t *hash)
27{ 27{
28 int i; 28 int i;
29 29
30 for (i = 0 ; i < hash->size; i++) 30 for (i = 0 ; i < hash->size; i++) {
31 INIT_HLIST_HEAD(&hash->table[i]); 31 INIT_HLIST_HEAD(&hash->table[i]);
32 spin_lock_init(&hash->list_locks[i]);
33 }
32} 34}
33 35
34/* free only the hashtable and the hash itself. */ 36/* free only the hashtable and the hash itself. */
35void hash_destroy(struct hashtable_t *hash) 37void hash_destroy(struct hashtable_t *hash)
36{ 38{
39 kfree(hash->list_locks);
37 kfree(hash->table); 40 kfree(hash->table);
38 kfree(hash); 41 kfree(hash);
39} 42}
@@ -43,20 +46,33 @@ struct hashtable_t *hash_new(int size)
43{ 46{
44 struct hashtable_t *hash; 47 struct hashtable_t *hash;
45 48
46 hash = kmalloc(sizeof(struct hashtable_t) , GFP_ATOMIC); 49 hash = kmalloc(sizeof(struct hashtable_t), GFP_ATOMIC);
47
48 if (!hash) 50 if (!hash)
49 return NULL; 51 return NULL;
50 52
51 hash->size = size;
52 hash->table = kmalloc(sizeof(struct element_t *) * size, GFP_ATOMIC); 53 hash->table = kmalloc(sizeof(struct element_t *) * size, GFP_ATOMIC);
54 if (!hash->table)
55 goto free_hash;
53 56
54 if (!hash->table) { 57 hash->list_locks = kmalloc(sizeof(spinlock_t) * size, GFP_ATOMIC);
55 kfree(hash); 58 if (!hash->list_locks)
56 return NULL; 59 goto free_table;
57 }
58 60
61 hash->size = size;
59 hash_init(hash); 62 hash_init(hash);
60
61 return hash; 63 return hash;
64
65free_table:
66 kfree(hash->table);
67free_hash:
68 kfree(hash);
69 return NULL;
70}
71
72void bucket_free_rcu(struct rcu_head *rcu)
73{
74 struct element_t *bucket;
75
76 bucket = container_of(rcu, struct element_t, rcu);
77 kfree(bucket);
62} 78}
diff --git a/net/batman-adv/hash.h b/net/batman-adv/hash.h
index eae24402fd0a..3c48c6bb1acd 100644
--- a/net/batman-adv/hash.h
+++ b/net/batman-adv/hash.h
@@ -39,10 +39,12 @@ typedef void (*hashdata_free_cb)(void *, void *);
39struct element_t { 39struct element_t {
40 void *data; /* pointer to the data */ 40 void *data; /* pointer to the data */
41 struct hlist_node hlist; /* bucket list pointer */ 41 struct hlist_node hlist; /* bucket list pointer */
42 struct rcu_head rcu;
42}; 43};
43 44
44struct hashtable_t { 45struct hashtable_t {
45 struct hlist_head *table; /* the hashtable itself, with the buckets */ 46 struct hlist_head *table; /* the hashtable itself with the buckets */
47 spinlock_t *list_locks; /* spinlock for each hash list entry */
46 int size; /* size of hashtable */ 48 int size; /* size of hashtable */
47}; 49};
48 50
@@ -52,6 +54,8 @@ struct hashtable_t *hash_new(int size);
52/* free only the hashtable and the hash itself. */ 54/* free only the hashtable and the hash itself. */
53void hash_destroy(struct hashtable_t *hash); 55void hash_destroy(struct hashtable_t *hash);
54 56
57void bucket_free_rcu(struct rcu_head *rcu);
58
55/* remove the hash structure. if hashdata_free_cb != NULL, this function will be 59/* remove the hash structure. if hashdata_free_cb != NULL, this function will be
56 * called to remove the elements inside of the hash. if you don't remove the 60 * called to remove the elements inside of the hash. if you don't remove the
57 * elements, memory might be leaked. */ 61 * elements, memory might be leaked. */
@@ -61,19 +65,22 @@ static inline void hash_delete(struct hashtable_t *hash,
61 struct hlist_head *head; 65 struct hlist_head *head;
62 struct hlist_node *walk, *safe; 66 struct hlist_node *walk, *safe;
63 struct element_t *bucket; 67 struct element_t *bucket;
68 spinlock_t *list_lock; /* spinlock to protect write access */
64 int i; 69 int i;
65 70
66 for (i = 0; i < hash->size; i++) { 71 for (i = 0; i < hash->size; i++) {
67 head = &hash->table[i]; 72 head = &hash->table[i];
73 list_lock = &hash->list_locks[i];
68 74
69 hlist_for_each_safe(walk, safe, head) { 75 spin_lock_bh(list_lock);
70 bucket = hlist_entry(walk, struct element_t, hlist); 76 hlist_for_each_entry_safe(bucket, walk, safe, head, hlist) {
71 if (free_cb) 77 if (free_cb)
72 free_cb(bucket->data, arg); 78 free_cb(bucket->data, arg);
73 79
74 hlist_del(walk); 80 hlist_del_rcu(walk);
75 kfree(bucket); 81 call_rcu(&bucket->rcu, bucket_free_rcu);
76 } 82 }
83 spin_unlock_bh(list_lock);
77 } 84 }
78 85
79 hash_destroy(hash); 86 hash_destroy(hash);
@@ -88,29 +95,39 @@ static inline int hash_add(struct hashtable_t *hash,
88 struct hlist_head *head; 95 struct hlist_head *head;
89 struct hlist_node *walk, *safe; 96 struct hlist_node *walk, *safe;
90 struct element_t *bucket; 97 struct element_t *bucket;
98 spinlock_t *list_lock; /* spinlock to protect write access */
91 99
92 if (!hash) 100 if (!hash)
93 return -1; 101 goto err;
94 102
95 index = choose(data, hash->size); 103 index = choose(data, hash->size);
96 head = &hash->table[index]; 104 head = &hash->table[index];
105 list_lock = &hash->list_locks[index];
97 106
98 hlist_for_each_safe(walk, safe, head) { 107 rcu_read_lock();
99 bucket = hlist_entry(walk, struct element_t, hlist); 108 hlist_for_each_entry_safe(bucket, walk, safe, head, hlist) {
100 if (compare(bucket->data, data)) 109 if (compare(bucket->data, data))
101 return -1; 110 goto err_unlock;
102 } 111 }
112 rcu_read_unlock();
103 113
104 /* no duplicate found in list, add new element */ 114 /* no duplicate found in list, add new element */
105 bucket = kmalloc(sizeof(struct element_t), GFP_ATOMIC); 115 bucket = kmalloc(sizeof(struct element_t), GFP_ATOMIC);
106
107 if (!bucket) 116 if (!bucket)
108 return -1; 117 goto err;
109 118
110 bucket->data = data; 119 bucket->data = data;
111 hlist_add_head(&bucket->hlist, head); 120
121 spin_lock_bh(list_lock);
122 hlist_add_head_rcu(&bucket->hlist, head);
123 spin_unlock_bh(list_lock);
112 124
113 return 0; 125 return 0;
126
127err_unlock:
128 rcu_read_unlock();
129err:
130 return -1;
114} 131}
115 132
116/* removes data from hash, if found. returns pointer do data on success, so you 133/* removes data from hash, if found. returns pointer do data on success, so you
@@ -125,25 +142,31 @@ static inline void *hash_remove(struct hashtable_t *hash,
125 struct hlist_node *walk; 142 struct hlist_node *walk;
126 struct element_t *bucket; 143 struct element_t *bucket;
127 struct hlist_head *head; 144 struct hlist_head *head;
128 void *data_save; 145 void *data_save = NULL;
129 146
130 index = choose(data, hash->size); 147 index = choose(data, hash->size);
131 head = &hash->table[index]; 148 head = &hash->table[index];
132 149
150 spin_lock_bh(&hash->list_locks[index]);
133 hlist_for_each_entry(bucket, walk, head, hlist) { 151 hlist_for_each_entry(bucket, walk, head, hlist) {
134 if (compare(bucket->data, data)) { 152 if (compare(bucket->data, data)) {
135 data_save = bucket->data; 153 data_save = bucket->data;
136 hlist_del(walk); 154 hlist_del_rcu(walk);
137 kfree(bucket); 155 call_rcu(&bucket->rcu, bucket_free_rcu);
138 return data_save; 156 break;
139 } 157 }
140 } 158 }
159 spin_unlock_bh(&hash->list_locks[index]);
141 160
142 return NULL; 161 return data_save;
143} 162}
144 163
145/* finds data, based on the key in keydata. returns the found data on success, 164/**
146 * or NULL on error */ 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 **/
147static inline void *hash_find(struct hashtable_t *hash, 170static inline void *hash_find(struct hashtable_t *hash,
148 hashdata_compare_cb compare, 171 hashdata_compare_cb compare,
149 hashdata_choose_cb choose, void *keydata) 172 hashdata_choose_cb choose, void *keydata)
@@ -152,6 +175,7 @@ static inline void *hash_find(struct hashtable_t *hash,
152 struct hlist_head *head; 175 struct hlist_head *head;
153 struct hlist_node *walk; 176 struct hlist_node *walk;
154 struct element_t *bucket; 177 struct element_t *bucket;
178 void *bucket_data = NULL;
155 179
156 if (!hash) 180 if (!hash)
157 return NULL; 181 return NULL;
@@ -159,13 +183,14 @@ static inline void *hash_find(struct hashtable_t *hash,
159 index = choose(keydata , hash->size); 183 index = choose(keydata , hash->size);
160 head = &hash->table[index]; 184 head = &hash->table[index];
161 185
162 hlist_for_each(walk, head) { 186 hlist_for_each_entry(bucket, walk, head, hlist) {
163 bucket = hlist_entry(walk, struct element_t, hlist); 187 if (compare(bucket->data, keydata)) {
164 if (compare(bucket->data, keydata)) 188 bucket_data = bucket->data;
165 return bucket->data; 189 break;
190 }
166 } 191 }
167 192
168 return NULL; 193 return bucket_data;
169} 194}
170 195
171#endif /* _NET_BATMAN_ADV_HASH_H_ */ 196#endif /* _NET_BATMAN_ADV_HASH_H_ */
diff --git a/net/batman-adv/icmp_socket.c b/net/batman-adv/icmp_socket.c
index 319a7ccf6efa..8e0cd8a1bc02 100644
--- a/net/batman-adv/icmp_socket.c
+++ b/net/batman-adv/icmp_socket.c
@@ -220,9 +220,11 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
220 goto dst_unreach; 220 goto dst_unreach;
221 221
222 spin_lock_bh(&bat_priv->orig_hash_lock); 222 spin_lock_bh(&bat_priv->orig_hash_lock);
223 rcu_read_lock();
223 orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, 224 orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash,
224 compare_orig, choose_orig, 225 compare_orig, choose_orig,
225 icmp_packet->dst)); 226 icmp_packet->dst));
227 rcu_read_unlock();
226 228
227 if (!orig_node) 229 if (!orig_node)
228 goto unlock; 230 goto unlock;
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index 899d4943d8ad..5c32314f8279 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -150,9 +150,11 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
150 int size; 150 int size;
151 int hash_added; 151 int hash_added;
152 152
153 rcu_read_lock();
153 orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, 154 orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash,
154 compare_orig, choose_orig, 155 compare_orig, choose_orig,
155 addr)); 156 addr));
157 rcu_read_unlock();
156 158
157 if (orig_node) 159 if (orig_node)
158 return orig_node; 160 return orig_node;
@@ -294,6 +296,7 @@ static void _purge_orig(struct bat_priv *bat_priv)
294 struct hlist_node *walk, *safe; 296 struct hlist_node *walk, *safe;
295 struct hlist_head *head; 297 struct hlist_head *head;
296 struct element_t *bucket; 298 struct element_t *bucket;
299 spinlock_t *list_lock; /* spinlock to protect write access */
297 struct orig_node *orig_node; 300 struct orig_node *orig_node;
298 int i; 301 int i;
299 302
@@ -305,22 +308,26 @@ static void _purge_orig(struct bat_priv *bat_priv)
305 /* for all origins... */ 308 /* for all origins... */
306 for (i = 0; i < hash->size; i++) { 309 for (i = 0; i < hash->size; i++) {
307 head = &hash->table[i]; 310 head = &hash->table[i];
311 list_lock = &hash->list_locks[i];
308 312
313 spin_lock_bh(list_lock);
309 hlist_for_each_entry_safe(bucket, walk, safe, head, hlist) { 314 hlist_for_each_entry_safe(bucket, walk, safe, head, hlist) {
310 orig_node = bucket->data; 315 orig_node = bucket->data;
311 316
312 if (purge_orig_node(bat_priv, orig_node)) { 317 if (purge_orig_node(bat_priv, orig_node)) {
313 if (orig_node->gw_flags) 318 if (orig_node->gw_flags)
314 gw_node_delete(bat_priv, orig_node); 319 gw_node_delete(bat_priv, orig_node);
315 hlist_del(walk); 320 hlist_del_rcu(walk);
316 kfree(bucket); 321 call_rcu(&bucket->rcu, bucket_free_rcu);
317 free_orig_node(orig_node, bat_priv); 322 free_orig_node(orig_node, bat_priv);
323 continue;
318 } 324 }
319 325
320 if (time_after(jiffies, orig_node->last_frag_packet + 326 if (time_after(jiffies, orig_node->last_frag_packet +
321 msecs_to_jiffies(FRAG_TIMEOUT))) 327 msecs_to_jiffies(FRAG_TIMEOUT)))
322 frag_list_free(&orig_node->frag_list); 328 frag_list_free(&orig_node->frag_list);
323 } 329 }
330 spin_unlock_bh(list_lock);
324 } 331 }
325 332
326 spin_unlock_bh(&bat_priv->orig_hash_lock); 333 spin_unlock_bh(&bat_priv->orig_hash_lock);
@@ -387,7 +394,8 @@ int orig_seq_print_text(struct seq_file *seq, void *offset)
387 for (i = 0; i < hash->size; i++) { 394 for (i = 0; i < hash->size; i++) {
388 head = &hash->table[i]; 395 head = &hash->table[i];
389 396
390 hlist_for_each_entry(bucket, walk, head, hlist) { 397 rcu_read_lock();
398 hlist_for_each_entry_rcu(bucket, walk, head, hlist) {
391 orig_node = bucket->data; 399 orig_node = bucket->data;
392 400
393 if (!orig_node->router) 401 if (!orig_node->router)
@@ -408,17 +416,16 @@ int orig_seq_print_text(struct seq_file *seq, void *offset)
408 neigh_node->addr, 416 neigh_node->addr,
409 neigh_node->if_incoming->net_dev->name); 417 neigh_node->if_incoming->net_dev->name);
410 418
411 rcu_read_lock();
412 hlist_for_each_entry_rcu(neigh_node, node, 419 hlist_for_each_entry_rcu(neigh_node, node,
413 &orig_node->neigh_list, list) { 420 &orig_node->neigh_list, list) {
414 seq_printf(seq, " %pM (%3i)", neigh_node->addr, 421 seq_printf(seq, " %pM (%3i)", neigh_node->addr,
415 neigh_node->tq_avg); 422 neigh_node->tq_avg);
416 } 423 }
417 rcu_read_unlock();
418 424
419 seq_printf(seq, "\n"); 425 seq_printf(seq, "\n");
420 batman_count++; 426 batman_count++;
421 } 427 }
428 rcu_read_unlock();
422 } 429 }
423 430
424 spin_unlock_bh(&bat_priv->orig_hash_lock); 431 spin_unlock_bh(&bat_priv->orig_hash_lock);
@@ -476,18 +483,21 @@ int orig_hash_add_if(struct batman_if *batman_if, int max_if_num)
476 for (i = 0; i < hash->size; i++) { 483 for (i = 0; i < hash->size; i++) {
477 head = &hash->table[i]; 484 head = &hash->table[i];
478 485
479 hlist_for_each_entry(bucket, walk, head, hlist) { 486 rcu_read_lock();
487 hlist_for_each_entry_rcu(bucket, walk, head, hlist) {
480 orig_node = bucket->data; 488 orig_node = bucket->data;
481 489
482 if (orig_node_add_if(orig_node, max_if_num) == -1) 490 if (orig_node_add_if(orig_node, max_if_num) == -1)
483 goto err; 491 goto err;
484 } 492 }
493 rcu_read_unlock();
485 } 494 }
486 495
487 spin_unlock_bh(&bat_priv->orig_hash_lock); 496 spin_unlock_bh(&bat_priv->orig_hash_lock);
488 return 0; 497 return 0;
489 498
490err: 499err:
500 rcu_read_unlock();
491 spin_unlock_bh(&bat_priv->orig_hash_lock); 501 spin_unlock_bh(&bat_priv->orig_hash_lock);
492 return -ENOMEM; 502 return -ENOMEM;
493} 503}
@@ -562,7 +572,8 @@ int orig_hash_del_if(struct batman_if *batman_if, int max_if_num)
562 for (i = 0; i < hash->size; i++) { 572 for (i = 0; i < hash->size; i++) {
563 head = &hash->table[i]; 573 head = &hash->table[i];
564 574
565 hlist_for_each_entry(bucket, walk, head, hlist) { 575 rcu_read_lock();
576 hlist_for_each_entry_rcu(bucket, walk, head, hlist) {
566 orig_node = bucket->data; 577 orig_node = bucket->data;
567 578
568 ret = orig_node_del_if(orig_node, max_if_num, 579 ret = orig_node_del_if(orig_node, max_if_num,
@@ -571,6 +582,7 @@ int orig_hash_del_if(struct batman_if *batman_if, int max_if_num)
571 if (ret == -1) 582 if (ret == -1)
572 goto err; 583 goto err;
573 } 584 }
585 rcu_read_unlock();
574 } 586 }
575 587
576 /* renumber remaining batman interfaces _inside_ of orig_hash_lock */ 588 /* renumber remaining batman interfaces _inside_ of orig_hash_lock */
@@ -595,6 +607,7 @@ int orig_hash_del_if(struct batman_if *batman_if, int max_if_num)
595 return 0; 607 return 0;
596 608
597err: 609err:
610 rcu_read_unlock();
598 spin_unlock_bh(&bat_priv->orig_hash_lock); 611 spin_unlock_bh(&bat_priv->orig_hash_lock);
599 return -ENOMEM; 612 return -ENOMEM;
600} 613}
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index c15e6c1c20b5..32ae04e26a05 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -52,7 +52,8 @@ void slide_own_bcast_window(struct batman_if *batman_if)
52 for (i = 0; i < hash->size; i++) { 52 for (i = 0; i < hash->size; i++) {
53 head = &hash->table[i]; 53 head = &hash->table[i];
54 54
55 hlist_for_each_entry(bucket, walk, head, hlist) { 55 rcu_read_lock();
56 hlist_for_each_entry_rcu(bucket, walk, head, hlist) {
56 orig_node = bucket->data; 57 orig_node = bucket->data;
57 word_index = batman_if->if_num * NUM_WORDS; 58 word_index = batman_if->if_num * NUM_WORDS;
58 word = &(orig_node->bcast_own[word_index]); 59 word = &(orig_node->bcast_own[word_index]);
@@ -61,6 +62,7 @@ void slide_own_bcast_window(struct batman_if *batman_if)
61 orig_node->bcast_own_sum[batman_if->if_num] = 62 orig_node->bcast_own_sum[batman_if->if_num] =
62 bit_packet_count(word); 63 bit_packet_count(word);
63 } 64 }
65 rcu_read_unlock();
64 } 66 }
65 67
66 spin_unlock_bh(&bat_priv->orig_hash_lock); 68 spin_unlock_bh(&bat_priv->orig_hash_lock);
@@ -873,9 +875,11 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv,
873 /* answer echo request (ping) */ 875 /* answer echo request (ping) */
874 /* get routing information */ 876 /* get routing information */
875 spin_lock_bh(&bat_priv->orig_hash_lock); 877 spin_lock_bh(&bat_priv->orig_hash_lock);
878 rcu_read_lock();
876 orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, 879 orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash,
877 compare_orig, choose_orig, 880 compare_orig, choose_orig,
878 icmp_packet->orig)); 881 icmp_packet->orig));
882 rcu_read_unlock();
879 ret = NET_RX_DROP; 883 ret = NET_RX_DROP;
880 884
881 if ((orig_node) && (orig_node->router)) { 885 if ((orig_node) && (orig_node->router)) {
@@ -931,9 +935,11 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
931 935
932 /* get routing information */ 936 /* get routing information */
933 spin_lock_bh(&bat_priv->orig_hash_lock); 937 spin_lock_bh(&bat_priv->orig_hash_lock);
938 rcu_read_lock();
934 orig_node = ((struct orig_node *) 939 orig_node = ((struct orig_node *)
935 hash_find(bat_priv->orig_hash, compare_orig, choose_orig, 940 hash_find(bat_priv->orig_hash, compare_orig, choose_orig,
936 icmp_packet->orig)); 941 icmp_packet->orig));
942 rcu_read_unlock();
937 ret = NET_RX_DROP; 943 ret = NET_RX_DROP;
938 944
939 if ((orig_node) && (orig_node->router)) { 945 if ((orig_node) && (orig_node->router)) {
@@ -1023,9 +1029,11 @@ int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if)
1023 1029
1024 /* get routing information */ 1030 /* get routing information */
1025 spin_lock_bh(&bat_priv->orig_hash_lock); 1031 spin_lock_bh(&bat_priv->orig_hash_lock);
1032 rcu_read_lock();
1026 orig_node = ((struct orig_node *) 1033 orig_node = ((struct orig_node *)
1027 hash_find(bat_priv->orig_hash, compare_orig, choose_orig, 1034 hash_find(bat_priv->orig_hash, compare_orig, choose_orig,
1028 icmp_packet->dst)); 1035 icmp_packet->dst));
1036 rcu_read_unlock();
1029 1037
1030 if ((orig_node) && (orig_node->router)) { 1038 if ((orig_node) && (orig_node->router)) {
1031 1039
@@ -1094,9 +1102,11 @@ struct neigh_node *find_router(struct bat_priv *bat_priv,
1094 router_orig->orig, ETH_ALEN) == 0) { 1102 router_orig->orig, ETH_ALEN) == 0) {
1095 primary_orig_node = router_orig; 1103 primary_orig_node = router_orig;
1096 } else { 1104 } else {
1105 rcu_read_lock();
1097 primary_orig_node = hash_find(bat_priv->orig_hash, compare_orig, 1106 primary_orig_node = hash_find(bat_priv->orig_hash, compare_orig,
1098 choose_orig, 1107 choose_orig,
1099 router_orig->primary_addr); 1108 router_orig->primary_addr);
1109 rcu_read_unlock();
1100 1110
1101 if (!primary_orig_node) 1111 if (!primary_orig_node)
1102 return orig_node->router; 1112 return orig_node->router;
@@ -1199,9 +1209,11 @@ int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if,
1199 1209
1200 /* get routing information */ 1210 /* get routing information */
1201 spin_lock_bh(&bat_priv->orig_hash_lock); 1211 spin_lock_bh(&bat_priv->orig_hash_lock);
1212 rcu_read_lock();
1202 orig_node = ((struct orig_node *) 1213 orig_node = ((struct orig_node *)
1203 hash_find(bat_priv->orig_hash, compare_orig, choose_orig, 1214 hash_find(bat_priv->orig_hash, compare_orig, choose_orig,
1204 unicast_packet->dest)); 1215 unicast_packet->dest));
1216 rcu_read_unlock();
1205 1217
1206 router = find_router(bat_priv, orig_node, recv_if); 1218 router = find_router(bat_priv, orig_node, recv_if);
1207 1219
@@ -1345,9 +1357,11 @@ int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if)
1345 return NET_RX_DROP; 1357 return NET_RX_DROP;
1346 1358
1347 spin_lock_bh(&bat_priv->orig_hash_lock); 1359 spin_lock_bh(&bat_priv->orig_hash_lock);
1360 rcu_read_lock();
1348 orig_node = ((struct orig_node *) 1361 orig_node = ((struct orig_node *)
1349 hash_find(bat_priv->orig_hash, compare_orig, choose_orig, 1362 hash_find(bat_priv->orig_hash, compare_orig, choose_orig,
1350 bcast_packet->orig)); 1363 bcast_packet->orig));
1364 rcu_read_unlock();
1351 1365
1352 if (!orig_node) { 1366 if (!orig_node) {
1353 spin_unlock_bh(&bat_priv->orig_hash_lock); 1367 spin_unlock_bh(&bat_priv->orig_hash_lock);
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 7fb6726ccbdd..b25e4b328dcb 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -60,10 +60,12 @@ void hna_local_add(struct net_device *soft_iface, uint8_t *addr)
60 int required_bytes; 60 int required_bytes;
61 61
62 spin_lock_bh(&bat_priv->hna_lhash_lock); 62 spin_lock_bh(&bat_priv->hna_lhash_lock);
63 rcu_read_lock();
63 hna_local_entry = 64 hna_local_entry =
64 ((struct hna_local_entry *)hash_find(bat_priv->hna_local_hash, 65 ((struct hna_local_entry *)hash_find(bat_priv->hna_local_hash,
65 compare_orig, choose_orig, 66 compare_orig, choose_orig,
66 addr)); 67 addr));
68 rcu_read_unlock();
67 spin_unlock_bh(&bat_priv->hna_lhash_lock); 69 spin_unlock_bh(&bat_priv->hna_lhash_lock);
68 70
69 if (hna_local_entry) { 71 if (hna_local_entry) {
@@ -116,9 +118,11 @@ void hna_local_add(struct net_device *soft_iface, uint8_t *addr)
116 /* remove address from global hash if present */ 118 /* remove address from global hash if present */
117 spin_lock_bh(&bat_priv->hna_ghash_lock); 119 spin_lock_bh(&bat_priv->hna_ghash_lock);
118 120
121 rcu_read_lock();
119 hna_global_entry = ((struct hna_global_entry *) 122 hna_global_entry = ((struct hna_global_entry *)
120 hash_find(bat_priv->hna_global_hash, 123 hash_find(bat_priv->hna_global_hash,
121 compare_orig, choose_orig, addr)); 124 compare_orig, choose_orig, addr));
125 rcu_read_unlock();
122 126
123 if (hna_global_entry) 127 if (hna_global_entry)
124 _hna_global_del_orig(bat_priv, hna_global_entry, 128 _hna_global_del_orig(bat_priv, hna_global_entry,
@@ -252,9 +256,11 @@ void hna_local_remove(struct bat_priv *bat_priv,
252 256
253 spin_lock_bh(&bat_priv->hna_lhash_lock); 257 spin_lock_bh(&bat_priv->hna_lhash_lock);
254 258
259 rcu_read_lock();
255 hna_local_entry = (struct hna_local_entry *) 260 hna_local_entry = (struct hna_local_entry *)
256 hash_find(bat_priv->hna_local_hash, compare_orig, choose_orig, 261 hash_find(bat_priv->hna_local_hash, compare_orig, choose_orig,
257 addr); 262 addr);
263 rcu_read_unlock();
258 264
259 if (hna_local_entry) 265 if (hna_local_entry)
260 hna_local_del(bat_priv, hna_local_entry, message); 266 hna_local_del(bat_priv, hna_local_entry, message);
@@ -334,9 +340,11 @@ void hna_global_add_orig(struct bat_priv *bat_priv,
334 spin_lock_bh(&bat_priv->hna_ghash_lock); 340 spin_lock_bh(&bat_priv->hna_ghash_lock);
335 341
336 hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN); 342 hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN);
343 rcu_read_lock();
337 hna_global_entry = (struct hna_global_entry *) 344 hna_global_entry = (struct hna_global_entry *)
338 hash_find(bat_priv->hna_global_hash, compare_orig, 345 hash_find(bat_priv->hna_global_hash, compare_orig,
339 choose_orig, hna_ptr); 346 choose_orig, hna_ptr);
347 rcu_read_unlock();
340 348
341 if (!hna_global_entry) { 349 if (!hna_global_entry) {
342 spin_unlock_bh(&bat_priv->hna_ghash_lock); 350 spin_unlock_bh(&bat_priv->hna_ghash_lock);
@@ -368,9 +376,11 @@ void hna_global_add_orig(struct bat_priv *bat_priv,
368 spin_lock_bh(&bat_priv->hna_lhash_lock); 376 spin_lock_bh(&bat_priv->hna_lhash_lock);
369 377
370 hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN); 378 hna_ptr = hna_buff + (hna_buff_count * ETH_ALEN);
379 rcu_read_lock();
371 hna_local_entry = (struct hna_local_entry *) 380 hna_local_entry = (struct hna_local_entry *)
372 hash_find(bat_priv->hna_local_hash, compare_orig, 381 hash_find(bat_priv->hna_local_hash, compare_orig,
373 choose_orig, hna_ptr); 382 choose_orig, hna_ptr);
383 rcu_read_unlock();
374 384
375 if (hna_local_entry) 385 if (hna_local_entry)
376 hna_local_del(bat_priv, hna_local_entry, 386 hna_local_del(bat_priv, hna_local_entry,
@@ -483,9 +493,11 @@ void hna_global_del_orig(struct bat_priv *bat_priv,
483 493
484 while ((hna_buff_count + 1) * ETH_ALEN <= orig_node->hna_buff_len) { 494 while ((hna_buff_count + 1) * ETH_ALEN <= orig_node->hna_buff_len) {
485 hna_ptr = orig_node->hna_buff + (hna_buff_count * ETH_ALEN); 495 hna_ptr = orig_node->hna_buff + (hna_buff_count * ETH_ALEN);
496 rcu_read_lock();
486 hna_global_entry = (struct hna_global_entry *) 497 hna_global_entry = (struct hna_global_entry *)
487 hash_find(bat_priv->hna_global_hash, compare_orig, 498 hash_find(bat_priv->hna_global_hash, compare_orig,
488 choose_orig, hna_ptr); 499 choose_orig, hna_ptr);
500 rcu_read_unlock();
489 501
490 if ((hna_global_entry) && 502 if ((hna_global_entry) &&
491 (hna_global_entry->orig_node == orig_node)) 503 (hna_global_entry->orig_node == orig_node))
@@ -521,9 +533,11 @@ struct orig_node *transtable_search(struct bat_priv *bat_priv, uint8_t *addr)
521 struct hna_global_entry *hna_global_entry; 533 struct hna_global_entry *hna_global_entry;
522 534
523 spin_lock_bh(&bat_priv->hna_ghash_lock); 535 spin_lock_bh(&bat_priv->hna_ghash_lock);
536 rcu_read_lock();
524 hna_global_entry = (struct hna_global_entry *) 537 hna_global_entry = (struct hna_global_entry *)
525 hash_find(bat_priv->hna_global_hash, 538 hash_find(bat_priv->hna_global_hash,
526 compare_orig, choose_orig, addr); 539 compare_orig, choose_orig, addr);
540 rcu_read_unlock();
527 spin_unlock_bh(&bat_priv->hna_ghash_lock); 541 spin_unlock_bh(&bat_priv->hna_ghash_lock);
528 542
529 if (!hna_global_entry) 543 if (!hna_global_entry)
diff --git a/net/batman-adv/unicast.c b/net/batman-adv/unicast.c
index 1b5e761d8823..4687027f1495 100644
--- a/net/batman-adv/unicast.c
+++ b/net/batman-adv/unicast.c
@@ -179,9 +179,11 @@ int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
179 179
180 *new_skb = NULL; 180 *new_skb = NULL;
181 spin_lock_bh(&bat_priv->orig_hash_lock); 181 spin_lock_bh(&bat_priv->orig_hash_lock);
182 rcu_read_lock();
182 orig_node = ((struct orig_node *) 183 orig_node = ((struct orig_node *)
183 hash_find(bat_priv->orig_hash, compare_orig, choose_orig, 184 hash_find(bat_priv->orig_hash, compare_orig, choose_orig,
184 unicast_packet->orig)); 185 unicast_packet->orig));
186 rcu_read_unlock();
185 187
186 if (!orig_node) { 188 if (!orig_node) {
187 pr_debug("couldn't find originator in orig_hash\n"); 189 pr_debug("couldn't find originator in orig_hash\n");
diff --git a/net/batman-adv/vis.c b/net/batman-adv/vis.c
index a77b773b0868..8092eadcbdee 100644
--- a/net/batman-adv/vis.c
+++ b/net/batman-adv/vis.c
@@ -380,8 +380,10 @@ static struct vis_info *add_packet(struct bat_priv *bat_priv,
380 sizeof(struct vis_packet)); 380 sizeof(struct vis_packet));
381 381
382 memcpy(search_packet->vis_orig, vis_packet->vis_orig, ETH_ALEN); 382 memcpy(search_packet->vis_orig, vis_packet->vis_orig, ETH_ALEN);
383 rcu_read_lock();
383 old_info = hash_find(bat_priv->vis_hash, vis_info_cmp, vis_info_choose, 384 old_info = hash_find(bat_priv->vis_hash, vis_info_cmp, vis_info_choose,
384 &search_elem); 385 &search_elem);
386 rcu_read_unlock();
385 kfree_skb(search_elem.skb_packet); 387 kfree_skb(search_elem.skb_packet);
386 388
387 if (old_info) { 389 if (old_info) {
@@ -540,7 +542,8 @@ static int find_best_vis_server(struct bat_priv *bat_priv,
540 for (i = 0; i < hash->size; i++) { 542 for (i = 0; i < hash->size; i++) {
541 head = &hash->table[i]; 543 head = &hash->table[i];
542 544
543 hlist_for_each_entry(bucket, walk, head, hlist) { 545 rcu_read_lock();
546 hlist_for_each_entry_rcu(bucket, walk, head, hlist) {
544 orig_node = bucket->data; 547 orig_node = bucket->data;
545 if ((orig_node) && (orig_node->router) && 548 if ((orig_node) && (orig_node->router) &&
546 (orig_node->flags & VIS_SERVER) && 549 (orig_node->flags & VIS_SERVER) &&
@@ -550,6 +553,7 @@ static int find_best_vis_server(struct bat_priv *bat_priv,
550 ETH_ALEN); 553 ETH_ALEN);
551 } 554 }
552 } 555 }
556 rcu_read_unlock();
553 } 557 }
554 558
555 return best_tq; 559 return best_tq;
@@ -605,7 +609,8 @@ static int generate_vis_packet(struct bat_priv *bat_priv)
605 for (i = 0; i < hash->size; i++) { 609 for (i = 0; i < hash->size; i++) {
606 head = &hash->table[i]; 610 head = &hash->table[i];
607 611
608 hlist_for_each_entry(bucket, walk, head, hlist) { 612 rcu_read_lock();
613 hlist_for_each_entry_rcu(bucket, walk, head, hlist) {
609 orig_node = bucket->data; 614 orig_node = bucket->data;
610 neigh_node = orig_node->router; 615 neigh_node = orig_node->router;
611 616
@@ -632,10 +637,12 @@ static int generate_vis_packet(struct bat_priv *bat_priv)
632 packet->entries++; 637 packet->entries++;
633 638
634 if (vis_packet_full(info)) { 639 if (vis_packet_full(info)) {
640 rcu_read_unlock();
635 spin_unlock_bh(&bat_priv->orig_hash_lock); 641 spin_unlock_bh(&bat_priv->orig_hash_lock);
636 return 0; 642 return 0;
637 } 643 }
638 } 644 }
645 rcu_read_unlock();
639 } 646 }
640 647
641 spin_unlock_bh(&bat_priv->orig_hash_lock); 648 spin_unlock_bh(&bat_priv->orig_hash_lock);
@@ -721,7 +728,8 @@ static void broadcast_vis_packet(struct bat_priv *bat_priv,
721 for (i = 0; i < hash->size; i++) { 728 for (i = 0; i < hash->size; i++) {
722 head = &hash->table[i]; 729 head = &hash->table[i];
723 730
724 hlist_for_each_entry(bucket, walk, head, hlist) { 731 rcu_read_lock();
732 hlist_for_each_entry_rcu(bucket, walk, head, hlist) {
725 orig_node = bucket->data; 733 orig_node = bucket->data;
726 734
727 /* if it's a vis server and reachable, send it. */ 735 /* if it's a vis server and reachable, send it. */
@@ -746,7 +754,7 @@ static void broadcast_vis_packet(struct bat_priv *bat_priv,
746 754
747 spin_lock_bh(&bat_priv->orig_hash_lock); 755 spin_lock_bh(&bat_priv->orig_hash_lock);
748 } 756 }
749 757 rcu_read_unlock();
750 } 758 }
751 759
752 spin_unlock_bh(&bat_priv->orig_hash_lock); 760 spin_unlock_bh(&bat_priv->orig_hash_lock);
@@ -763,9 +771,11 @@ static void unicast_vis_packet(struct bat_priv *bat_priv,
763 771
764 spin_lock_bh(&bat_priv->orig_hash_lock); 772 spin_lock_bh(&bat_priv->orig_hash_lock);
765 packet = (struct vis_packet *)info->skb_packet->data; 773 packet = (struct vis_packet *)info->skb_packet->data;
774 rcu_read_lock();
766 orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, 775 orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash,
767 compare_orig, choose_orig, 776 compare_orig, choose_orig,
768 packet->target_orig)); 777 packet->target_orig));
778 rcu_read_unlock();
769 779
770 if ((!orig_node) || (!orig_node->router)) 780 if ((!orig_node) || (!orig_node->router))
771 goto out; 781 goto out;