aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorJavier Cardona <javier@cozybit.com>2009-08-10 15:15:52 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-08-14 09:14:01 -0400
commit18889231e4527dfe23145efe318e74744794a95d (patch)
treebcb509dab37d80f6dbbfb6671a530aa882c9975e /net/mac80211
parent5b365834255d7c90fc724b032c814dfa297aacf9 (diff)
mac80211: Move mpath and mpp growth to mesh workqueue.
This prevents calling rcu_synchronize from within the tx path by moving the table growth code to the mesh workqueue. Move mesh_table_free and mesh_table_grow from mesh.c to mesh_pathtbl.c and declare them static. Also, re-enable mesh in Kconfig and update the configuration description. Signed-off-by: Javier Cardona <javier@cozybit.com> Tested-by: Andrey Yurovsky <andrey@cozybit.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/Kconfig8
-rw-r--r--net/mac80211/ieee80211_i.h2
-rw-r--r--net/mac80211/mesh.c77
-rw-r--r--net/mac80211/mesh.h20
-rw-r--r--net/mac80211/mesh_pathtbl.c146
5 files changed, 144 insertions, 109 deletions
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index 7dd77b6d4c9a..9db4ff836a3d 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -66,12 +66,12 @@ endmenu
66config MAC80211_MESH 66config MAC80211_MESH
67 bool "Enable mac80211 mesh networking (pre-802.11s) support" 67 bool "Enable mac80211 mesh networking (pre-802.11s) support"
68 depends on MAC80211 && EXPERIMENTAL 68 depends on MAC80211 && EXPERIMENTAL
69 depends on BROKEN
70 ---help--- 69 ---help---
71 This options enables support of Draft 802.11s mesh networking. 70 This options enables support of Draft 802.11s mesh networking.
72 The implementation is based on Draft 1.08 of the Mesh Networking 71 The implementation is based on Draft 2.08 of the Mesh Networking
73 amendment. For more information visit http://o11s.org/. 72 amendment. However, no compliance with that draft is claimed or even
74 73 possible, as drafts leave a number of identifiers to be defined after
74 ratification. For more information visit http://o11s.org/.
75 75
76config MAC80211_LEDS 76config MAC80211_LEDS
77 bool "Enable LED triggers" 77 bool "Enable LED triggers"
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index d6bd7dd77960..a6abc7dfd903 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -355,7 +355,7 @@ struct ieee80211_if_mesh {
355 355
356 unsigned long timers_running; 356 unsigned long timers_running;
357 357
358 bool housekeeping; 358 unsigned long wrkq_flags;
359 359
360 u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN]; 360 u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN];
361 size_t mesh_id_len; 361 size_t mesh_id_len;
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 25d0065778ef..3185e18c8214 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -47,7 +47,7 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data)
47 struct ieee80211_local *local = sdata->local; 47 struct ieee80211_local *local = sdata->local;
48 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; 48 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
49 49
50 ifmsh->housekeeping = true; 50 ifmsh->wrkq_flags |= MESH_WORK_HOUSEKEEPING;
51 51
52 if (local->quiescing) { 52 if (local->quiescing) {
53 set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); 53 set_bit(TMR_RUNNING_HK, &ifmsh->timers_running);
@@ -320,30 +320,6 @@ struct mesh_table *mesh_table_alloc(int size_order)
320 return newtbl; 320 return newtbl;
321} 321}
322 322
323static void __mesh_table_free(struct mesh_table *tbl)
324{
325 kfree(tbl->hash_buckets);
326 kfree(tbl->hashwlock);
327 kfree(tbl);
328}
329
330void mesh_table_free(struct mesh_table *tbl, bool free_leafs)
331{
332 struct hlist_head *mesh_hash;
333 struct hlist_node *p, *q;
334 int i;
335
336 mesh_hash = tbl->hash_buckets;
337 for (i = 0; i <= tbl->hash_mask; i++) {
338 spin_lock(&tbl->hashwlock[i]);
339 hlist_for_each_safe(p, q, &mesh_hash[i]) {
340 tbl->free_node(p, free_leafs);
341 atomic_dec(&tbl->entries);
342 }
343 spin_unlock(&tbl->hashwlock[i]);
344 }
345 __mesh_table_free(tbl);
346}
347 323
348static void ieee80211_mesh_path_timer(unsigned long data) 324static void ieee80211_mesh_path_timer(unsigned long data)
349{ 325{
@@ -360,44 +336,6 @@ static void ieee80211_mesh_path_timer(unsigned long data)
360 ieee80211_queue_work(&local->hw, &ifmsh->work); 336 ieee80211_queue_work(&local->hw, &ifmsh->work);
361} 337}
362 338
363struct mesh_table *mesh_table_grow(struct mesh_table *tbl)
364{
365 struct mesh_table *newtbl;
366 struct hlist_head *oldhash;
367 struct hlist_node *p, *q;
368 int i;
369
370 if (atomic_read(&tbl->entries)
371 < tbl->mean_chain_len * (tbl->hash_mask + 1))
372 goto endgrow;
373
374 newtbl = mesh_table_alloc(tbl->size_order + 1);
375 if (!newtbl)
376 goto endgrow;
377
378 newtbl->free_node = tbl->free_node;
379 newtbl->mean_chain_len = tbl->mean_chain_len;
380 newtbl->copy_node = tbl->copy_node;
381 atomic_set(&newtbl->entries, atomic_read(&tbl->entries));
382
383 oldhash = tbl->hash_buckets;
384 for (i = 0; i <= tbl->hash_mask; i++)
385 hlist_for_each(p, &oldhash[i])
386 if (tbl->copy_node(p, newtbl) < 0)
387 goto errcopy;
388
389 return newtbl;
390
391errcopy:
392 for (i = 0; i <= newtbl->hash_mask; i++) {
393 hlist_for_each_safe(p, q, &newtbl->hash_buckets[i])
394 tbl->free_node(p, 0);
395 }
396 __mesh_table_free(newtbl);
397endgrow:
398 return NULL;
399}
400
401/** 339/**
402 * ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame 340 * ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame
403 * @hdr: 802.11 frame header 341 * @hdr: 802.11 frame header
@@ -487,7 +425,6 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata,
487 if (free_plinks != sdata->u.mesh.accepting_plinks) 425 if (free_plinks != sdata->u.mesh.accepting_plinks)
488 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); 426 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
489 427
490 ifmsh->housekeeping = false;
491 mod_timer(&ifmsh->housekeeping_timer, 428 mod_timer(&ifmsh->housekeeping_timer,
492 round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL)); 429 round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL));
493} 430}
@@ -524,8 +461,8 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
524 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; 461 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
525 struct ieee80211_local *local = sdata->local; 462 struct ieee80211_local *local = sdata->local;
526 463
527 ifmsh->housekeeping = true; 464 ifmsh->wrkq_flags |= MESH_WORK_HOUSEKEEPING;
528 queue_work(local->hw, &ifmsh->work); 465 ieee80211_queue_work(&local->hw, &ifmsh->work);
529 sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL; 466 sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL;
530 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | 467 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON |
531 BSS_CHANGED_BEACON_ENABLED | 468 BSS_CHANGED_BEACON_ENABLED |
@@ -664,7 +601,13 @@ static void ieee80211_mesh_work(struct work_struct *work)
664 ifmsh->last_preq + msecs_to_jiffies(ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval))) 601 ifmsh->last_preq + msecs_to_jiffies(ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval)))
665 mesh_path_start_discovery(sdata); 602 mesh_path_start_discovery(sdata);
666 603
667 if (ifmsh->housekeeping) 604 if (test_and_clear_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags))
605 mesh_mpath_table_grow();
606
607 if (test_and_clear_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags))
608 mesh_mpp_table_grow();
609
610 if (test_and_clear_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags))
668 ieee80211_mesh_housekeeping(sdata, ifmsh); 611 ieee80211_mesh_housekeeping(sdata, ifmsh);
669} 612}
670 613
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 4241925095c7..eb23fc639b2b 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -44,6 +44,23 @@ enum mesh_path_flags {
44}; 44};
45 45
46/** 46/**
47 * enum mesh_deferred_task_flags - mac80211 mesh deferred tasks
48 *
49 *
50 *
51 * @MESH_WORK_HOUSEKEEPING: run the periodic mesh housekeeping tasks
52 * @MESH_WORK_GROW_MPATH_TABLE: the mesh path table is full and needs
53 * to grow.
54 * @MESH_WORK_GROW_MPP_TABLE: the mesh portals table is full and needs to
55 * grow
56 */
57enum mesh_deferred_task_flags {
58 MESH_WORK_HOUSEKEEPING,
59 MESH_WORK_GROW_MPATH_TABLE,
60 MESH_WORK_GROW_MPP_TABLE,
61};
62
63/**
47 * struct mesh_path - mac80211 mesh path structure 64 * struct mesh_path - mac80211 mesh path structure
48 * 65 *
49 * @dst: mesh path destination mac address 66 * @dst: mesh path destination mac address
@@ -250,7 +267,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
250/* Mesh tables */ 267/* Mesh tables */
251struct mesh_table *mesh_table_alloc(int size_order); 268struct mesh_table *mesh_table_alloc(int size_order);
252void mesh_table_free(struct mesh_table *tbl, bool free_leafs); 269void mesh_table_free(struct mesh_table *tbl, bool free_leafs);
253struct mesh_table *mesh_table_grow(struct mesh_table *tbl); 270void mesh_mpath_table_grow(void);
271void mesh_mpp_table_grow(void);
254u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, 272u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata,
255 struct mesh_table *tbl); 273 struct mesh_table *tbl);
256/* Mesh paths */ 274/* Mesh paths */
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 431865a58622..751c4d0e2b36 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -39,6 +39,69 @@ static struct mesh_table *mesh_paths;
39static struct mesh_table *mpp_paths; /* Store paths for MPP&MAP */ 39static struct mesh_table *mpp_paths; /* Store paths for MPP&MAP */
40 40
41int mesh_paths_generation; 41int mesh_paths_generation;
42static void __mesh_table_free(struct mesh_table *tbl)
43{
44 kfree(tbl->hash_buckets);
45 kfree(tbl->hashwlock);
46 kfree(tbl);
47}
48
49void mesh_table_free(struct mesh_table *tbl, bool free_leafs)
50{
51 struct hlist_head *mesh_hash;
52 struct hlist_node *p, *q;
53 int i;
54
55 mesh_hash = tbl->hash_buckets;
56 for (i = 0; i <= tbl->hash_mask; i++) {
57 spin_lock(&tbl->hashwlock[i]);
58 hlist_for_each_safe(p, q, &mesh_hash[i]) {
59 tbl->free_node(p, free_leafs);
60 atomic_dec(&tbl->entries);
61 }
62 spin_unlock(&tbl->hashwlock[i]);
63 }
64 __mesh_table_free(tbl);
65}
66
67static struct mesh_table *mesh_table_grow(struct mesh_table *tbl)
68{
69 struct mesh_table *newtbl;
70 struct hlist_head *oldhash;
71 struct hlist_node *p, *q;
72 int i;
73
74 if (atomic_read(&tbl->entries)
75 < tbl->mean_chain_len * (tbl->hash_mask + 1))
76 goto endgrow;
77
78 newtbl = mesh_table_alloc(tbl->size_order + 1);
79 if (!newtbl)
80 goto endgrow;
81
82 newtbl->free_node = tbl->free_node;
83 newtbl->mean_chain_len = tbl->mean_chain_len;
84 newtbl->copy_node = tbl->copy_node;
85 atomic_set(&newtbl->entries, atomic_read(&tbl->entries));
86
87 oldhash = tbl->hash_buckets;
88 for (i = 0; i <= tbl->hash_mask; i++)
89 hlist_for_each(p, &oldhash[i])
90 if (tbl->copy_node(p, newtbl) < 0)
91 goto errcopy;
92
93 return newtbl;
94
95errcopy:
96 for (i = 0; i <= newtbl->hash_mask; i++) {
97 hlist_for_each_safe(p, q, &newtbl->hash_buckets[i])
98 tbl->free_node(p, 0);
99 }
100 __mesh_table_free(newtbl);
101endgrow:
102 return NULL;
103}
104
42 105
43/* This lock will have the grow table function as writer and add / delete nodes 106/* This lock will have the grow table function as writer and add / delete nodes
44 * as readers. When reading the table (i.e. doing lookups) we are well protected 107 * as readers. When reading the table (i.e. doing lookups) we are well protected
@@ -187,6 +250,8 @@ struct mesh_path *mesh_path_lookup_by_idx(int idx, struct ieee80211_sub_if_data
187 */ 250 */
188int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) 251int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
189{ 252{
253 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
254 struct ieee80211_local *local = sdata->local;
190 struct mesh_path *mpath, *new_mpath; 255 struct mesh_path *mpath, *new_mpath;
191 struct mpath_node *node, *new_node; 256 struct mpath_node *node, *new_node;
192 struct hlist_head *bucket; 257 struct hlist_head *bucket;
@@ -195,8 +260,6 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
195 int err = 0; 260 int err = 0;
196 u32 hash_idx; 261 u32 hash_idx;
197 262
198 might_sleep();
199
200 if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0) 263 if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0)
201 /* never add ourselves as neighbours */ 264 /* never add ourselves as neighbours */
202 return -ENOTSUPP; 265 return -ENOTSUPP;
@@ -208,11 +271,11 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
208 return -ENOSPC; 271 return -ENOSPC;
209 272
210 err = -ENOMEM; 273 err = -ENOMEM;
211 new_mpath = kzalloc(sizeof(struct mesh_path), GFP_KERNEL); 274 new_mpath = kzalloc(sizeof(struct mesh_path), GFP_ATOMIC);
212 if (!new_mpath) 275 if (!new_mpath)
213 goto err_path_alloc; 276 goto err_path_alloc;
214 277
215 new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL); 278 new_node = kmalloc(sizeof(struct mpath_node), GFP_ATOMIC);
216 if (!new_node) 279 if (!new_node)
217 goto err_node_alloc; 280 goto err_node_alloc;
218 281
@@ -250,20 +313,8 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
250 spin_unlock(&mesh_paths->hashwlock[hash_idx]); 313 spin_unlock(&mesh_paths->hashwlock[hash_idx]);
251 read_unlock(&pathtbl_resize_lock); 314 read_unlock(&pathtbl_resize_lock);
252 if (grow) { 315 if (grow) {
253 struct mesh_table *oldtbl, *newtbl; 316 set_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags);
254 317 ieee80211_queue_work(&local->hw, &ifmsh->work);
255 write_lock(&pathtbl_resize_lock);
256 oldtbl = mesh_paths;
257 newtbl = mesh_table_grow(mesh_paths);
258 if (!newtbl) {
259 write_unlock(&pathtbl_resize_lock);
260 return 0;
261 }
262 rcu_assign_pointer(mesh_paths, newtbl);
263 write_unlock(&pathtbl_resize_lock);
264
265 synchronize_rcu();
266 mesh_table_free(oldtbl, false);
267 } 318 }
268 return 0; 319 return 0;
269 320
@@ -278,9 +329,46 @@ err_path_alloc:
278 return err; 329 return err;
279} 330}
280 331
332void mesh_mpath_table_grow(void)
333{
334 struct mesh_table *oldtbl, *newtbl;
335
336 write_lock(&pathtbl_resize_lock);
337 oldtbl = mesh_paths;
338 newtbl = mesh_table_grow(mesh_paths);
339 if (!newtbl) {
340 write_unlock(&pathtbl_resize_lock);
341 return;
342 }
343 rcu_assign_pointer(mesh_paths, newtbl);
344 write_unlock(&pathtbl_resize_lock);
345
346 synchronize_rcu();
347 mesh_table_free(oldtbl, false);
348}
349
350void mesh_mpp_table_grow(void)
351{
352 struct mesh_table *oldtbl, *newtbl;
353
354 write_lock(&pathtbl_resize_lock);
355 oldtbl = mpp_paths;
356 newtbl = mesh_table_grow(mpp_paths);
357 if (!newtbl) {
358 write_unlock(&pathtbl_resize_lock);
359 return;
360 }
361 rcu_assign_pointer(mpp_paths, newtbl);
362 write_unlock(&pathtbl_resize_lock);
363
364 synchronize_rcu();
365 mesh_table_free(oldtbl, false);
366}
281 367
282int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) 368int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
283{ 369{
370 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
371 struct ieee80211_local *local = sdata->local;
284 struct mesh_path *mpath, *new_mpath; 372 struct mesh_path *mpath, *new_mpath;
285 struct mpath_node *node, *new_node; 373 struct mpath_node *node, *new_node;
286 struct hlist_head *bucket; 374 struct hlist_head *bucket;
@@ -289,8 +377,6 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
289 int err = 0; 377 int err = 0;
290 u32 hash_idx; 378 u32 hash_idx;
291 379
292 might_sleep();
293
294 if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0) 380 if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0)
295 /* never add ourselves as neighbours */ 381 /* never add ourselves as neighbours */
296 return -ENOTSUPP; 382 return -ENOTSUPP;
@@ -299,11 +385,11 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
299 return -ENOTSUPP; 385 return -ENOTSUPP;
300 386
301 err = -ENOMEM; 387 err = -ENOMEM;
302 new_mpath = kzalloc(sizeof(struct mesh_path), GFP_KERNEL); 388 new_mpath = kzalloc(sizeof(struct mesh_path), GFP_ATOMIC);
303 if (!new_mpath) 389 if (!new_mpath)
304 goto err_path_alloc; 390 goto err_path_alloc;
305 391
306 new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL); 392 new_node = kmalloc(sizeof(struct mpath_node), GFP_ATOMIC);
307 if (!new_node) 393 if (!new_node)
308 goto err_node_alloc; 394 goto err_node_alloc;
309 395
@@ -337,20 +423,8 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
337 spin_unlock(&mpp_paths->hashwlock[hash_idx]); 423 spin_unlock(&mpp_paths->hashwlock[hash_idx]);
338 read_unlock(&pathtbl_resize_lock); 424 read_unlock(&pathtbl_resize_lock);
339 if (grow) { 425 if (grow) {
340 struct mesh_table *oldtbl, *newtbl; 426 set_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags);
341 427 ieee80211_queue_work(&local->hw, &ifmsh->work);
342 write_lock(&pathtbl_resize_lock);
343 oldtbl = mpp_paths;
344 newtbl = mesh_table_grow(mpp_paths);
345 if (!newtbl) {
346 write_unlock(&pathtbl_resize_lock);
347 return 0;
348 }
349 rcu_assign_pointer(mpp_paths, newtbl);
350 write_unlock(&pathtbl_resize_lock);
351
352 synchronize_rcu();
353 mesh_table_free(oldtbl, false);
354 } 428 }
355 return 0; 429 return 0;
356 430