The following commit has been merged in the merge/master branch: commit 2783bc2a5ac88e0f7cefa71c324bd86c542d4ae5 Author: Sven Eckelmann sven@narfation.org Date: Thu Jan 14 15:28:19 2016 +0100
batman-adv: Avoid recursive call_rcu for batadv_bla_claim
The batadv_claim_free_ref function uses call_rcu to delay the free of the batadv_bla_claim object until no (already started) rcu_read_lock is enabled anymore. This makes sure that no context is still trying to access the object which should be removed. But batadv_bla_claim also contains a reference to backbone_gw which must be removed.
The reference drop of backbone_gw was done in the call_rcu function batadv_claim_free_rcu but should actually be done in the batadv_claim_release function to avoid nested call_rcus. This is important because rcu_barrier (e.g. batadv_softif_free or batadv_exit) will not detect the inner call_rcu as relevant for its execution. Otherwise this barrier will most likely be inserted in the queue before the callback of the first call_rcu was executed. The caller of rcu_barrier will therefore continue to run before the inner call_rcu callback finished.
Fixes: a9ce0dc43e2c ("batman-adv: add basic bridge loop avoidance code") Signed-off-by: Sven Eckelmann sven@narfation.org Acked-by: Simon Wunderlich sw@simonwunderlich.de Signed-off-by: Marek Lindner mareklindner@neomailbox.ch
diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c index d9b034a..6e951dd 100644 --- a/net/batman-adv/bridge_loop_avoidance.c +++ b/net/batman-adv/bridge_loop_avoidance.c @@ -154,17 +154,14 @@ batadv_backbone_gw_free_ref(struct batadv_bla_backbone_gw *backbone_gw) }
/** - * batadv_claim_free_rcu - finally deinitialize the claim - * @rcu: rcu pointer within the claim structure + * batadv_claim_release - release claim from lists and queue for free after rcu + * grace period + * @claim: claim to be free'd */ -static void batadv_claim_free_rcu(struct rcu_head *rcu) +static void batadv_claim_release(struct batadv_bla_claim *claim) { - struct batadv_bla_claim *claim; - - claim = container_of(rcu, struct batadv_bla_claim, rcu); - batadv_backbone_gw_free_ref(claim->backbone_gw); - kfree(claim); + kfree_rcu(claim, rcu); }
/** @@ -174,7 +171,7 @@ static void batadv_claim_free_rcu(struct rcu_head *rcu) static void batadv_claim_free_ref(struct batadv_bla_claim *claim) { if (atomic_dec_and_test(&claim->refcount)) - call_rcu(&claim->rcu, batadv_claim_free_rcu); + batadv_claim_release(claim); }
/**