*/
void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta)
{
- __sta_info_get(sta);
- if (mpath->next_hop)
- sta_info_put(mpath->next_hop);
- mpath->next_hop = sta;
+ rcu_assign_pointer(mpath->next_hop, sta);
}
/**
* mesh_path_lookup_by_idx - look up a path in the mesh path table by its index
* @idx: index
- * @dev: local interface
+ * @dev: local interface, or NULL for all entries
*
* Returns: pointer to the mesh path structure, or NULL if not found.
*
int i;
int j = 0;
- for_each_mesh_entry(mesh_paths, p, node, i)
+ for_each_mesh_entry(mesh_paths, p, node, i) {
+ if (dev && node->mpath->dev != dev)
+ continue;
if (j++ == idx) {
if (MPATH_EXPIRED(node->mpath)) {
spin_lock_bh(&node->mpath->state_lock);
}
return node->mpath;
}
+ }
return NULL;
}
if (atomic_add_unless(&sdata->u.sta.mpaths, 1, MESH_MAX_MPATHS) == 0)
return -ENOSPC;
- read_lock(&pathtbl_resize_lock);
-
new_mpath = kzalloc(sizeof(struct mesh_path), GFP_KERNEL);
if (!new_mpath) {
atomic_dec(&sdata->u.sta.mpaths);
err = -ENOMEM;
goto endadd2;
}
+ new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL);
+ if (!new_node) {
+ kfree(new_mpath);
+ atomic_dec(&sdata->u.sta.mpaths);
+ err = -ENOMEM;
+ goto endadd2;
+ }
+
+ read_lock(&pathtbl_resize_lock);
memcpy(new_mpath->dst, dst, ETH_ALEN);
new_mpath->dev = dev;
new_mpath->flags = 0;
skb_queue_head_init(&new_mpath->frame_queue);
- new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL);
new_node->mpath = new_mpath;
new_mpath->timer.data = (unsigned long) new_mpath;
new_mpath->timer.function = mesh_path_timer;
endadd:
spin_unlock(&mesh_paths->hashwlock[hash_idx]);
-endadd2:
read_unlock(&pathtbl_resize_lock);
if (!err && grow) {
struct mesh_table *oldtbl, *newtbl;
return -ENOMEM;
}
rcu_assign_pointer(mesh_paths, newtbl);
+ write_unlock(&pathtbl_resize_lock);
+
synchronize_rcu();
mesh_table_free(oldtbl, false);
- write_unlock(&pathtbl_resize_lock);
}
+endadd2:
return err;
}
struct mesh_path *mpath;
struct mpath_node *node;
struct hlist_node *p;
- struct net_device *dev = sta->dev;
+ struct net_device *dev = sta->sdata->dev;
int i;
rcu_read_lock();
*
* @sta - mesh peer to match
*
- * RCU notes: this function is called when a mesh plink transitions from ESTAB
- * to any other state, since ESTAB state is the only one that allows path
- * creation. This will happen before the sta can be freed (since we hold
- * a reference to it) so any reader in a rcu read block will be protected
- * against the plink dissapearing.
+ * RCU notes: this function is called when a mesh plink transitions from
+ * PLINK_ESTAB to any other state, since PLINK_ESTAB state is the only one that
+ * allows path creation. This will happen before the sta can be freed (because
+ * sta_info_destroy() calls this) so any reader in a rcu read block will be
+ * protected against the plink disappearing.
*/
void mesh_path_flush_by_nexthop(struct sta_info *sta)
{
struct mpath_node *node = container_of(rp, struct mpath_node, rcu);
struct ieee80211_sub_if_data *sdata =
IEEE80211_DEV_TO_SUB_IF(node->mpath->dev);
- if (node->mpath->next_hop)
- sta_info_put(node->mpath->next_hop);
+
+ del_timer_sync(&node->mpath->timer);
atomic_dec(&sdata->u.sta.mpaths);
kfree(node->mpath);
kfree(node);
* @dev: local interface
*
* Returns: 0 if succesful
- *
- * State: if the path is being resolved, the deletion will be postponed until
- * the path resolution completes or times out.
*/
int mesh_path_del(u8 *addr, struct net_device *dev)
{
if (mpath->dev == dev &&
memcmp(addr, mpath->dst, ETH_ALEN) == 0) {
spin_lock_bh(&mpath->state_lock);
- if (mpath->flags & MESH_PATH_RESOLVING) {
- mpath->flags |= MESH_PATH_DELETE;
- } else {
- mpath->flags |= MESH_PATH_RESOLVING;
- hlist_del_rcu(&node->list);
- call_rcu(&node->rcu, mesh_path_node_reclaim);
- atomic_dec(&mesh_paths->entries);
- }
+ mpath->flags |= MESH_PATH_RESOLVING;
+ hlist_del_rcu(&node->list);
+ call_rcu(&node->rcu, mesh_path_node_reclaim);
+ atomic_dec(&mesh_paths->entries);
spin_unlock_bh(&mpath->state_lock);
goto enddel;
}