| From foo@baz Tue Jan 26 21:35:03 PST 2016 |
| From: Sven Eckelmann <sven@narfation.org> |
| Date: Tue, 5 Jan 2016 12:06:25 +0100 |
| Subject: batman-adv: Drop immediate batadv_hard_iface free function |
| |
| From: Sven Eckelmann <sven@narfation.org> |
| |
| [ Upstream commit b4d922cfc9c08318eeb77d53b7633740e6b0efb0 ] |
| |
| It is not allowed to free the memory of an object which is part of a list |
| which is protected by rcu-read-side-critical sections without making sure |
| that no other context is accessing the object anymore. This usually happens |
| by removing the references to this object and then waiting until the rcu |
| grace period is over and no one (allowedly) accesses it anymore. |
| |
| But the _now functions ignore this completely. They free the object |
| directly even when a different context still tries to access it. This has |
| to be avoided and thus these functions must be removed and all functions |
| have to use batadv_hardif_free_ref. |
| |
| Fixes: 89652331c00f ("batman-adv: split tq information in neigh_node struct") |
| Signed-off-by: Sven Eckelmann <sven@narfation.org> |
| Signed-off-by: Marek Lindner <mareklindner@neomailbox.ch> |
| Signed-off-by: Antonio Quartulli <a@unstable.cc> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/batman-adv/hard-interface.h | 12 ------------ |
| net/batman-adv/originator.c | 14 +++++++------- |
| 2 files changed, 7 insertions(+), 19 deletions(-) |
| |
| --- a/net/batman-adv/hard-interface.h |
| +++ b/net/batman-adv/hard-interface.h |
| @@ -75,18 +75,6 @@ batadv_hardif_free_ref(struct batadv_har |
| call_rcu(&hard_iface->rcu, batadv_hardif_free_rcu); |
| } |
| |
| -/** |
| - * batadv_hardif_free_ref_now - decrement the hard interface refcounter and |
| - * possibly free it (without rcu callback) |
| - * @hard_iface: the hard interface to free |
| - */ |
| -static inline void |
| -batadv_hardif_free_ref_now(struct batadv_hard_iface *hard_iface) |
| -{ |
| - if (atomic_dec_and_test(&hard_iface->refcount)) |
| - batadv_hardif_free_rcu(&hard_iface->rcu); |
| -} |
| - |
| static inline struct batadv_hard_iface * |
| batadv_primary_if_get_selected(struct batadv_priv *bat_priv) |
| { |
| --- a/net/batman-adv/originator.c |
| +++ b/net/batman-adv/originator.c |
| @@ -189,16 +189,16 @@ void batadv_neigh_ifinfo_free_ref(struct |
| |
| /** |
| * batadv_neigh_node_free_rcu - free the neigh_node |
| - * @rcu: rcu pointer of the neigh_node |
| + * batadv_neigh_node_release - release neigh_node from lists and queue for |
| + * free after rcu grace period |
| + * @neigh_node: neigh neighbor to free |
| */ |
| -static void batadv_neigh_node_free_rcu(struct rcu_head *rcu) |
| +static void batadv_neigh_node_release(struct batadv_neigh_node *neigh_node) |
| { |
| struct hlist_node *node_tmp; |
| - struct batadv_neigh_node *neigh_node; |
| struct batadv_neigh_ifinfo *neigh_ifinfo; |
| struct batadv_algo_ops *bao; |
| |
| - neigh_node = container_of(rcu, struct batadv_neigh_node, rcu); |
| bao = neigh_node->orig_node->bat_priv->bat_algo_ops; |
| |
| hlist_for_each_entry_safe(neigh_ifinfo, node_tmp, |
| @@ -209,9 +209,9 @@ static void batadv_neigh_node_free_rcu(s |
| if (bao->bat_neigh_free) |
| bao->bat_neigh_free(neigh_node); |
| |
| - batadv_hardif_free_ref_now(neigh_node->if_incoming); |
| + batadv_hardif_free_ref(neigh_node->if_incoming); |
| |
| - kfree(neigh_node); |
| + kfree_rcu(neigh_node, rcu); |
| } |
| |
| /** |
| @@ -222,7 +222,7 @@ static void batadv_neigh_node_free_rcu(s |
| void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node) |
| { |
| if (atomic_dec_and_test(&neigh_node->refcount)) |
| - call_rcu(&neigh_node->rcu, batadv_neigh_node_free_rcu); |
| + batadv_neigh_node_release(neigh_node); |
| } |
| |
| /** |