2016-02-29 01:04:09

by Bob Copeland

[permalink] [raw]
Subject: [PATCH 1/4] mac80211: mesh: move path tables into if_mesh

The mesh path and mesh gate hashtables are global, containing
all of the mpaths for every mesh interface, but the paths are
all tied logically to a single interface. The common case is
just a single mesh interface, so optimize for that by moving
the global hashtable into the per-interface struct.

Doing so allows us to drop sdata pointer comparisons inside
the lookups and also saves a few bytes of BSS and data.

Signed-off-by: Bob Copeland <[email protected]>
---
net/mac80211/cfg.c | 4 +-
net/mac80211/ieee80211_i.h | 12 +++
net/mac80211/mesh.c | 10 ++-
net/mac80211/mesh.h | 10 +--
net/mac80211/mesh_pathtbl.c | 181 +++++++++++++++++++-------------------------
net/mac80211/tx.c | 2 +-
6 files changed, 104 insertions(+), 115 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index fe1704c4e8fb..b37adb60c9cb 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1499,7 +1499,7 @@ static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop,

memset(pinfo, 0, sizeof(*pinfo));

- pinfo->generation = mesh_paths_generation;
+ pinfo->generation = mpath->sdata->u.mesh.mesh_paths_generation;

pinfo->filled = MPATH_INFO_FRAME_QLEN |
MPATH_INFO_SN |
@@ -1577,7 +1577,7 @@ static void mpp_set_pinfo(struct mesh_path *mpath, u8 *mpp,
memset(pinfo, 0, sizeof(*pinfo));
memcpy(mpp, mpath->mpp, ETH_ALEN);

- pinfo->generation = mpp_paths_generation;
+ pinfo->generation = mpath->sdata->u.mesh.mpp_paths_generation;
}

static int ieee80211_get_mpp(struct wiphy *wiphy, struct net_device *dev,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 1630975c89f1..597f1b6260f4 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -696,6 +696,18 @@ struct ieee80211_if_mesh {

/* offset from skb->data while building IE */
int meshconf_offset;
+
+ struct mesh_table __rcu *mesh_paths;
+ struct mesh_table __rcu *mpp_paths; /* Store paths for MPP&MAP */
+ int mesh_paths_generation;
+ int mpp_paths_generation;
+
+ /* Protects assignment of the mesh_paths/mpp_paths table
+ * pointer for resize against reading it for add/delete
+ * of individual paths. Pure readers (lookups) just use
+ * RCU.
+ */
+ rwlock_t pathtbl_resize_lock;
};

#ifdef CONFIG_MAC80211_MESH
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index d32cefcb63b0..c92af2a7714d 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -25,7 +25,6 @@ bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt)

void ieee80211s_init(void)
{
- mesh_pathtbl_init();
mesh_allocated = 1;
rm_cache = kmem_cache_create("mesh_rmc", sizeof(struct rmc_entry),
0, 0, NULL);
@@ -35,7 +34,6 @@ void ieee80211s_stop(void)
{
if (!mesh_allocated)
return;
- mesh_pathtbl_unregister();
kmem_cache_destroy(rm_cache);
}

@@ -902,6 +900,7 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
/* flush STAs and mpaths on this iface */
sta_info_flush(sdata);
mesh_path_flush_by_iface(sdata);
+ mesh_pathtbl_unregister(sdata);

/* free all potentially still buffered group-addressed frames */
local->total_ps_buffered -= skb_queue_len(&ifmsh->ps.bc_buf);
@@ -1349,10 +1348,10 @@ void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata)
mesh_path_start_discovery(sdata);

if (test_and_clear_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags))
- mesh_mpath_table_grow();
+ mesh_mpath_table_grow(sdata);

if (test_and_clear_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags))
- mesh_mpp_table_grow();
+ mesh_mpp_table_grow(sdata);

if (test_and_clear_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags))
ieee80211_mesh_housekeeping(sdata);
@@ -1388,6 +1387,9 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
/* Allocate all mesh structures when creating the first mesh interface. */
if (!mesh_allocated)
ieee80211s_init();
+
+ mesh_pathtbl_init(sdata);
+
setup_timer(&ifmsh->mesh_path_timer,
ieee80211_mesh_path_timer,
(unsigned long) sdata);
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 87c017a3b1ce..601992b6cd8a 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -300,8 +300,8 @@ void mesh_sta_cleanup(struct sta_info *sta);

/* Private interfaces */
/* Mesh tables */
-void mesh_mpath_table_grow(void);
-void mesh_mpp_table_grow(void);
+void mesh_mpath_table_grow(struct ieee80211_sub_if_data *sdata);
+void mesh_mpp_table_grow(struct ieee80211_sub_if_data *sdata);
/* Mesh paths */
int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata,
u8 ttl, const u8 *target, u32 target_sn,
@@ -309,8 +309,8 @@ int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata,
void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta);
void mesh_path_flush_pending(struct mesh_path *mpath);
void mesh_path_tx_pending(struct mesh_path *mpath);
-int mesh_pathtbl_init(void);
-void mesh_pathtbl_unregister(void);
+int mesh_pathtbl_init(struct ieee80211_sub_if_data *sdata);
+void mesh_pathtbl_unregister(struct ieee80211_sub_if_data *sdata);
int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr);
void mesh_path_timer(unsigned long data);
void mesh_path_flush_by_nexthop(struct sta_info *sta);
@@ -319,8 +319,6 @@ void mesh_path_discard_frame(struct ieee80211_sub_if_data *sdata,
void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata);

bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt);
-extern int mesh_paths_generation;
-extern int mpp_paths_generation;

