diff options
author | Linus Lüssing <linus.luessing@web.de> | 2011-03-14 18:43:37 -0400 |
---|---|---|
committer | Sven Eckelmann <sven@narfation.org> | 2011-04-17 15:11:01 -0400 |
commit | e1a5382f978b67b5cc36eec65e6046730ce07714 (patch) | |
tree | f7ca07cde3a49858d0cfa33e0189a659a1fcc95d /net/batman-adv/originator.c | |
parent | 57f0c07c4d0da8bcc23e21c330fe9c7c5cf776b5 (diff) |
batman-adv: Make orig_node->router an rcu protected pointer
The rcu protected macros rcu_dereference() and rcu_assign_pointer()
for the orig_node->router need to be used, as well as spin/rcu locking.
Otherwise we might end up using a router pointer pointing to already
freed memory.
Therefore this commit introduces the safe getter method
orig_node_get_router().
Signed-off-by: Linus Lüssing <linus.luessing@web.de>
Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Diffstat (limited to 'net/batman-adv/originator.c')
-rw-r--r-- | net/batman-adv/originator.c | 37 |
1 files changed, 28 insertions, 9 deletions
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 0b9133022d2d..b4cfe3686155 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c | |||
@@ -70,6 +70,21 @@ void neigh_node_free_ref(struct neigh_node *neigh_node) | |||
70 | call_rcu(&neigh_node->rcu, neigh_node_free_rcu); | 70 | call_rcu(&neigh_node->rcu, neigh_node_free_rcu); |
71 | } | 71 | } |
72 | 72 | ||
73 | /* increases the refcounter of a found router */ | ||
74 | struct neigh_node *orig_node_get_router(struct orig_node *orig_node) | ||
75 | { | ||
76 | struct neigh_node *router; | ||
77 | |||
78 | rcu_read_lock(); | ||
79 | router = rcu_dereference(orig_node->router); | ||
80 | |||
81 | if (router && !atomic_inc_not_zero(&router->refcount)) | ||
82 | router = NULL; | ||
83 | |||
84 | rcu_read_unlock(); | ||
85 | return router; | ||
86 | } | ||
87 | |||
73 | struct neigh_node *create_neighbor(struct orig_node *orig_node, | 88 | struct neigh_node *create_neighbor(struct orig_node *orig_node, |
74 | struct orig_node *orig_neigh_node, | 89 | struct orig_node *orig_neigh_node, |
75 | uint8_t *neigh, | 90 | uint8_t *neigh, |
@@ -390,7 +405,7 @@ int orig_seq_print_text(struct seq_file *seq, void *offset) | |||
390 | struct hlist_node *node, *node_tmp; | 405 | struct hlist_node *node, *node_tmp; |
391 | struct hlist_head *head; | 406 | struct hlist_head *head; |
392 | struct orig_node *orig_node; | 407 | struct orig_node *orig_node; |
393 | struct neigh_node *neigh_node; | 408 | struct neigh_node *neigh_node, *neigh_node_tmp; |
394 | int batman_count = 0; | 409 | int batman_count = 0; |
395 | int last_seen_secs; | 410 | int last_seen_secs; |
396 | int last_seen_msecs; | 411 | int last_seen_msecs; |
@@ -421,37 +436,41 @@ int orig_seq_print_text(struct seq_file *seq, void *offset) | |||
421 | 436 | ||
422 | rcu_read_lock(); | 437 | rcu_read_lock(); |
423 | hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) { | 438 | hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) { |
424 | if (!orig_node->router) | 439 | neigh_node = orig_node_get_router(orig_node); |
440 | if (!neigh_node) | ||
425 | continue; | 441 | continue; |
426 | 442 | ||
427 | if (orig_node->router->tq_avg == 0) | 443 | if (neigh_node->tq_avg == 0) |
428 | continue; | 444 | goto next; |
429 | 445 | ||
430 | last_seen_secs = jiffies_to_msecs(jiffies - | 446 | last_seen_secs = jiffies_to_msecs(jiffies - |
431 | orig_node->last_valid) / 1000; | 447 | orig_node->last_valid) / 1000; |
432 | last_seen_msecs = jiffies_to_msecs(jiffies - | 448 | last_seen_msecs = jiffies_to_msecs(jiffies - |
433 | orig_node->last_valid) % 1000; | 449 | orig_node->last_valid) % 1000; |
434 | 450 | ||
435 | neigh_node = orig_node->router; | ||
436 | seq_printf(seq, "%pM %4i.%03is (%3i) %pM [%10s]:", | 451 | seq_printf(seq, "%pM %4i.%03is (%3i) %pM [%10s]:", |
437 | orig_node->orig, last_seen_secs, | 452 | orig_node->orig, last_seen_secs, |
438 | last_seen_msecs, neigh_node->tq_avg, | 453 | last_seen_msecs, neigh_node->tq_avg, |
439 | neigh_node->addr, | 454 | neigh_node->addr, |
440 | neigh_node->if_incoming->net_dev->name); | 455 | neigh_node->if_incoming->net_dev->name); |
441 | 456 | ||
442 | hlist_for_each_entry_rcu(neigh_node, node_tmp, | 457 | hlist_for_each_entry_rcu(neigh_node_tmp, node_tmp, |
443 | &orig_node->neigh_list, list) { | 458 | &orig_node->neigh_list, list) { |
444 | seq_printf(seq, " %pM (%3i)", neigh_node->addr, | 459 | seq_printf(seq, " %pM (%3i)", |
445 | neigh_node->tq_avg); | 460 | neigh_node_tmp->addr, |
461 | neigh_node_tmp->tq_avg); | ||
446 | } | 462 | } |
447 | 463 | ||
448 | seq_printf(seq, "\n"); | 464 | seq_printf(seq, "\n"); |
449 | batman_count++; | 465 | batman_count++; |
466 | |||
467 | next: | ||
468 | neigh_node_free_ref(neigh_node); | ||
450 | } | 469 | } |
451 | rcu_read_unlock(); | 470 | rcu_read_unlock(); |
452 | } | 471 | } |
453 | 472 | ||
454 | if ((batman_count == 0)) | 473 | if (batman_count == 0) |
455 | seq_printf(seq, "No batman nodes in range ...\n"); | 474 | seq_printf(seq, "No batman nodes in range ...\n"); |
456 | 475 | ||
457 | return 0; | 476 | return 0; |