diff options
author | Marek Lindner <lindner_marek@yahoo.de> | 2010-12-12 16:57:12 -0500 |
---|---|---|
committer | Marek Lindner <lindner_marek@yahoo.de> | 2011-03-05 06:49:54 -0500 |
commit | f987ed6ebd991009cd9f6190ce319e8b50d6be1f (patch) | |
tree | 08fd4c5edc6ee74407ec901cef960978946f716f /net/batman-adv | |
parent | 9591a79f280ede740e44aeb8ad93a6692d482dce (diff) |
batman-adv: protect neighbor list with rcu locks
Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
Diffstat (limited to 'net/batman-adv')
-rw-r--r-- | net/batman-adv/originator.c | 35 | ||||
-rw-r--r-- | net/batman-adv/routing.c | 41 | ||||
-rw-r--r-- | net/batman-adv/types.h | 2 |
3 files changed, 57 insertions, 21 deletions
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 68b04e77f4d7..6cb9af3f89e5 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c | |||
@@ -67,6 +67,14 @@ void neigh_node_free_ref(struct kref *refcount) | |||
67 | kfree(neigh_node); | 67 | kfree(neigh_node); |
68 | } | 68 | } |
69 | 69 | ||
70 | static void neigh_node_free_rcu(struct rcu_head *rcu) | ||
71 | { | ||
72 | struct neigh_node *neigh_node; | ||
73 | |||
74 | neigh_node = container_of(rcu, struct neigh_node, rcu); | ||
75 | kref_put(&neigh_node->refcount, neigh_node_free_ref); | ||
76 | } | ||
77 | |||
70 | struct neigh_node *create_neighbor(struct orig_node *orig_node, | 78 | struct neigh_node *create_neighbor(struct orig_node *orig_node, |
71 | struct orig_node *orig_neigh_node, | 79 | struct orig_node *orig_neigh_node, |
72 | uint8_t *neigh, | 80 | uint8_t *neigh, |
@@ -89,7 +97,9 @@ struct neigh_node *create_neighbor(struct orig_node *orig_node, | |||
89 | neigh_node->if_incoming = if_incoming; | 97 | neigh_node->if_incoming = if_incoming; |
90 | kref_init(&neigh_node->refcount); | 98 | kref_init(&neigh_node->refcount); |
91 | 99 | ||
92 | hlist_add_head(&neigh_node->list, &orig_node->neigh_list); | 100 | spin_lock_bh(&orig_node->neigh_list_lock); |
101 | hlist_add_head_rcu(&neigh_node->list, &orig_node->neigh_list); | ||
102 | spin_unlock_bh(&orig_node->neigh_list_lock); | ||
93 | return neigh_node; | 103 | return neigh_node; |
94 | } | 104 | } |
95 | 105 | ||
@@ -100,13 +110,17 @@ static void free_orig_node(void *data, void *arg) | |||
100 | struct orig_node *orig_node = (struct orig_node *)data; | 110 | struct orig_node *orig_node = (struct orig_node *)data; |
101 | struct bat_priv *bat_priv = (struct bat_priv *)arg; | 111 | struct bat_priv *bat_priv = (struct bat_priv *)arg; |
102 | 112 | ||
113 | spin_lock_bh(&orig_node->neigh_list_lock); | ||
114 | |||
103 | /* for all neighbors towards this originator ... */ | 115 | /* for all neighbors towards this originator ... */ |
104 | hlist_for_each_entry_safe(neigh_node, node, node_tmp, | 116 | hlist_for_each_entry_safe(neigh_node, node, node_tmp, |
105 | &orig_node->neigh_list, list) { | 117 | &orig_node->neigh_list, list) { |
106 | hlist_del(&neigh_node->list); | 118 | hlist_del_rcu(&neigh_node->list); |
107 | kref_put(&neigh_node->refcount, neigh_node_free_ref); | 119 | call_rcu(&neigh_node->rcu, neigh_node_free_rcu); |
108 | } | 120 | } |
109 | 121 | ||
122 | spin_unlock_bh(&orig_node->neigh_list_lock); | ||
123 | |||
110 | frag_list_free(&orig_node->frag_list); | 124 | frag_list_free(&orig_node->frag_list); |
111 | hna_global_del_orig(bat_priv, orig_node, "originator timed out"); | 125 | hna_global_del_orig(bat_priv, orig_node, "originator timed out"); |
112 | 126 | ||
@@ -151,6 +165,7 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr) | |||
151 | return NULL; | 165 | return NULL; |
152 | 166 | ||
153 | INIT_HLIST_HEAD(&orig_node->neigh_list); | 167 | INIT_HLIST_HEAD(&orig_node->neigh_list); |
168 | spin_lock_init(&orig_node->neigh_list_lock); | ||
154 | 169 | ||
155 | memcpy(orig_node->orig, addr, ETH_ALEN); | 170 | memcpy(orig_node->orig, addr, ETH_ALEN); |
156 | orig_node->router = NULL; | 171 | orig_node->router = NULL; |
@@ -200,6 +215,8 @@ static bool purge_orig_neighbors(struct bat_priv *bat_priv, | |||
200 | 215 | ||
201 | *best_neigh_node = NULL; | 216 | *best_neigh_node = NULL; |
202 | 217 | ||
218 | spin_lock_bh(&orig_node->neigh_list_lock); | ||
219 | |||
203 | /* for all neighbors towards this originator ... */ | 220 | /* for all neighbors towards this originator ... */ |
204 | hlist_for_each_entry_safe(neigh_node, node, node_tmp, | 221 | hlist_for_each_entry_safe(neigh_node, node, node_tmp, |
205 | &orig_node->neigh_list, list) { | 222 | &orig_node->neigh_list, list) { |
@@ -225,14 +242,16 @@ static bool purge_orig_neighbors(struct bat_priv *bat_priv, | |||
225 | 242 | ||
226 | neigh_purged = true; | 243 | neigh_purged = true; |
227 | 244 | ||
228 | hlist_del(&neigh_node->list); | 245 | hlist_del_rcu(&neigh_node->list); |
229 | kref_put(&neigh_node->refcount, neigh_node_free_ref); | 246 | call_rcu(&neigh_node->rcu, neigh_node_free_rcu); |
230 | } else { | 247 | } else { |
231 | if ((!*best_neigh_node) || | 248 | if ((!*best_neigh_node) || |
232 | (neigh_node->tq_avg > (*best_neigh_node)->tq_avg)) | 249 | (neigh_node->tq_avg > (*best_neigh_node)->tq_avg)) |
233 | *best_neigh_node = neigh_node; | 250 | *best_neigh_node = neigh_node; |
234 | } | 251 | } |
235 | } | 252 | } |
253 | |||
254 | spin_unlock_bh(&orig_node->neigh_list_lock); | ||
236 | return neigh_purged; | 255 | return neigh_purged; |
237 | } | 256 | } |
238 | 257 | ||
@@ -384,11 +403,13 @@ int orig_seq_print_text(struct seq_file *seq, void *offset) | |||
384 | neigh_node->addr, | 403 | neigh_node->addr, |
385 | neigh_node->if_incoming->net_dev->name); | 404 | neigh_node->if_incoming->net_dev->name); |
386 | 405 | ||
387 | hlist_for_each_entry(neigh_node, node, | 406 | rcu_read_lock(); |
388 | &orig_node->neigh_list, list) { | 407 | hlist_for_each_entry_rcu(neigh_node, node, |
408 | &orig_node->neigh_list, list) { | ||
389 | seq_printf(seq, " %pM (%3i)", neigh_node->addr, | 409 | seq_printf(seq, " %pM (%3i)", neigh_node->addr, |
390 | neigh_node->tq_avg); | 410 | neigh_node->tq_avg); |
391 | } | 411 | } |
412 | rcu_read_unlock(); | ||
392 | 413 | ||
393 | seq_printf(seq, "\n"); | 414 | seq_printf(seq, "\n"); |
394 | batman_count++; | 415 | batman_count++; |
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index e8379ba25e95..97f321615686 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c | |||
@@ -153,14 +153,16 @@ static int is_bidirectional_neigh(struct orig_node *orig_node, | |||
153 | unsigned char total_count; | 153 | unsigned char total_count; |
154 | 154 | ||
155 | if (orig_node == orig_neigh_node) { | 155 | if (orig_node == orig_neigh_node) { |
156 | hlist_for_each_entry(tmp_neigh_node, node, | 156 | rcu_read_lock(); |
157 | &orig_node->neigh_list, list) { | 157 | hlist_for_each_entry_rcu(tmp_neigh_node, node, |
158 | &orig_node->neigh_list, list) { | ||
158 | 159 | ||
159 | if (compare_orig(tmp_neigh_node->addr, | 160 | if (compare_orig(tmp_neigh_node->addr, |
160 | orig_neigh_node->orig) && | 161 | orig_neigh_node->orig) && |
161 | (tmp_neigh_node->if_incoming == if_incoming)) | 162 | (tmp_neigh_node->if_incoming == if_incoming)) |
162 | neigh_node = tmp_neigh_node; | 163 | neigh_node = tmp_neigh_node; |
163 | } | 164 | } |
165 | rcu_read_unlock(); | ||
164 | 166 | ||
165 | if (!neigh_node) | 167 | if (!neigh_node) |
166 | neigh_node = create_neighbor(orig_node, | 168 | neigh_node = create_neighbor(orig_node, |
@@ -174,14 +176,16 @@ static int is_bidirectional_neigh(struct orig_node *orig_node, | |||
174 | neigh_node->last_valid = jiffies; | 176 | neigh_node->last_valid = jiffies; |
175 | } else { | 177 | } else { |
176 | /* find packet count of corresponding one hop neighbor */ | 178 | /* find packet count of corresponding one hop neighbor */ |
177 | hlist_for_each_entry(tmp_neigh_node, node, | 179 | rcu_read_lock(); |
178 | &orig_neigh_node->neigh_list, list) { | 180 | hlist_for_each_entry_rcu(tmp_neigh_node, node, |
181 | &orig_neigh_node->neigh_list, list) { | ||
179 | 182 | ||
180 | if (compare_orig(tmp_neigh_node->addr, | 183 | if (compare_orig(tmp_neigh_node->addr, |
181 | orig_neigh_node->orig) && | 184 | orig_neigh_node->orig) && |
182 | (tmp_neigh_node->if_incoming == if_incoming)) | 185 | (tmp_neigh_node->if_incoming == if_incoming)) |
183 | neigh_node = tmp_neigh_node; | 186 | neigh_node = tmp_neigh_node; |
184 | } | 187 | } |
188 | rcu_read_unlock(); | ||
185 | 189 | ||
186 | if (!neigh_node) | 190 | if (!neigh_node) |
187 | neigh_node = create_neighbor(orig_neigh_node, | 191 | neigh_node = create_neighbor(orig_neigh_node, |
@@ -266,8 +270,9 @@ static void update_orig(struct bat_priv *bat_priv, | |||
266 | bat_dbg(DBG_BATMAN, bat_priv, "update_originator(): " | 270 | bat_dbg(DBG_BATMAN, bat_priv, "update_originator(): " |
267 | "Searching and updating originator entry of received packet\n"); | 271 | "Searching and updating originator entry of received packet\n"); |
268 | 272 | ||
269 | hlist_for_each_entry(tmp_neigh_node, node, | 273 | rcu_read_lock(); |
270 | &orig_node->neigh_list, list) { | 274 | hlist_for_each_entry_rcu(tmp_neigh_node, node, |
275 | &orig_node->neigh_list, list) { | ||
271 | if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) && | 276 | if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) && |
272 | (tmp_neigh_node->if_incoming == if_incoming)) { | 277 | (tmp_neigh_node->if_incoming == if_incoming)) { |
273 | neigh_node = tmp_neigh_node; | 278 | neigh_node = tmp_neigh_node; |
@@ -282,6 +287,7 @@ static void update_orig(struct bat_priv *bat_priv, | |||
282 | tmp_neigh_node->tq_avg = | 287 | tmp_neigh_node->tq_avg = |
283 | ring_buffer_avg(tmp_neigh_node->tq_recv); | 288 | ring_buffer_avg(tmp_neigh_node->tq_recv); |
284 | } | 289 | } |
290 | rcu_read_unlock(); | ||
285 | 291 | ||
286 | if (!neigh_node) { | 292 | if (!neigh_node) { |
287 | struct orig_node *orig_tmp; | 293 | struct orig_node *orig_tmp; |
@@ -410,8 +416,9 @@ static char count_real_packets(struct ethhdr *ethhdr, | |||
410 | &orig_node->batman_seqno_reset)) | 416 | &orig_node->batman_seqno_reset)) |
411 | return -1; | 417 | return -1; |
412 | 418 | ||
413 | hlist_for_each_entry(tmp_neigh_node, node, | 419 | rcu_read_lock(); |
414 | &orig_node->neigh_list, list) { | 420 | hlist_for_each_entry_rcu(tmp_neigh_node, node, |
421 | &orig_node->neigh_list, list) { | ||
415 | 422 | ||
416 | is_duplicate |= get_bit_status(tmp_neigh_node->real_bits, | 423 | is_duplicate |= get_bit_status(tmp_neigh_node->real_bits, |
417 | orig_node->last_real_seqno, | 424 | orig_node->last_real_seqno, |
@@ -431,6 +438,7 @@ static char count_real_packets(struct ethhdr *ethhdr, | |||
431 | tmp_neigh_node->real_packet_count = | 438 | tmp_neigh_node->real_packet_count = |
432 | bit_packet_count(tmp_neigh_node->real_bits); | 439 | bit_packet_count(tmp_neigh_node->real_bits); |
433 | } | 440 | } |
441 | rcu_read_unlock(); | ||
434 | 442 | ||
435 | if (need_update) { | 443 | if (need_update) { |
436 | bat_dbg(DBG_BATMAN, bat_priv, | 444 | bat_dbg(DBG_BATMAN, bat_priv, |
@@ -481,15 +489,19 @@ void update_bonding_candidates(struct orig_node *orig_node) | |||
481 | * as "bonding partner" */ | 489 | * as "bonding partner" */ |
482 | 490 | ||
483 | /* first, zero the list */ | 491 | /* first, zero the list */ |
484 | hlist_for_each_entry(tmp_neigh_node, node, | 492 | rcu_read_lock(); |
485 | &orig_node->neigh_list, list) { | 493 | hlist_for_each_entry_rcu(tmp_neigh_node, node, |
494 | &orig_node->neigh_list, list) { | ||
486 | tmp_neigh_node->next_bond_candidate = NULL; | 495 | tmp_neigh_node->next_bond_candidate = NULL; |
487 | } | 496 | } |
497 | rcu_read_unlock(); | ||
488 | 498 | ||
489 | first_candidate = NULL; | 499 | first_candidate = NULL; |
490 | last_candidate = NULL; | 500 | last_candidate = NULL; |
491 | hlist_for_each_entry(tmp_neigh_node, node, | 501 | |
492 | &orig_node->neigh_list, list) { | 502 | rcu_read_lock(); |
503 | hlist_for_each_entry_rcu(tmp_neigh_node, node, | ||
504 | &orig_node->neigh_list, list) { | ||
493 | 505 | ||
494 | /* only consider if it has the same primary address ... */ | 506 | /* only consider if it has the same primary address ... */ |
495 | if (memcmp(orig_node->orig, | 507 | if (memcmp(orig_node->orig, |
@@ -506,8 +518,8 @@ void update_bonding_candidates(struct orig_node *orig_node) | |||
506 | * select this candidate because of possible interference. */ | 518 | * select this candidate because of possible interference. */ |
507 | 519 | ||
508 | interference_candidate = 0; | 520 | interference_candidate = 0; |
509 | hlist_for_each_entry(tmp_neigh_node2, node2, | 521 | hlist_for_each_entry_rcu(tmp_neigh_node2, node2, |
510 | &orig_node->neigh_list, list) { | 522 | &orig_node->neigh_list, list) { |
511 | 523 | ||
512 | if (tmp_neigh_node2 == tmp_neigh_node) | 524 | if (tmp_neigh_node2 == tmp_neigh_node) |
513 | continue; | 525 | continue; |
@@ -541,6 +553,7 @@ void update_bonding_candidates(struct orig_node *orig_node) | |||
541 | 553 | ||
542 | candidates++; | 554 | candidates++; |
543 | } | 555 | } |
556 | rcu_read_unlock(); | ||
544 | 557 | ||
545 | if (candidates > 0) { | 558 | if (candidates > 0) { |
546 | first_candidate->next_bond_candidate = last_candidate; | 559 | first_candidate->next_bond_candidate = last_candidate; |
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 779c5c30bd04..d4fa727aece3 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h | |||
@@ -85,6 +85,7 @@ struct orig_node { | |||
85 | uint32_t last_bcast_seqno; | 85 | uint32_t last_bcast_seqno; |
86 | struct hlist_head neigh_list; | 86 | struct hlist_head neigh_list; |
87 | struct list_head frag_list; | 87 | struct list_head frag_list; |
88 | spinlock_t neigh_list_lock; /* protects neighbor list */ | ||
88 | unsigned long last_frag_packet; | 89 | unsigned long last_frag_packet; |
89 | struct { | 90 | struct { |
90 | uint8_t candidates; | 91 | uint8_t candidates; |
@@ -116,6 +117,7 @@ struct neigh_node { | |||
116 | unsigned long last_valid; | 117 | unsigned long last_valid; |
117 | unsigned long real_bits[NUM_WORDS]; | 118 | unsigned long real_bits[NUM_WORDS]; |
118 | struct kref refcount; | 119 | struct kref refcount; |
120 | struct rcu_head rcu; | ||
119 | struct orig_node *orig_node; | 121 | struct orig_node *orig_node; |
120 | struct batman_if *if_incoming; | 122 | struct batman_if *if_incoming; |
121 | }; | 123 | }; |