#ifdef CONFIG_MAC80211_MESH
static inline
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 2ba7aa56b11c..0508b37b0471 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -40,36 +40,24 @@ struct mpath_node {
struct mesh_path *mpath;
};

-static struct mesh_table __rcu *mesh_paths;
-static struct mesh_table __rcu *mpp_paths; /* Store paths for MPP&MAP */
-
-int mesh_paths_generation;
-int mpp_paths_generation;
-
-/* This lock will have the grow table function as writer and add / delete nodes
- * as readers. RCU provides sufficient protection only when reading the table
- * (i.e. doing lookups). Adding or adding or removing nodes requires we take
- * the read lock or we risk operating on an old table. The write lock is only
- * needed when modifying the number of buckets a table.
- */
-static DEFINE_RWLOCK(pathtbl_resize_lock);
-
-
static inline struct mesh_table *resize_dereference_paths(
+ struct ieee80211_sub_if_data *sdata,
struct mesh_table __rcu *table)
{
return rcu_dereference_protected(table,
- lockdep_is_held(&pathtbl_resize_lock));
+ lockdep_is_held(&sdata->u.mesh.pathtbl_resize_lock));
}

-static inline struct mesh_table *resize_dereference_mesh_paths(void)
+static inline struct mesh_table *resize_dereference_mesh_paths(
+ struct ieee80211_sub_if_data *sdata)
{
- return resize_dereference_paths(mesh_paths);
+ return resize_dereference_paths(sdata, sdata->u.mesh.mesh_paths);
}

-static inline struct mesh_table *resize_dereference_mpp_paths(void)
+static inline struct mesh_table *resize_dereference_mpp_paths(
+ struct ieee80211_sub_if_data *sdata)
{
- return resize_dereference_paths(mpp_paths);
+ return resize_dereference_paths(sdata, sdata->u.mesh.mpp_paths);
}

