diff options
author | Marek Lindner <lindner_marek@yahoo.de> | 2011-01-19 15:01:40 -0500 |
---|---|---|
committer | Marek Lindner <lindner_marek@yahoo.de> | 2011-03-05 06:49:58 -0500 |
commit | fb778ea173fcd58b8fc3d75c674f07fab187b55f (patch) | |
tree | b14cfc99b7ca61ddcb49cc56c9a8e2822675debc | |
parent | a775eb847ae66211577d4fd2c46749b77c9993c9 (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.c | 34 | ||||
-rw-r--r-- | net/batman-adv/hash.h | 73 | ||||
-rw-r--r-- | net/batman-adv/icmp_socket.c | 2 | ||||
-rw-r--r-- | net/batman-adv/originator.c | 27 | ||||
-rw-r--r-- | net/batman-adv/routing.c | 16 | ||||
-rw-r--r-- | net/batman-adv/translation-table.c | 14 | ||||
-rw-r--r-- | net/batman-adv/unicast.c | 2 | ||||
-rw-r--r-- | net/batman-adv/vis.c | 18 |
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. */ |
35 | void hash_destroy(struct hashtable_t *hash) | 37 | void 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 | |||
65 | free_table: | ||
66 | kfree(hash->table); | ||
67 | free_hash: | ||
68 | kfree(hash); | ||
69 | return NULL; | ||
70 | } | ||
71 | |||
72 | void 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 *); | |||
39 | struct element_t { | 39 | struct 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 | ||
44 | struct hashtable_t { | 45 | struct 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. */ |
53 | void hash_destroy(struct hashtable_t *hash); | 55 | void hash_destroy(struct hashtable_t *hash); |
54 | 56 | ||
57 | void 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 | |||
127 | err_unlock: | ||
128 | rcu_read_unlock(); | ||
129 | err: | ||
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 | **/ | ||
147 | static inline void *hash_find(struct hashtable_t *hash, | 170 | static 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 | ||
490 | err: | 499 | err: |
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 | ||
597 | err: | 609 | err: |
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; |