Commit 1928ecab620907a0953f811316d05f367f3f4dba
Committed by
John W. Linville
1 parent
d07c7cf49a
Exists in
master
and in
4 other branches
mac80211: fix and simplify mesh locking
The locking in mesh_{mpath,mpp}_table_grow not only has an rcu_read_unlock() missing, it's also racy (though really only technically since it's invoked from a single function only) since it obtains the new size of the table without any locking, so two invocations of the function could attempt the same resize. Additionally, it uses synchronize_rcu() which is rather expensive and can be avoided trivially here. Modify the functions to only use the table lock and use call_rcu() instead of synchronize_rcu(). Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Showing 2 changed files with 25 additions and 22 deletions Side-by-side Diff
net/mac80211/mesh.h
... | ... | @@ -120,6 +120,7 @@ |
120 | 120 | * buckets |
121 | 121 | * @mean_chain_len: maximum average length for the hash buckets' list, if it is |
122 | 122 | * reached, the table will grow |
123 | + * rcu_head: RCU head to free the table | |
123 | 124 | */ |
124 | 125 | struct mesh_table { |
125 | 126 | /* Number of buckets will be 2^N */ |
... | ... | @@ -132,6 +133,8 @@ |
132 | 133 | int (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl); |
133 | 134 | int size_order; |
134 | 135 | int mean_chain_len; |
136 | + | |
137 | + struct rcu_head rcu_head; | |
135 | 138 | }; |
136 | 139 | |
137 | 140 | /* Recent multicast cache */ |
net/mac80211/mesh_pathtbl.c
... | ... | @@ -370,52 +370,52 @@ |
370 | 370 | return err; |
371 | 371 | } |
372 | 372 | |
373 | +static void mesh_table_free_rcu(struct rcu_head *rcu) | |
374 | +{ | |
375 | + struct mesh_table *tbl = container_of(rcu, struct mesh_table, rcu_head); | |
376 | + | |
377 | + mesh_table_free(tbl, false); | |
378 | +} | |
379 | + | |
373 | 380 | void mesh_mpath_table_grow(void) |
374 | 381 | { |
375 | 382 | struct mesh_table *oldtbl, *newtbl; |
376 | 383 | |
377 | - rcu_read_lock(); | |
378 | - newtbl = mesh_table_alloc(rcu_dereference(mesh_paths)->size_order + 1); | |
379 | - if (!newtbl) | |
380 | - return; | |
381 | 384 | write_lock_bh(&pathtbl_resize_lock); |
385 | + newtbl = mesh_table_alloc(mesh_paths->size_order + 1); | |
386 | + if (!newtbl) | |
387 | + goto out; | |
382 | 388 | oldtbl = mesh_paths; |
383 | 389 | if (mesh_table_grow(mesh_paths, newtbl) < 0) { |
384 | - rcu_read_unlock(); | |
385 | 390 | __mesh_table_free(newtbl); |
386 | - write_unlock_bh(&pathtbl_resize_lock); | |
387 | - return; | |
391 | + goto out; | |
388 | 392 | } |
389 | - rcu_read_unlock(); | |
390 | 393 | rcu_assign_pointer(mesh_paths, newtbl); |
391 | - write_unlock_bh(&pathtbl_resize_lock); | |
392 | 394 | |
393 | - synchronize_rcu(); | |
394 | - mesh_table_free(oldtbl, false); | |
395 | + call_rcu(&oldtbl->rcu_head, mesh_table_free_rcu); | |
396 | + | |
397 | + out: | |
398 | + write_unlock_bh(&pathtbl_resize_lock); | |
395 | 399 | } |
396 | 400 | |
397 | 401 | void mesh_mpp_table_grow(void) |
398 | 402 | { |
399 | 403 | struct mesh_table *oldtbl, *newtbl; |
400 | 404 | |
401 | - rcu_read_lock(); | |
402 | - newtbl = mesh_table_alloc(rcu_dereference(mpp_paths)->size_order + 1); | |
403 | - if (!newtbl) | |
404 | - return; | |
405 | 405 | write_lock_bh(&pathtbl_resize_lock); |
406 | + newtbl = mesh_table_alloc(mpp_paths->size_order + 1); | |
407 | + if (!newtbl) | |
408 | + goto out; | |
406 | 409 | oldtbl = mpp_paths; |
407 | 410 | if (mesh_table_grow(mpp_paths, newtbl) < 0) { |
408 | - rcu_read_unlock(); | |
409 | 411 | __mesh_table_free(newtbl); |
410 | - write_unlock_bh(&pathtbl_resize_lock); | |
411 | - return; | |
412 | + goto out; | |
412 | 413 | } |
413 | - rcu_read_unlock(); | |
414 | 414 | rcu_assign_pointer(mpp_paths, newtbl); |
415 | - write_unlock_bh(&pathtbl_resize_lock); | |
415 | + call_rcu(&oldtbl->rcu_head, mesh_table_free_rcu); | |
416 | 416 | |
417 | - synchronize_rcu(); | |
418 | - mesh_table_free(oldtbl, false); | |
417 | + out: | |
418 | + write_unlock_bh(&pathtbl_resize_lock); | |
419 | 419 | } |
420 | 420 | |
421 | 421 | int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) |