summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--net/mac80211/mesh.h3
-rw-r--r--net/mac80211/mesh_hwmp.c4
-rw-r--r--net/mac80211/mesh_pathtbl.c33
3 files changed, 25 insertions, 15 deletions
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index cc6854db156e..e1415c952e9c 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -32,6 +32,8 @@
* @MESH_PATH_RESOLVED: the mesh path can has been resolved
* @MESH_PATH_REQ_QUEUED: there is an unsent path request for this destination
* already queued up, waiting for the discovery process to start.
+ * @MESH_PATH_DELETED: the mesh path has been deleted and should no longer
+ * be used
*
* MESH_PATH_RESOLVED is used by the mesh path timer to
* decide when to stop or cancel the mesh path discovery.
@@ -43,6 +45,7 @@ enum mesh_path_flags {
MESH_PATH_FIXED = BIT(3),
MESH_PATH_RESOLVED = BIT(4),
MESH_PATH_REQ_QUEUED = BIT(5),
+ MESH_PATH_DELETED = BIT(6),
};
/**
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 5b6aec1a0630..2748cf627ee3 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -1012,6 +1012,10 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
goto enddiscovery;
spin_lock_bh(&mpath->state_lock);
+ if (mpath->flags & MESH_PATH_DELETED) {
+ spin_unlock_bh(&mpath->state_lock);
+ goto enddiscovery;
+ }
mpath->flags &= ~MESH_PATH_REQ_QUEUED;
if (preq_node->flags & PREQ_Q_F_START) {
if (mpath->flags & MESH_PATH_RESOLVING) {
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 7455397f8c3b..1c9412a29ca3 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -18,6 +18,8 @@
#include "ieee80211_i.h"
#include "mesh.h"
+static void mesh_path_free_rcu(struct mesh_table *tbl, struct mesh_path *mpath);
+
static u32 mesh_table_hash(const void *addr, u32 len, u32 seed)
{
/* Use last four bytes of hw addr as hash index */
@@ -40,18 +42,12 @@ static inline bool mpath_expired(struct mesh_path *mpath)
!(mpath->flags & MESH_PATH_FIXED);
}
-static void mesh_path_reclaim(struct rcu_head *rp)
-{
- struct mesh_path *mpath = container_of(rp, struct mesh_path, rcu);
-
- del_timer_sync(&mpath->timer);
- kfree(mpath);
-}
-
-static void mesh_path_rht_free(void *ptr, void *unused_arg)
+static void mesh_path_rht_free(void *ptr, void *tblptr)
{
struct mesh_path *mpath = ptr;
- call_rcu(&mpath->rcu, mesh_path_reclaim);
+ struct mesh_table *tbl = tblptr;
+
+ mesh_path_free_rcu(tbl, mpath);
}
static struct mesh_table *mesh_table_alloc(void)
@@ -77,7 +73,7 @@ static struct mesh_table *mesh_table_alloc(void)
static void mesh_table_free(struct mesh_table *tbl)
{
rhashtable_free_and_destroy(&tbl->rhead,
- mesh_path_rht_free, NULL);
+ mesh_path_rht_free, tbl);
kfree(tbl);
}
@@ -551,18 +547,25 @@ out:
rhashtable_walk_exit(&iter);
}
-static void __mesh_path_del(struct mesh_table *tbl, struct mesh_path *mpath)
+static void mesh_path_free_rcu(struct mesh_table *tbl,
+ struct mesh_path *mpath)
{
struct ieee80211_sub_if_data *sdata = mpath->sdata;
- rhashtable_remove_fast(&tbl->rhead, &mpath->rhash, mesh_rht_params);
spin_lock_bh(&mpath->state_lock);
- mpath->flags |= MESH_PATH_RESOLVING;
+ mpath->flags |= MESH_PATH_RESOLVING | MESH_PATH_DELETED;
mesh_gate_del(tbl, mpath);
- call_rcu(&mpath->rcu, mesh_path_reclaim);
spin_unlock_bh(&mpath->state_lock);
+ del_timer_sync(&mpath->timer);
atomic_dec(&sdata->u.mesh.mpaths);
atomic_dec(&tbl->entries);
+ kfree_rcu(mpath, rcu);
+}
+
+static void __mesh_path_del(struct mesh_table *tbl, struct mesh_path *mpath)
+{
+ rhashtable_remove_fast(&tbl->rhead, &mpath->rhash, mesh_rht_params);
+ mesh_path_free_rcu(tbl, mpath);
}
/**