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/originator.c | |
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/originator.c')
-rw-r--r-- | net/batman-adv/originator.c | 35 |
1 files changed, 28 insertions, 7 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++; |