[8/9] batman-adv: count election of gateway as reference
Commit Message
We reference the gw_nodes as curr_gw for each bat_priv. They are tracked
inside a rcu protected list gw_list which may free the memory after it
gets removed from the list. Nevertheless it could still be referenced by
curr_gw and access to it would result in a kernel oops.
Signed-off-by: Sven Eckelmann <sven.eckelmann@gmx.de>
---
batman-adv/gateway_client.c | 22 +++++++++++++++++++---
1 files changed, 19 insertions(+), 3 deletions(-)
@@ -51,13 +51,18 @@ void *gw_get_selected(struct bat_priv *bat_priv)
void gw_deselect(struct bat_priv *bat_priv)
{
+ struct gw_node *gw_node = bat_priv->curr_gw;
+
bat_priv->curr_gw = NULL;
+
+ if (gw_node)
+ gw_node_put(gw_node);
}
void gw_election(struct bat_priv *bat_priv)
{
struct hlist_node *node;
- struct gw_node *gw_node, *curr_gw_tmp = NULL;
+ struct gw_node *gw_node, *curr_gw_tmp = NULL, *old_gw_node = NULL;
uint8_t max_tq = 0;
uint32_t max_gw_factor = 0, tmp_gw_factor = 0;
int down, up;
@@ -131,7 +136,6 @@ void gw_election(struct bat_priv *bat_priv)
if (tmp_gw_factor > max_gw_factor)
max_gw_factor = tmp_gw_factor;
}
- rcu_read_unlock();
if (bat_priv->curr_gw != curr_gw_tmp) {
if ((bat_priv->curr_gw) && (!curr_gw_tmp))
@@ -153,8 +157,17 @@ void gw_election(struct bat_priv *bat_priv)
curr_gw_tmp->orig_node->gw_flags,
curr_gw_tmp->orig_node->router->tq_avg);
+ old_gw_node = bat_priv->curr_gw;
+ if (curr_gw_tmp)
+ gw_node_hold(curr_gw_tmp);
+
bat_priv->curr_gw = curr_gw_tmp;
}
+
+ rcu_read_unlock();
+
+ if (old_gw_node)
+ gw_node_put(old_gw_node);
}
void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node)
@@ -258,8 +271,11 @@ void gw_node_update(struct bat_priv *bat_priv,
"Gateway %pM removed from gateway list\n",
orig_node->orig);
- if (gw_node == bat_priv->curr_gw)
+ if (gw_node == bat_priv->curr_gw) {
+ rcu_read_unlock();
gw_deselect(bat_priv);
+ return;
+ }
}
rcu_read_unlock();