diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/mesh.h | 3 | ||||
-rw-r--r-- | net/mac80211/mesh_pathtbl.c | 44 |
2 files changed, 25 insertions, 22 deletions
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index e7c5fddb4804..eb733c0d61aa 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -120,6 +120,7 @@ struct mesh_path { * buckets * @mean_chain_len: maximum average length for the hash buckets' list, if it is * reached, the table will grow + * rcu_head: RCU head to free the table */ struct mesh_table { /* Number of buckets will be 2^N */ @@ -132,6 +133,8 @@ struct mesh_table { int (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl); int size_order; int mean_chain_len; + + struct rcu_head rcu_head; }; /* Recent multicast cache */ diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index f775202552e5..74021365b8c8 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -370,52 +370,52 @@ err_path_alloc: return err; } +static void mesh_table_free_rcu(struct rcu_head *rcu) +{ + struct mesh_table *tbl = container_of(rcu, struct mesh_table, rcu_head); + + mesh_table_free(tbl, false); +} + void mesh_mpath_table_grow(void) { struct mesh_table *oldtbl, *newtbl; - rcu_read_lock(); - newtbl = mesh_table_alloc(rcu_dereference(mesh_paths)->size_order + 1); - if (!newtbl) - return; write_lock_bh(&pathtbl_resize_lock); + newtbl = mesh_table_alloc(mesh_paths->size_order + 1); + if (!newtbl) + goto out; oldtbl = mesh_paths; if (mesh_table_grow(mesh_paths, newtbl) < 0) { - rcu_read_unlock(); __mesh_table_free(newtbl); - write_unlock_bh(&pathtbl_resize_lock); - return; + goto out; } - rcu_read_unlock(); rcu_assign_pointer(mesh_paths, newtbl); - write_unlock_bh(&pathtbl_resize_lock); - synchronize_rcu(); - mesh_table_free(oldtbl, false); + call_rcu(&oldtbl->rcu_head, mesh_table_free_rcu); + + out: + write_unlock_bh(&pathtbl_resize_lock); } void mesh_mpp_table_grow(void) { struct mesh_table *oldtbl, *newtbl; - rcu_read_lock(); - newtbl = mesh_table_alloc(rcu_dereference(mpp_paths)->size_order + 1); - if (!newtbl) - return; write_lock_bh(&pathtbl_resize_lock); + newtbl = mesh_table_alloc(mpp_paths->size_order + 1); + if (!newtbl) + goto out; oldtbl = mpp_paths; if (mesh_table_grow(mpp_paths, newtbl) < 0) { - rcu_read_unlock(); __mesh_table_free(newtbl); - write_unlock_bh(&pathtbl_resize_lock); - return; + goto out; } - rcu_read_unlock(); rcu_assign_pointer(mpp_paths, newtbl); - write_unlock_bh(&pathtbl_resize_lock); + call_rcu(&oldtbl->rcu_head, mesh_table_free_rcu); - synchronize_rcu(); - mesh_table_free(oldtbl, false); + out: + write_unlock_bh(&pathtbl_resize_lock); } int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) |