/*
@@ -346,8 +334,7 @@ static struct mesh_path *mpath_lookup(struct mesh_table *tbl, const u8 *dst,
bucket = &tbl->hash_buckets[mesh_table_hash(dst, sdata, tbl)];
hlist_for_each_entry_rcu(node, bucket, list) {
mpath = node->mpath;
- if (mpath->sdata == sdata &&
- ether_addr_equal(dst, mpath->dst)) {
+ if (ether_addr_equal(dst, mpath->dst)) {
if (mpath_expired(mpath)) {
spin_lock_bh(&mpath->state_lock);
mpath->flags &= ~MESH_PATH_ACTIVE;
@@ -371,13 +358,15 @@ static struct mesh_path *mpath_lookup(struct mesh_table *tbl, const u8 *dst,
struct mesh_path *
mesh_path_lookup(struct ieee80211_sub_if_data *sdata, const u8 *dst)
{
- return mpath_lookup(rcu_dereference(mesh_paths), dst, sdata);
+ return mpath_lookup(rcu_dereference(sdata->u.mesh.mesh_paths), dst,
+ sdata);
}

struct mesh_path *
mpp_path_lookup(struct ieee80211_sub_if_data *sdata, const u8 *dst)
{
- return mpath_lookup(rcu_dereference(mpp_paths), dst, sdata);
+ return mpath_lookup(rcu_dereference(sdata->u.mesh.mpp_paths), dst,
+ sdata);
}


@@ -393,14 +382,12 @@ mpp_path_lookup(struct ieee80211_sub_if_data *sdata, const u8 *dst)
struct mesh_path *
mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx)
{
- struct mesh_table *tbl = rcu_dereference(mesh_paths);
+ struct mesh_table *tbl = rcu_dereference(sdata->u.mesh.mesh_paths);
struct mpath_node *node;
int i;
int j = 0;

for_each_mesh_entry(tbl, node, i) {
- if (sdata && node->mpath->sdata != sdata)
- continue;
if (j++ == idx) {
if (mpath_expired(node->mpath)) {
spin_lock_bh(&node->mpath->state_lock);
@@ -426,14 +413,12 @@ mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx)
struct mesh_path *
mpp_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx)
{
- struct mesh_table *tbl = rcu_dereference(mpp_paths);
+ struct mesh_table *tbl = rcu_dereference(sdata->u.mesh.mpp_paths);
struct mpath_node *node;
int i;
int j = 0;

for_each_mesh_entry(tbl, node, i) {
- if (sdata && node->mpath->sdata != sdata)
- continue;
if (j++ == idx)
return node->mpath;
}
@@ -452,7 +437,7 @@ int mesh_path_add_gate(struct mesh_path *mpath)
int err;

rcu_read_lock();
- tbl = rcu_dereference(mesh_paths);
+ tbl = rcu_dereference(mpath->sdata->u.mesh.mesh_paths);

hlist_for_each_entry_rcu(gate, tbl->known_gates, list)
if (gate->mpath == mpath) {
@@ -550,8 +535,8 @@ struct mesh_path *mesh_path_add(struct ieee80211_sub_if_data *sdata,
if (atomic_add_unless(&sdata->u.mesh.mpaths, 1, MESH_MAX_MPATHS) == 0)
return ERR_PTR(-ENOSPC);

- read_lock_bh(&pathtbl_resize_lock);
- tbl = resize_dereference_mesh_paths();
+ read_lock_bh(&sdata->u.mesh.pathtbl_resize_lock);
+ tbl = resize_dereference_mesh_paths(sdata);

hash_idx = mesh_table_hash(dst, sdata, tbl);
bucket = &tbl->hash_buckets[hash_idx];
@@ -560,8 +545,7 @@ struct mesh_path *mesh_path_add(struct ieee80211_sub_if_data *sdata,

hlist_for_each_entry(node, bucket, list) {
mpath = node->mpath;
- if (mpath->sdata == sdata &&
- ether_addr_equal(dst, mpath->dst))
+ if (ether_addr_equal(dst, mpath->dst))
goto found;
}

@@ -592,7 +576,7 @@ struct mesh_path *mesh_path_add(struct ieee80211_sub_if_data *sdata,
MEAN_CHAIN_LEN * (tbl->hash_mask + 1))
grow = 1;

- mesh_paths_generation++;
+ sdata->u.mesh.mesh_paths_generation++;

if (grow) {
set_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags);
@@ -601,7 +585,7 @@ struct mesh_path *mesh_path_add(struct ieee80211_sub_if_data *sdata,
mpath = new_mpath;
found:
spin_unlock(&tbl->hashwlock[hash_idx]);
- read_unlock_bh(&pathtbl_resize_lock);
+ read_unlock_bh(&sdata->u.mesh.pathtbl_resize_lock);
return mpath;

err_node_alloc:
@@ -609,7 +593,7 @@ err_node_alloc:
err_path_alloc:
atomic_dec(&sdata->u.mesh.mpaths);
spin_unlock(&tbl->hashwlock[hash_idx]);
- read_unlock_bh(&pathtbl_resize_lock);
+ read_unlock_bh(&sdata->u.mesh.pathtbl_resize_lock);
return ERR_PTR(err);
}

@@ -620,12 +604,12 @@ static void mesh_table_free_rcu(struct rcu_head *rcu)
mesh_table_free(tbl, false);
}

-void mesh_mpath_table_grow(void)
+void mesh_mpath_table_grow(struct ieee80211_sub_if_data *sdata)
{
struct mesh_table *oldtbl, *newtbl;

- write_lock_bh(&pathtbl_resize_lock);
- oldtbl = resize_dereference_mesh_paths();
+ write_lock_bh(&sdata->u.mesh.pathtbl_resize_lock);
+ oldtbl = resize_dereference_mesh_paths(sdata);
newtbl = mesh_table_alloc(oldtbl->size_order + 1);
if (!newtbl)
goto out;
@@ -633,20 +617,20 @@ void mesh_mpath_table_grow(void)
__mesh_table_free(newtbl);
goto out;
}
- rcu_assign_pointer(mesh_paths, newtbl);
+ rcu_assign_pointer(sdata->u.mesh.mesh_paths, newtbl);

call_rcu(&oldtbl->rcu_head, mesh_table_free_rcu);

out:
- write_unlock_bh(&pathtbl_resize_lock);
+ write_unlock_bh(&sdata->u.mesh.pathtbl_resize_lock);
}

-void mesh_mpp_table_grow(void)
+void mesh_mpp_table_grow(struct ieee80211_sub_if_data *sdata)
{
struct mesh_table *oldtbl, *newtbl;

- write_lock_bh(&pathtbl_resize_lock);
- oldtbl = resize_dereference_mpp_paths();
+ write_lock_bh(&sdata->u.mesh.pathtbl_resize_lock);
+ oldtbl = resize_dereference_mpp_paths(sdata);
newtbl = mesh_table_alloc(oldtbl->size_order + 1);
if (!newtbl)
goto out;
@@ -654,11 +638,11 @@ void mesh_mpp_table_grow(void)
__mesh_table_free(newtbl);
goto out;
}
- rcu_assign_pointer(mpp_paths, newtbl);
+ rcu_assign_pointer(sdata->u.mesh.mpp_paths, newtbl);
call_rcu(&oldtbl->rcu_head, mesh_table_free_rcu);

out:
- write_unlock_bh(&pathtbl_resize_lock);
+ write_unlock_bh(&sdata->u.mesh.pathtbl_resize_lock);
}

int mpp_path_add(struct ieee80211_sub_if_data *sdata,
@@ -690,7 +674,7 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata,
if (!new_node)
goto err_node_alloc;

- read_lock_bh(&pathtbl_resize_lock);
+ read_lock_bh(&sdata->u.mesh.pathtbl_resize_lock);
memcpy(new_mpath->dst, dst, ETH_ALEN);
memcpy(new_mpath->mpp, mpp, ETH_ALEN);
new_mpath->sdata = sdata;
@@ -701,7 +685,7 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata,
new_mpath->exp_time = jiffies;
spin_lock_init(&new_mpath->state_lock);

- tbl = resize_dereference_mpp_paths();
+ tbl = resize_dereference_mpp_paths(sdata);

hash_idx = mesh_table_hash(dst, sdata, tbl);
bucket = &tbl->hash_buckets[hash_idx];
@@ -711,8 +695,7 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata,
err = -EEXIST;
hlist_for_each_entry(node, bucket, list) {
mpath = node->mpath;
- if (mpath->sdata == sdata &&
- ether_addr_equal(dst, mpath->dst))
+ if (ether_addr_equal(dst, mpath->dst))
goto err_exists;
}

@@ -722,9 +705,9 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata,
grow = 1;

spin_unlock(&tbl->hashwlock[hash_idx]);
- read_unlock_bh(&pathtbl_resize_lock);
+ read_unlock_bh(&sdata->u.mesh.pathtbl_resize_lock);

- mpp_paths_generation++;
+ sdata->u.mesh.mpp_paths_generation++;

if (grow) {
set_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags);
@@ -734,7 +717,7 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata,

err_exists:
spin_unlock(&tbl->hashwlock[hash_idx]);
- read_unlock_bh(&pathtbl_resize_lock);
+ read_unlock_bh(&sdata->u.mesh.pathtbl_resize_lock);
kfree(new_node);
err_node_alloc:
kfree(new_mpath);
@@ -761,7 +744,7 @@ void mesh_plink_broken(struct sta_info *sta)
int i;

rcu_read_lock();
- tbl = rcu_dereference(mesh_paths);
+ tbl = rcu_dereference(sdata->u.mesh.mesh_paths);
for_each_mesh_entry(tbl, node, i) {
mpath = node->mpath;
if (rcu_access_pointer(mpath->next_hop) == sta &&
@@ -819,14 +802,15 @@ static void __mesh_path_del(struct mesh_table *tbl, struct mpath_node *node)
*/
void mesh_path_flush_by_nexthop(struct sta_info *sta)
{
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
struct mesh_table *tbl;
struct mesh_path *mpath;
struct mpath_node *node;
int i;

rcu_read_lock();
- read_lock_bh(&pathtbl_resize_lock);
- tbl = resize_dereference_mesh_paths();
+ read_lock_bh(&sdata->u.mesh.pathtbl_resize_lock);
+ tbl = resize_dereference_mesh_paths(sdata);
for_each_mesh_entry(tbl, node, i) {
mpath = node->mpath;
if (rcu_access_pointer(mpath->next_hop) == sta) {
@@ -835,7 +819,7 @@ void mesh_path_flush_by_nexthop(struct sta_info *sta)
spin_unlock(&tbl->hashwlock[i]);
}
}
- read_unlock_bh(&pathtbl_resize_lock);
+ read_unlock_bh(&sdata->u.mesh.pathtbl_resize_lock);
rcu_read_unlock();
}

