diff options
author | Linus Lüssing <linus.luessing@web.de> | 2011-03-14 22:43:37 +0000 |
---|---|---|
committer | Sven Eckelmann <sven@narfation.org> | 2011-04-17 21:11:01 +0200 |
commit | e1a5382f978b67b5cc36eec65e6046730ce07714 (patch) | |
tree | f7ca07cde3a49858d0cfa33e0189a659a1fcc95d /net/batman-adv/originator.c | |
parent | 57f0c07c4d0da8bcc23e21c330fe9c7c5cf776b5 (diff) | |
download | lwn-e1a5382f978b67b5cc36eec65e6046730ce07714.tar.gz lwn-e1a5382f978b67b5cc36eec65e6046730ce07714.zip |
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) call_rcu(&neigh_node->rcu, neigh_node_free_rcu); } +/* increases the refcounter of a found router */ +struct neigh_node *orig_node_get_router(struct orig_node *orig_node) +{ + struct neigh_node *router; + + rcu_read_lock(); + router = rcu_dereference(orig_node->router); + + if (router && !atomic_inc_not_zero(&router->refcount)) + router = NULL; + + rcu_read_unlock(); + return router; +} + struct neigh_node *create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node, uint8_t *neigh, @@ -390,7 +405,7 @@ int orig_seq_print_text(struct seq_file *seq, void *offset) struct hlist_node *node, *node_tmp; struct hlist_head *head; struct orig_node *orig_node; - struct neigh_node *neigh_node; + struct neigh_node *neigh_node, *neigh_node_tmp; int batman_count = 0; int last_seen_secs; int last_seen_msecs; @@ -421,37 +436,41 @@ int orig_seq_print_text(struct seq_file *seq, void *offset) rcu_read_lock(); hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) { - if (!orig_node->router) + neigh_node = orig_node_get_router(orig_node); + if (!neigh_node) continue; - if (orig_node->router->tq_avg == 0) - continue; + if (neigh_node->tq_avg == 0) + goto next; last_seen_secs = jiffies_to_msecs(jiffies - orig_node->last_valid) / 1000; last_seen_msecs = jiffies_to_msecs(jiffies - orig_node->last_valid) % 1000; - neigh_node = orig_node->router; seq_printf(seq, "%pM %4i.%03is (%3i) %pM [%10s]:", orig_node->orig, last_seen_secs, last_seen_msecs, neigh_node->tq_avg, neigh_node->addr, neigh_node->if_incoming->net_dev->name); - hlist_for_each_entry_rcu(neigh_node, node_tmp, + hlist_for_each_entry_rcu(neigh_node_tmp, node_tmp, &orig_node->neigh_list, list) { - seq_printf(seq, " %pM (%3i)", neigh_node->addr, - neigh_node->tq_avg); + seq_printf(seq, " %pM (%3i)", + neigh_node_tmp->addr, + neigh_node_tmp->tq_avg); } seq_printf(seq, "\n"); batman_count++; + +next: + neigh_node_free_ref(neigh_node); } rcu_read_unlock(); } - if ((batman_count == 0)) + if (batman_count == 0) seq_printf(seq, "No batman nodes in range ...\n"); return 0; |