Skip to content

Commit

Permalink
batman-adv: Fix consistency of update route messages
Browse files Browse the repository at this point in the history
The debug messages of _batadv_update_route were printed before the actual
route change is done. At this point it is not really known which
curr_router will be replaced. Thus the messages could print the wrong
operation.

Printing the debug messages after the operation was done avoids this
problem.

Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Marek Lindner <mareklindner@neomailbox.ch>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
  • Loading branch information
Sven Eckelmann authored and Simon Wunderlich committed Aug 9, 2016
1 parent 4d7de48 commit b5dcbad
Showing 1 changed file with 17 additions and 26 deletions.
43 changes: 17 additions & 26 deletions net/batman-adv/routing.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,23 @@ static void _batadv_update_route(struct batadv_priv *bat_priv,
if (!orig_ifinfo)
return;

rcu_read_lock();
curr_router = rcu_dereference(orig_ifinfo->router);
if (curr_router && !kref_get_unless_zero(&curr_router->refcount))
curr_router = NULL;
rcu_read_unlock();
spin_lock_bh(&orig_node->neigh_list_lock);
/* curr_router used earlier may not be the current orig_ifinfo->router
* anymore because it was dereferenced outside of the neigh_list_lock
* protected region. After the new best neighbor has replace the current
* best neighbor the reference counter needs to decrease. Consequently,
* the code needs to ensure the curr_router variable contains a pointer
* to the replaced best neighbor.
*/
curr_router = rcu_dereference_protected(orig_ifinfo->router, true);

/* increase refcount of new best neighbor */
if (neigh_node)
kref_get(&neigh_node->refcount);

rcu_assign_pointer(orig_ifinfo->router, neigh_node);
spin_unlock_bh(&orig_node->neigh_list_lock);
batadv_orig_ifinfo_put(orig_ifinfo);

/* route deleted */
if ((curr_router) && (!neigh_node)) {
Expand All @@ -100,27 +112,6 @@ static void _batadv_update_route(struct batadv_priv *bat_priv,
curr_router->addr);
}

if (curr_router)
batadv_neigh_node_put(curr_router);

spin_lock_bh(&orig_node->neigh_list_lock);
/* curr_router used earlier may not be the current orig_ifinfo->router
* anymore because it was dereferenced outside of the neigh_list_lock
* protected region. After the new best neighbor has replace the current
* best neighbor the reference counter needs to decrease. Consequently,
* the code needs to ensure the curr_router variable contains a pointer
* to the replaced best neighbor.
*/
curr_router = rcu_dereference_protected(orig_ifinfo->router, true);

/* increase refcount of new best neighbor */
if (neigh_node)
kref_get(&neigh_node->refcount);

rcu_assign_pointer(orig_ifinfo->router, neigh_node);
spin_unlock_bh(&orig_node->neigh_list_lock);
batadv_orig_ifinfo_put(orig_ifinfo);

/* decrease refcount of previous best neighbor */
if (curr_router)
batadv_neigh_node_put(curr_router);
Expand Down

0 comments on commit b5dcbad

Please sign in to comment.