@@ -848,8 +832,8 @@ static void mpp_flush_by_proxy(struct ieee80211_sub_if_data *sdata,
int i;

rcu_read_lock();
- read_lock_bh(&pathtbl_resize_lock);
- tbl = resize_dereference_mpp_paths();
+ read_lock_bh(&sdata->u.mesh.pathtbl_resize_lock);
+ tbl = resize_dereference_mpp_paths(sdata);
for_each_mesh_entry(tbl, node, i) {
mpp = node->mpath;
if (ether_addr_equal(mpp->mpp, proxy)) {
@@ -858,7 +842,7 @@ static void mpp_flush_by_proxy(struct ieee80211_sub_if_data *sdata,
spin_unlock(&tbl->hashwlock[i]);
}
}
- read_unlock_bh(&pathtbl_resize_lock);
+ read_unlock_bh(&sdata->u.mesh.pathtbl_resize_lock);
rcu_read_unlock();
}

@@ -872,8 +856,6 @@ static void table_flush_by_iface(struct mesh_table *tbl,
WARN_ON(!rcu_read_lock_held());
for_each_mesh_entry(tbl, node, i) {
mpath = node->mpath;
- if (mpath->sdata != sdata)
- continue;
spin_lock_bh(&tbl->hashwlock[i]);
__mesh_path_del(tbl, node);
spin_unlock_bh(&tbl->hashwlock[i]);
@@ -893,12 +875,12 @@ void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata)
struct mesh_table *tbl;

rcu_read_lock();
- read_lock_bh(&pathtbl_resize_lock);
- tbl = resize_dereference_mesh_paths();
+ read_lock_bh(&sdata->u.mesh.pathtbl_resize_lock);
+ tbl = resize_dereference_mesh_paths(sdata);
table_flush_by_iface(tbl, sdata);
- tbl = resize_dereference_mpp_paths();
+ tbl = resize_dereference_mpp_paths(sdata);
table_flush_by_iface(tbl, sdata);
- read_unlock_bh(&pathtbl_resize_lock);
+ read_unlock_bh(&sdata->u.mesh.pathtbl_resize_lock);
rcu_read_unlock();
}

@@ -922,15 +904,14 @@ static int table_path_del(struct mesh_table __rcu *rcu_tbl,
int hash_idx;
int err = 0;

- tbl = resize_dereference_paths(rcu_tbl);
+ tbl = resize_dereference_paths(sdata, rcu_tbl);
hash_idx = mesh_table_hash(addr, sdata, tbl);
bucket = &tbl->hash_buckets[hash_idx];

spin_lock(&tbl->hashwlock[hash_idx]);
hlist_for_each_entry(node, bucket, list) {
mpath = node->mpath;
- if (mpath->sdata == sdata &&
- ether_addr_equal(addr, mpath->dst)) {
+ if (ether_addr_equal(addr, mpath->dst)) {
__mesh_path_del(tbl, node);
goto enddel;
}
@@ -957,10 +938,10 @@ int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr)
/* flush relevant mpp entries first */
mpp_flush_by_proxy(sdata, addr);

- read_lock_bh(&pathtbl_resize_lock);
- err = table_path_del(mesh_paths, sdata, addr);
- mesh_paths_generation++;
- read_unlock_bh(&pathtbl_resize_lock);
+ read_lock_bh(&sdata->u.mesh.pathtbl_resize_lock);
+ err = table_path_del(sdata->u.mesh.mesh_paths, sdata, addr);
+ sdata->u.mesh.mesh_paths_generation++;
+ read_unlock_bh(&sdata->u.mesh.pathtbl_resize_lock);

return err;
}
@@ -977,10 +958,10 @@ static int mpp_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr)
{
int err = 0;

- read_lock_bh(&pathtbl_resize_lock);
- err = table_path_del(mpp_paths, sdata, addr);
- mpp_paths_generation++;
- read_unlock_bh(&pathtbl_resize_lock);
+ read_lock_bh(&sdata->u.mesh.pathtbl_resize_lock);
+ err = table_path_del(sdata->u.mesh.mpp_paths, sdata, addr);
+ sdata->u.mesh.mpp_paths_generation++;
+ read_unlock_bh(&sdata->u.mesh.pathtbl_resize_lock);

return err;
}
@@ -1020,7 +1001,7 @@ int mesh_path_send_to_gates(struct mesh_path *mpath)
struct hlist_head *known_gates;

rcu_read_lock();
- tbl = rcu_dereference(mesh_paths);
+ tbl = rcu_dereference(sdata->u.mesh.mesh_paths);
known_gates = tbl->known_gates;
rcu_read_unlock();

@@ -1028,9 +1009,6 @@ int mesh_path_send_to_gates(struct mesh_path *mpath)
return -EHOSTUNREACH;

hlist_for_each_entry_rcu(gate, known_gates, list) {
- if (gate->mpath->sdata != sdata)
- continue;
-
if (gate->mpath->flags & MESH_PATH_ACTIVE) {
mpath_dbg(sdata, "Forwarding to %pM\n", gate->mpath->dst);
mesh_path_move_to_queue(gate->mpath, from_mpath, copy);
@@ -1043,11 +1021,10 @@ int mesh_path_send_to_gates(struct mesh_path *mpath)
}
}

- hlist_for_each_entry_rcu(gate, known_gates, list)
- if (gate->mpath->sdata == sdata) {
- mpath_dbg(sdata, "Sending to %pM\n", gate->mpath->dst);
- mesh_path_tx_pending(gate->mpath);
- }
+ hlist_for_each_entry_rcu(gate, known_gates, list) {
+ mpath_dbg(sdata, "Sending to %pM\n", gate->mpath->dst);
+ mesh_path_tx_pending(gate->mpath);
+ }

return (from_mpath == mpath) ? -EHOSTUNREACH : 0;
}
@@ -1136,7 +1113,7 @@ static int mesh_path_node_copy(struct hlist_node *p, struct mesh_table *newtbl)
return 0;
}

