aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mesh_pathtbl.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2008-02-25 10:27:46 -0500
committerJohn W. Linville <linville@tuxdriver.com>2008-03-06 15:30:46 -0500
commitd0709a65181beb787ef3f58cfe45536a2bb254c8 (patch)
tree29e5f36583b0e0a3f11b291347e57672eab41dad /net/mac80211/mesh_pathtbl.c
parent5cf121c3cdb955583bf0c5d28c992b7968a4aa1a (diff)
mac80211: RCU-ify STA info structure access
This makes access to the STA hash table/list use RCU to protect against freeing of items. However, it's not a true RCU, the copy step is missing: whenever somebody changes a STA item it is simply updated. This is an existing race condition that is now somewhat understandable. This patch also fixes the race key freeing vs. STA destruction by making sure that sta_info_destroy() is always called under RTNL and frees the key. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/mesh_pathtbl.c')
-rw-r--r--net/mac80211/mesh_pathtbl.c30
1 files changed, 14 insertions, 16 deletions
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 3cbdbb23d75a..a17f2b299045 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -55,10 +55,7 @@ static DEFINE_RWLOCK(pathtbl_resize_lock);
55 */ 55 */
56void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta) 56void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta)
57{ 57{
58 __sta_info_get(sta); 58 rcu_assign_pointer(mpath->next_hop, sta);
59 if (mpath->next_hop)
60 sta_info_put(mpath->next_hop);
61 mpath->next_hop = sta;
62} 59}
63 60
64 61
@@ -236,7 +233,7 @@ void mesh_plink_broken(struct sta_info *sta)
236 struct mesh_path *mpath; 233 struct mesh_path *mpath;
237 struct mpath_node *node; 234 struct mpath_node *node;
238 struct hlist_node *p; 235 struct hlist_node *p;
239 struct net_device *dev = sta->dev; 236 struct net_device *dev = sta->sdata->dev;
240 int i; 237 int i;
241 238
242 rcu_read_lock(); 239 rcu_read_lock();
@@ -266,9 +263,9 @@ EXPORT_SYMBOL(mesh_plink_broken);
266 * 263 *
267 * RCU notes: this function is called when a mesh plink transitions from ESTAB 264 * RCU notes: this function is called when a mesh plink transitions from ESTAB
268 * to any other state, since ESTAB state is the only one that allows path 265 * to any other state, since ESTAB state is the only one that allows path
269 * creation. This will happen before the sta can be freed (since we hold 266 * creation. This will happen before the sta can be freed (because
270 * a reference to it) so any reader in a rcu read block will be protected 267 * sta_info_destroy() calls this) so any reader in a rcu read block will be
271 * against the plink dissapearing. 268 * protected against the plink disappearing.
272 */ 269 */
273void mesh_path_flush_by_nexthop(struct sta_info *sta) 270void mesh_path_flush_by_nexthop(struct sta_info *sta)
274{ 271{
@@ -280,7 +277,7 @@ void mesh_path_flush_by_nexthop(struct sta_info *sta)
280 for_each_mesh_entry(mesh_paths, p, node, i) { 277 for_each_mesh_entry(mesh_paths, p, node, i) {
281 mpath = node->mpath; 278 mpath = node->mpath;
282 if (mpath->next_hop == sta) 279 if (mpath->next_hop == sta)
283 mesh_path_del(mpath->dst, mpath->dev); 280 mesh_path_del(mpath->dst, mpath->dev, true);
284 } 281 }
285} 282}
286 283
@@ -294,7 +291,7 @@ void mesh_path_flush(struct net_device *dev)
294 for_each_mesh_entry(mesh_paths, p, node, i) { 291 for_each_mesh_entry(mesh_paths, p, node, i) {
295 mpath = node->mpath; 292 mpath = node->mpath;
296 if (mpath->dev == dev) 293 if (mpath->dev == dev)
297 mesh_path_del(mpath->dst, mpath->dev); 294 mesh_path_del(mpath->dst, mpath->dev, false);
298 } 295 }
299} 296}
300 297
@@ -303,8 +300,8 @@ static void mesh_path_node_reclaim(struct rcu_head *rp)
303 struct mpath_node *node = container_of(rp, struct mpath_node, rcu); 300 struct mpath_node *node = container_of(rp, struct mpath_node, rcu);
304 struct ieee80211_sub_if_data *sdata = 301 struct ieee80211_sub_if_data *sdata =
305 IEEE80211_DEV_TO_SUB_IF(node->mpath->dev); 302 IEEE80211_DEV_TO_SUB_IF(node->mpath->dev);
306 if (node->mpath->next_hop) 303
307 sta_info_put(node->mpath->next_hop); 304 rcu_assign_pointer(node->mpath->next_hop, NULL);
308 atomic_dec(&sdata->u.sta.mpaths); 305 atomic_dec(&sdata->u.sta.mpaths);
309 kfree(node->mpath); 306 kfree(node->mpath);
310 kfree(node); 307 kfree(node);
@@ -319,9 +316,10 @@ static void mesh_path_node_reclaim(struct rcu_head *rp)
319 * Returns: 0 if succesful 316 * Returns: 0 if succesful
320 * 317 *
321 * State: if the path is being resolved, the deletion will be postponed until 318 * State: if the path is being resolved, the deletion will be postponed until
322 * the path resolution completes or times out. 319 * the path resolution completes or times out, unless the force parameter
320 * is given.
323 */ 321 */
324int mesh_path_del(u8 *addr, struct net_device *dev) 322int mesh_path_del(u8 *addr, struct net_device *dev, bool force)
325{ 323{
326 struct mesh_path *mpath; 324 struct mesh_path *mpath;
327 struct mpath_node *node; 325 struct mpath_node *node;
@@ -340,7 +338,7 @@ int mesh_path_del(u8 *addr, struct net_device *dev)
340 if (mpath->dev == dev && 338 if (mpath->dev == dev &&
341 memcmp(addr, mpath->dst, ETH_ALEN) == 0) { 339 memcmp(addr, mpath->dst, ETH_ALEN) == 0) {
342 spin_lock_bh(&mpath->state_lock); 340 spin_lock_bh(&mpath->state_lock);
343 if (mpath->flags & MESH_PATH_RESOLVING) { 341 if (!force && mpath->flags & MESH_PATH_RESOLVING) {
344 mpath->flags |= MESH_PATH_DELETE; 342 mpath->flags |= MESH_PATH_DELETE;
345 } else { 343 } else {
346 mpath->flags |= MESH_PATH_RESOLVING; 344 mpath->flags |= MESH_PATH_RESOLVING;
@@ -510,7 +508,7 @@ void mesh_path_expire(struct net_device *dev)
510 time_after(jiffies, 508 time_after(jiffies,
511 mpath->exp_time + MESH_PATH_EXPIRE)) { 509 mpath->exp_time + MESH_PATH_EXPIRE)) {
512 spin_unlock_bh(&mpath->state_lock); 510 spin_unlock_bh(&mpath->state_lock);
513 mesh_path_del(mpath->dst, mpath->dev); 511 mesh_path_del(mpath->dst, mpath->dev, false);
514 } else 512 } else
515 spin_unlock_bh(&mpath->state_lock); 513 spin_unlock_bh(&mpath->state_lock);
516 } 514 }