Skip to content

Commit 1928eca

Browse files
jmberg-intellinvjw
authored andcommitted
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 <[email protected]> Signed-off-by: John W. Linville <[email protected]>
1 parent d07c7cf commit 1928eca

File tree

2 files changed

+25
-22
lines changed

2 files changed

+25
-22
lines changed

net/mac80211/mesh.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ struct mesh_path {
120120
* buckets
121121
* @mean_chain_len: maximum average length for the hash buckets' list, if it is
122122
* reached, the table will grow
123+
* rcu_head: RCU head to free the table
123124
*/
124125
struct mesh_table {
125126
/* Number of buckets will be 2^N */
@@ -132,6 +133,8 @@ struct mesh_table {
132133
int (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl);
133134
int size_order;
134135
int mean_chain_len;
136+
137+
struct rcu_head rcu_head;
135138
};
136139

137140
/* Recent multicast cache */

net/mac80211/mesh_pathtbl.c

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -370,52 +370,52 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
370370
return err;
371371
}
372372

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+
373380
void mesh_mpath_table_grow(void)
374381
{
375382
struct mesh_table *oldtbl, *newtbl;
376383

377-
rcu_read_lock();
378-
newtbl = mesh_table_alloc(rcu_dereference(mesh_paths)->size_order + 1);
379-
if (!newtbl)
380-
return;
381384
write_lock_bh(&pathtbl_resize_lock);
385+
newtbl = mesh_table_alloc(mesh_paths->size_order + 1);
386+
if (!newtbl)
387+
goto out;
382388
oldtbl = mesh_paths;
383389
if (mesh_table_grow(mesh_paths, newtbl) < 0) {
384-
rcu_read_unlock();
385390
__mesh_table_free(newtbl);
386-
write_unlock_bh(&pathtbl_resize_lock);
387-
return;
391+
goto out;
388392
}
389-
rcu_read_unlock();
390393
rcu_assign_pointer(mesh_paths, newtbl);
391-
write_unlock_bh(&pathtbl_resize_lock);
392394

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);
395399
}
396400

397401
void mesh_mpp_table_grow(void)
398402
{
399403
struct mesh_table *oldtbl, *newtbl;
400404

401-
rcu_read_lock();
402-
newtbl = mesh_table_alloc(rcu_dereference(mpp_paths)->size_order + 1);
403-
if (!newtbl)
404-
return;
405405
write_lock_bh(&pathtbl_resize_lock);
406+
newtbl = mesh_table_alloc(mpp_paths->size_order + 1);
407+
if (!newtbl)
408+
goto out;
406409
oldtbl = mpp_paths;
407410
if (mesh_table_grow(mpp_paths, newtbl) < 0) {
408-
rcu_read_unlock();
409411
__mesh_table_free(newtbl);
410-
write_unlock_bh(&pathtbl_resize_lock);
411-
return;
412+
goto out;
412413
}
413-
rcu_read_unlock();
414414
rcu_assign_pointer(mpp_paths, newtbl);
415-
write_unlock_bh(&pathtbl_resize_lock);
415+
call_rcu(&oldtbl->rcu_head, mesh_table_free_rcu);
416416

417-
synchronize_rcu();
418-
mesh_table_free(oldtbl, false);
417+
out:
418+
write_unlock_bh(&pathtbl_resize_lock);
419419
}
420420

421421
int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)

0 commit comments

Comments
 (0)