-int mesh_pathtbl_init(void)
+int mesh_pathtbl_init(struct ieee80211_sub_if_data *sdata)
{
struct mesh_table *tbl_path, *tbl_mpp;
int ret;
@@ -1168,9 +1145,11 @@ int mesh_pathtbl_init(void)
}
INIT_HLIST_HEAD(tbl_mpp->known_gates);

+ rwlock_init(&sdata->u.mesh.pathtbl_resize_lock);
+
/* Need no locking since this is during init */
- RCU_INIT_POINTER(mesh_paths, tbl_path);
- RCU_INIT_POINTER(mpp_paths, tbl_mpp);
+ RCU_INIT_POINTER(sdata->u.mesh.mesh_paths, tbl_path);
+ RCU_INIT_POINTER(sdata->u.mesh.mpp_paths, tbl_mpp);

return 0;

@@ -1189,33 +1168,31 @@ void mesh_path_expire(struct ieee80211_sub_if_data *sdata)
int i;

rcu_read_lock();
- tbl = rcu_dereference(mesh_paths);
+ tbl = rcu_dereference(sdata->u.mesh.mesh_paths);
for_each_mesh_entry(tbl, node, i) {
- if (node->mpath->sdata != sdata)
- continue;
mpath = node->mpath;
if ((!(mpath->flags & MESH_PATH_RESOLVING)) &&
(!(mpath->flags & MESH_PATH_FIXED)) &&
time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE))
- mesh_path_del(mpath->sdata, mpath->dst);
+ mesh_path_del(sdata, mpath->dst);
}

- tbl = rcu_dereference(mpp_paths);
+ tbl = rcu_dereference(sdata->u.mesh.mpp_paths);
for_each_mesh_entry(tbl, node, i) {
- if (node->mpath->sdata != sdata)
- continue;
mpath = node->mpath;
if ((!(mpath->flags & MESH_PATH_FIXED)) &&
time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE))
- mpp_path_del(mpath->sdata, mpath->dst);
+ mpp_path_del(sdata, mpath->dst);
}

rcu_read_unlock();
}

-void mesh_pathtbl_unregister(void)
+void mesh_pathtbl_unregister(struct ieee80211_sub_if_data *sdata)
{
/* no need for locking during exit path */
- mesh_table_free(rcu_dereference_protected(mesh_paths, 1), true);
- mesh_table_free(rcu_dereference_protected(mpp_paths, 1), true);
+ mesh_table_free(rcu_dereference_protected(sdata->u.mesh.mesh_paths, 1),
+ true);
+ mesh_table_free(rcu_dereference_protected(sdata->u.mesh.mpp_paths, 1),
+ true);
}
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 3a7475ff1a41..4388a7a91c42 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2181,7 +2181,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
}

if (mppath && mpath)
- mesh_path_del(mpath->sdata, mpath->dst);
+ mesh_path_del(sdata, mpath->dst);
}

