diff options
Diffstat (limited to 'net/batman-adv/originator.c')
-rw-r--r-- | net/batman-adv/originator.c | 27 |
1 files changed, 20 insertions, 7 deletions
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 | } |