diff options
author | Javier Cardona <javier@cozybit.com> | 2009-08-10 15:15:52 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-08-14 09:14:01 -0400 |
commit | 18889231e4527dfe23145efe318e74744794a95d (patch) | |
tree | bcb509dab37d80f6dbbfb6671a530aa882c9975e /net/mac80211 | |
parent | 5b365834255d7c90fc724b032c814dfa297aacf9 (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/Kconfig | 8 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 2 | ||||
-rw-r--r-- | net/mac80211/mesh.c | 77 | ||||
-rw-r--r-- | net/mac80211/mesh.h | 20 | ||||
-rw-r--r-- | net/mac80211/mesh_pathtbl.c | 146 |
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 | |||
66 | config MAC80211_MESH | 66 | config 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 | ||
76 | config MAC80211_LEDS | 76 | config 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 | ||
323 | static void __mesh_table_free(struct mesh_table *tbl) | ||
324 | { | ||
325 | kfree(tbl->hash_buckets); | ||
326 | kfree(tbl->hashwlock); | ||
327 | kfree(tbl); | ||
328 | } | ||
329 | |||
330 | void 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 | ||
348 | static void ieee80211_mesh_path_timer(unsigned long data) | 324 | static 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 | ||
363 | struct 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 | |||
391 | errcopy: | ||
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); | ||
397 | endgrow: | ||
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 | */ | ||
57 | enum 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 */ |
251 | struct mesh_table *mesh_table_alloc(int size_order); | 268 | struct mesh_table *mesh_table_alloc(int size_order); |
252 | void mesh_table_free(struct mesh_table *tbl, bool free_leafs); | 269 | void mesh_table_free(struct mesh_table *tbl, bool free_leafs); |
253 | struct mesh_table *mesh_table_grow(struct mesh_table *tbl); | 270 | void mesh_mpath_table_grow(void); |
271 | void mesh_mpp_table_grow(void); | ||
254 | u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, | 272 | u32 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; | |||
39 | static struct mesh_table *mpp_paths; /* Store paths for MPP&MAP */ | 39 | static struct mesh_table *mpp_paths; /* Store paths for MPP&MAP */ |
40 | 40 | ||
41 | int mesh_paths_generation; | 41 | int mesh_paths_generation; |
42 | static void __mesh_table_free(struct mesh_table *tbl) | ||
43 | { | ||
44 | kfree(tbl->hash_buckets); | ||
45 | kfree(tbl->hashwlock); | ||
46 | kfree(tbl); | ||
47 | } | ||
48 | |||
49 | void 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 | |||
67 | static 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 | |||
95 | errcopy: | ||
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); | ||
101 | endgrow: | ||
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 | */ |
188 | int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata) | 251 | int 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 | ||
332 | void 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 | |||
350 | void 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 | ||
282 | int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) | 368 | int 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 | ||