summaryrefslogtreecommitdiffstats
path: root/net/batman-adv/originator.c
diff options
context:
space:
mode:
authorLinus Lüssing <linus.luessing@web.de>2013-04-15 21:43:29 +0800
committerAntonio Quartulli <ordex@autistici.org>2013-05-17 09:54:28 +0200
commit72822225bd41320a98f5d7cde38317766e18983f (patch)
treec1947655ac129d0a1aa3212755097baa9600bb3e /net/batman-adv/originator.c
parentb0ce3508b25ea6fa10ae3ca254de1d695b521702 (diff)
downloadlinux-72822225bd41320a98f5d7cde38317766e18983f.tar.gz
linux-72822225bd41320a98f5d7cde38317766e18983f.tar.bz2
linux-72822225bd41320a98f5d7cde38317766e18983f.zip
batman-adv: Fix rcu_barrier() miss due to double call_rcu() in TT code
rcu_barrier() only waits for the currently scheduled rcu functions to finish - it won't wait for any function scheduled via another call_rcu() within an rcu scheduled function. Unfortunately our batadv_tt_orig_list_entry_free_ref() does just that, via a batadv_orig_node_free_ref() call, leading to our rcu_barrier() call potentially missing such a batadv_orig_node_free_ref(). This patch fixes this issue by calling the batadv_orig_node_free_rcu() directly from the rcu callback, removing the unnecessary, additional call_rcu() layer here. Signed-off-by: Linus Lüssing <linus.luessing@web.de> Signed-off-by: Marek Lindner <lindner_marek@yahoo.de> Acked-by: Antonio Quartulli <ordex@autistici.org>
Diffstat (limited to 'net/batman-adv/originator.c')
-rw-r--r--net/batman-adv/originator.c16
1 files changed, 16 insertions, 0 deletions
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index 2f3452546636..fad1a2093e15 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -156,12 +156,28 @@ static void batadv_orig_node_free_rcu(struct rcu_head *rcu)
kfree(orig_node);
}
+/**
+ * batadv_orig_node_free_ref - decrement the orig node refcounter and possibly
+ * schedule an rcu callback for freeing it
+ * @orig_node: the orig node to free
+ */
void batadv_orig_node_free_ref(struct batadv_orig_node *orig_node)
{
if (atomic_dec_and_test(&orig_node->refcount))
call_rcu(&orig_node->rcu, batadv_orig_node_free_rcu);
}
+/**
+ * batadv_orig_node_free_ref_now - decrement the orig node refcounter and
+ * possibly free it (without rcu callback)
+ * @orig_node: the orig node to free
+ */
+void batadv_orig_node_free_ref_now(struct batadv_orig_node *orig_node)
+{
+ if (atomic_dec_and_test(&orig_node->refcount))
+ batadv_orig_node_free_rcu(&orig_node->rcu);
+}
+
void batadv_originator_free(struct batadv_priv *bat_priv)
{
struct batadv_hashtable *hash = bat_priv->orig_hash;