/*
--
2.6.1



2016-02-29 01:04:08

by Bob Copeland

[permalink] [raw]
Subject: [PATCH 3/4] mesh: factor out common mesh path allocation code

Remove duplicate code to allocate and initialize a mesh
path or mesh proxy path.

Signed-off-by: Bob Copeland <[email protected]>
---
net/mac80211/mesh_pathtbl.c | 51 +++++++++++++++++++++++++--------------------
1 file changed, 28 insertions(+), 23 deletions(-)

diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index fc3cc350df8c..4794240e8f94 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -501,6 +501,31 @@ int mesh_gate_num(struct ieee80211_sub_if_data *sdata)
return sdata->u.mesh.num_gates;
}

+static
+struct mesh_path *mesh_path_new(struct ieee80211_sub_if_data *sdata,
+ const u8 *dst, gfp_t gfp_flags)
+{
+ struct mesh_path *new_mpath;
+
+ new_mpath = kzalloc(sizeof(struct mesh_path), gfp_flags);
+ if (!new_mpath)
+ return NULL;
+
+ memcpy(new_mpath->dst, dst, ETH_ALEN);
+ eth_broadcast_addr(new_mpath->rann_snd_addr);
+ new_mpath->is_root = false;
+ new_mpath->sdata = sdata;
+ new_mpath->flags = 0;
+ skb_queue_head_init(&new_mpath->frame_queue);
+ new_mpath->timer.data = (unsigned long) new_mpath;
+ new_mpath->timer.function = mesh_path_timer;
+ new_mpath->exp_time = jiffies;
+ spin_lock_init(&new_mpath->state_lock);
+ init_timer(&new_mpath->timer);
+
+ return new_mpath;
+}
+
/**
* mesh_path_add - allocate and add a new path to the mesh path table
* @dst: destination address of the path (ETH_ALEN length)
@@ -548,7 +573,7 @@ struct mesh_path *mesh_path_add(struct ieee80211_sub_if_data *sdata,
}

err = -ENOMEM;
- new_mpath = kzalloc(sizeof(struct mesh_path), GFP_ATOMIC);
+ new_mpath = mesh_path_new(sdata, dst, GFP_ATOMIC);
if (!new_mpath)
goto err_path_alloc;

@@ -556,19 +581,7 @@ struct mesh_path *mesh_path_add(struct ieee80211_sub_if_data *sdata,
if (!new_node)
goto err_node_alloc;

- memcpy(new_mpath->dst, dst, ETH_ALEN);
- eth_broadcast_addr(new_mpath->rann_snd_addr);
- new_mpath->is_root = false;
- new_mpath->sdata = sdata;
- new_mpath->flags = 0;
- skb_queue_head_init(&new_mpath->frame_queue);
new_node->mpath = new_mpath;
- new_mpath->timer.data = (unsigned long) new_mpath;
- new_mpath->timer.function = mesh_path_timer;
- new_mpath->exp_time = jiffies;
- spin_lock_init(&new_mpath->state_lock);
- init_timer(&new_mpath->timer);
-
hlist_add_head_rcu(&new_node->list, bucket);
if (atomic_inc_return(&tbl->entries) >=
MEAN_CHAIN_LEN * (tbl->hash_mask + 1))
@@ -664,7 +677,7 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata,
return -ENOTSUPP;

err = -ENOMEM;
- new_mpath = kzalloc(sizeof(struct mesh_path), GFP_ATOMIC);
+ new_mpath = mesh_path_new(sdata, dst, GFP_ATOMIC);
if (!new_mpath)
goto err_path_alloc;

@@ -672,17 +685,9 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata,
if (!new_node)
goto err_node_alloc;

- read_lock_bh(&sdata->u.mesh.pathtbl_resize_lock);
- memcpy(new_mpath->dst, dst, ETH_ALEN);
memcpy(new_mpath->mpp, mpp, ETH_ALEN);
- new_mpath->sdata = sdata;
- new_mpath->flags = 0;
- skb_queue_head_init(&new_mpath->frame_queue);
new_node->mpath = new_mpath;
- init_timer(&new_mpath->timer);
- new_mpath->exp_time = jiffies;
- spin_lock_init(&new_mpath->state_lock);
-
+ read_lock_bh(&sdata->u.mesh.pathtbl_resize_lock);
tbl = resize_dereference_mpp_paths(sdata);

hash_idx = mesh_table_hash(dst, tbl);
--
2.6.1


2016-02-29 01:04:08

by Bob Copeland

[permalink] [raw]
Subject: [PATCH 2/4] mac80211: mesh: don't hash sdata in mpath tables

Now that the sdata pointer is the same for all entries of a
path table, hashing it is pointless, so hash only the address.

Signed-off-by: Bob Copeland <[email protected]>
---
net/mac80211/mesh_pathtbl.c | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)

diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 0508b37b0471..fc3cc350df8c 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -177,12 +177,10 @@ errcopy:
return -ENOMEM;
}

-static u32 mesh_table_hash(const u8 *addr, struct ieee80211_sub_if_data *sdata,
- struct mesh_table *tbl)
+static u32 mesh_table_hash(const u8 *addr, struct mesh_table *tbl)
{
- /* Use last four bytes of hw addr and interface index as hash index */
- return jhash_2words(*(u32 *)(addr+2), sdata->dev->ifindex,
- tbl->hash_rnd) & tbl->hash_mask;
+ /* Use last four bytes of hw addr as hash index */
+ return jhash_1word(*(u32 *)(addr+2), tbl->hash_rnd) & tbl->hash_mask;
}


@@ -331,7 +329,7 @@ static struct mesh_path *mpath_lookup(struct mesh_table *tbl, const u8 *dst,
struct hlist_head *bucket;
struct mpath_node *node;

- bucket = &tbl->hash_buckets[mesh_table_hash(dst, sdata, tbl)];
+ bucket = &tbl->hash_buckets[mesh_table_hash(dst, tbl)];
hlist_for_each_entry_rcu(node, bucket, list) {
mpath = node->mpath;
if (ether_addr_equal(dst, mpath->dst)) {
@@ -538,7 +536,7 @@ struct mesh_path *mesh_path_add(struct ieee80211_sub_if_data *sdata,
read_lock_bh(&sdata->u.mesh.pathtbl_resize_lock);
tbl = resize_dereference_mesh_paths(sdata);

- hash_idx = mesh_table_hash(dst, sdata, tbl);
+ hash_idx = mesh_table_hash(dst, tbl);
bucket = &tbl->hash_buckets[hash_idx];

spin_lock(&tbl->hashwlock[hash_idx]);
@@ -687,7 +685,7 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata,

tbl = resize_dereference_mpp_paths(sdata);

- hash_idx = mesh_table_hash(dst, sdata, tbl);
+ hash_idx = mesh_table_hash(dst, tbl);
bucket = &tbl->hash_buckets[hash_idx];

spin_lock(&tbl->hashwlock[hash_idx]);
@@ -905,7 +903,7 @@ static int table_path_del(struct mesh_table __rcu *rcu_tbl,
int err = 0;

tbl = resize_dereference_paths(sdata, rcu_tbl);
- hash_idx = mesh_table_hash(addr, sdata, tbl);
+ hash_idx = mesh_table_hash(addr, tbl);
bucket = &tbl->hash_buckets[hash_idx];

spin_lock(&tbl->hashwlock[hash_idx]);
@@ -1107,7 +1105,7 @@ static int mesh_path_node_copy(struct hlist_node *p, struct mesh_table *newtbl)
node = hlist_entry(p, struct mpath_node, list);
mpath = node->mpath;
new_node->mpath = mpath;
- hash_idx = mesh_table_hash(mpath->dst, mpath->sdata, newtbl);
+ hash_idx = mesh_table_hash(mpath->dst, newtbl);
hlist_add_head(&new_node->list,
&newtbl->hash_buckets[hash_idx]);
return 0;
--
2.6.1


2016-02-29 01:04:09

by Bob Copeland

[permalink] [raw]
Subject: [PATCH 4/4] mac80211: mesh: embed known gates list in struct mesh_path

The mesh path table uses a struct mesh_node in its hlists in
order to support a resizable hash table: the mesh_node provides
an indirection to the actual mesh path so that two different
bucket lists can point to the same path entry.

However, for the known gates list, we don't need this indirection
because there is ever only one list. So we can just embed the
hlist_node in the mesh path itself, which simplifies things a bit
and saves a linear search whenever we need to find an item in
the list.

Signed-off-by: Bob Copeland <[email protected]>
---
net/mac80211/mesh.h | 1 +
net/mac80211/mesh_pathtbl.c | 100 +++++++++++++++++++-------------------------
2 files changed, 45 insertions(+), 56 deletions(-)

diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 601992b6cd8a..f3cc3917e048 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -105,6 +105,7 @@ enum mesh_deferred_task_flags {
struct mesh_path {
u8 dst[ETH_ALEN];
u8 mpp[ETH_ALEN]; /* used for MPP or MAP */
+ struct hlist_node gate_list;
struct ieee80211_sub_if_data *sdata;
struct sta_info __rcu *next_hop;
struct timer_list timer;
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 4794240e8f94..e4daf4b94eaf 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -119,10 +119,18 @@ static void mesh_table_free(struct mesh_table *tbl, bool free_leafs)
{
struct hlist_head *mesh_hash;
struct hlist_node *p, *q;
- struct mpath_node *gate;
+ struct mesh_path *gate;
int i;

mesh_hash = tbl->hash_buckets;
+ if (free_leafs) {
+ spin_lock_bh(&tbl->gates_lock);
+ hlist_for_each_entry_safe(gate, q,
+ tbl->known_gates, gate_list)
+ hlist_del(&gate->gate_list);
+ kfree(tbl->known_gates);
+ spin_unlock_bh(&tbl->gates_lock);
+ }
for (i = 0; i <= tbl->hash_mask; i++) {
spin_lock_bh(&tbl->hashwlock[i]);
hlist_for_each_safe(p, q, &mesh_hash[i]) {
@@ -131,16 +139,6 @@ static void mesh_table_free(struct mesh_table *tbl, bool free_leafs)
}
spin_unlock_bh(&tbl->hashwlock[i]);
}
- if (free_leafs) {
- spin_lock_bh(&tbl->gates_lock);
- hlist_for_each_entry_safe(gate, q,
- tbl->known_gates, list) {
- hlist_del(&gate->list);
- kfree(gate);
- }
- kfree(tbl->known_gates);
- spin_unlock_bh(&tbl->gates_lock);
- }

__mesh_table_free(tbl);
}
@@ -431,30 +429,26 @@ mpp_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx)
int mesh_path_add_gate(struct mesh_path *mpath)
{
struct mesh_table *tbl;
- struct mpath_node *gate, *new_gate;
int err;

rcu_read_lock();
tbl = rcu_dereference(mpath->sdata->u.mesh.mesh_paths);

- hlist_for_each_entry_rcu(gate, tbl->known_gates, list)
- if (gate->mpath == mpath) {
- err = -EEXIST;
- goto err_rcu;
- }
-
- new_gate = kzalloc(sizeof(struct mpath_node), GFP_ATOMIC);
- if (!new_gate) {
- err = -ENOMEM;
+ spin_lock_bh(&mpath->state_lock);
+ if (mpath->is_gate) {
+ err = -EEXIST;
+ spin_unlock_bh(&mpath->state_lock);
goto err_rcu;
}
-
mpath->is_gate = true;
mpath->sdata->u.mesh.num_gates++;
- new_gate->mpath = mpath;
- spin_lock_bh(&tbl->gates_lock);
- hlist_add_head_rcu(&new_gate->list, tbl->known_gates);
- spin_unlock_bh(&tbl->gates_lock);
+
+ spin_lock(&tbl->gates_lock);
+ hlist_add_head_rcu(&mpath->gate_list, tbl->known_gates);
+ spin_unlock(&tbl->gates_lock);
+
+ spin_unlock_bh(&mpath->state_lock);
+
mpath_dbg(mpath->sdata,
"Mesh path: Recorded new gate: %pM. %d known gates\n",
mpath->dst, mpath->sdata->u.mesh.num_gates);
@@ -468,28 +462,22 @@ err_rcu:
* mesh_gate_del - remove a mesh gate from the list of known gates
* @tbl: table which holds our list of known gates
* @mpath: gate mpath
- *
- * Locking: must be called inside rcu_read_lock() section
*/
static void mesh_gate_del(struct mesh_table *tbl, struct mesh_path *mpath)
{
- struct mpath_node *gate;
- struct hlist_node *q;
+ lockdep_assert_held(&mpath->state_lock);
+ if (!mpath->is_gate)
+ return;

- hlist_for_each_entry_safe(gate, q, tbl->known_gates, list) {
- if (gate->mpath != mpath)
- continue;
- spin_lock_bh(&tbl->gates_lock);
- hlist_del_rcu(&gate->list);
- kfree_rcu(gate, rcu);
- spin_unlock_bh(&tbl->gates_lock);
- mpath->sdata->u.mesh.num_gates--;
- mpath->is_gate = false;
- mpath_dbg(mpath->sdata,
- "Mesh path: Deleted gate: %pM. %d known gates\n",
- mpath->dst, mpath->sdata->u.mesh.num_gates);
- break;
- }
+ mpath->is_gate = false;
+ spin_lock_bh(&tbl->gates_lock);
+ hlist_del_rcu(&mpath->gate_list);
+ mpath->sdata->u.mesh.num_gates--;
+ spin_unlock_bh(&tbl->gates_lock);
+
+ mpath_dbg(mpath->sdata,
+ "Mesh path: Deleted gate: %pM. %d known gates\n",
+ mpath->dst, mpath->sdata->u.mesh.num_gates);
}

/**
@@ -781,13 +769,13 @@ static void __mesh_path_del(struct mesh_table *tbl, struct mpath_node *node)
struct mesh_path *mpath = node->mpath;
struct ieee80211_sub_if_data *sdata = node->mpath->sdata;

- spin_lock(&mpath->state_lock);
+ spin_lock_bh(&mpath->state_lock);
mpath->flags |= MESH_PATH_RESOLVING;
if (mpath->is_gate)
mesh_gate_del(tbl, mpath);
hlist_del_rcu(&node->list);
call_rcu(&node->rcu, mesh_path_node_reclaim);
- spin_unlock(&mpath->state_lock);
+ spin_unlock_bh(&mpath->state_lock);
atomic_dec(&sdata->u.mesh.mpaths);
atomic_dec(&tbl->entries);
}
@@ -999,7 +987,7 @@ int mesh_path_send_to_gates(struct mesh_path *mpath)
struct ieee80211_sub_if_data *sdata = mpath->sdata;
struct mesh_table *tbl;
struct mesh_path *from_mpath = mpath;
- struct mpath_node *gate = NULL;
+ struct mesh_path *gate = NULL;
bool copy = false;
struct hlist_head *known_gates;

@@ -1011,22 +999,22 @@ int mesh_path_send_to_gates(struct mesh_path *mpath)
if (!known_gates)
return -EHOSTUNREACH;

- hlist_for_each_entry_rcu(gate, known_gates, list) {
- if (gate->mpath->flags & MESH_PATH_ACTIVE) {
- mpath_dbg(sdata, "Forwarding to %pM\n", gate->mpath->dst);
- mesh_path_move_to_queue(gate->mpath, from_mpath, copy);
- from_mpath = gate->mpath;
+ hlist_for_each_entry_rcu(gate, known_gates, gate_list) {
+ if (gate->flags & MESH_PATH_ACTIVE) {
+ mpath_dbg(sdata, "Forwarding to %pM\n", gate->dst);
+ mesh_path_move_to_queue(gate, from_mpath, copy);
+ from_mpath = gate;
copy = true;
} else {
mpath_dbg(sdata,
"Not forwarding to %pM (flags %#x)\n",
- gate->mpath->dst, gate->mpath->flags);
+ gate->dst, gate->flags);
}
}

- hlist_for_each_entry_rcu(gate, known_gates, list) {
- mpath_dbg(sdata, "Sending to %pM\n", gate->mpath->dst);
- mesh_path_tx_pending(gate->mpath);
+ hlist_for_each_entry_rcu(gate, known_gates, gate_list) {
+ mpath_dbg(sdata, "Sending to %pM\n", gate->dst);
+ mesh_path_tx_pending(gate);
}

return (from_mpath == mpath) ? -EHOSTUNREACH : 0;
--
2.6.1


2016-03-03 15:18:59

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 1/4] mac80211: mesh: move path tables into if_mesh

On Sun, 2016-02-28 at 20:03 -0500, Bob Copeland wrote:
> The mesh path and mesh gate hashtables are global, containing
> all of the mpaths for every mesh interface, but the paths are
> all tied logically to a single interface.  The common case is
> just a single mesh interface, so optimize for that by moving
> the global hashtable into the per-interface struct.
>
> Doing so allows us to drop sdata pointer comparisons inside
> the lookups and also saves a few bytes of BSS and data.
>
All 4 applied.

johannes