[linux-next] LinuxNextTracking branch, master, updated. next-20160114

batman at open-mesh.org batman at open-mesh.org
Fri Jan 15 00:15:44 CET 2016


The following commit has been merged in the master branch:
commit bab7c6c3deac70966a3000402c0ea6d0c20edd15
Author: Sven Eckelmann <sven at narfation.org>
Date:   Tue Jan 5 12:06:17 2016 +0100

    batman-adv: Fix list removal of batadv_hardif_neigh_node
    
    The neigh_list with batadv_hardif_neigh_node objects is accessed with only
    rcu_read_lock in batadv_hardif_neigh_get and batadv_iv_neigh_print. Thus it
    is not allowed to kfree the object before the rcu grace period ends (which
    may still protects context accessing this object). Therefore the object has
    first to be removed from the neigh_list and then it has either wait with
    synchronize_rcu or call_rcu till the grace period ends before it can be
    freed.
    
    Fixes: cef63419f7db ("batman-adv: add list of unique single hop neighbors per hard-interface")
    Signed-off-by: Sven Eckelmann <sven at narfation.org>
    Signed-off-by: Marek Lindner <mareklindner at neomailbox.ch>
    Signed-off-by: Antonio Quartulli <a at unstable.cc>

diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index 3c782a33..ae6d18c 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -211,10 +211,6 @@ static void batadv_hardif_neigh_free_rcu(struct rcu_head *rcu)
 
 	hardif_neigh = container_of(rcu, struct batadv_hardif_neigh_node, rcu);
 
-	spin_lock_bh(&hardif_neigh->if_incoming->neigh_list_lock);
-	hlist_del_init_rcu(&hardif_neigh->list);
-	spin_unlock_bh(&hardif_neigh->if_incoming->neigh_list_lock);
-
 	batadv_hardif_free_ref_now(hardif_neigh->if_incoming);
 	kfree(hardif_neigh);
 }
@@ -227,8 +223,13 @@ static void batadv_hardif_neigh_free_rcu(struct rcu_head *rcu)
 static void
 batadv_hardif_neigh_free_now(struct batadv_hardif_neigh_node *hardif_neigh)
 {
-	if (atomic_dec_and_test(&hardif_neigh->refcount))
+	if (atomic_dec_and_test(&hardif_neigh->refcount)) {
+		spin_lock_bh(&hardif_neigh->if_incoming->neigh_list_lock);
+		hlist_del_init_rcu(&hardif_neigh->list);
+		spin_unlock_bh(&hardif_neigh->if_incoming->neigh_list_lock);
+
 		batadv_hardif_neigh_free_rcu(&hardif_neigh->rcu);
+	}
 }
 
 /**
@@ -238,8 +239,13 @@ batadv_hardif_neigh_free_now(struct batadv_hardif_neigh_node *hardif_neigh)
  */
 void batadv_hardif_neigh_free_ref(struct batadv_hardif_neigh_node *hardif_neigh)
 {
-	if (atomic_dec_and_test(&hardif_neigh->refcount))
+	if (atomic_dec_and_test(&hardif_neigh->refcount)) {
+		spin_lock_bh(&hardif_neigh->if_incoming->neigh_list_lock);
+		hlist_del_init_rcu(&hardif_neigh->list);
+		spin_unlock_bh(&hardif_neigh->if_incoming->neigh_list_lock);
+
 		call_rcu(&hardif_neigh->rcu, batadv_hardif_neigh_free_rcu);
+	}
 }
 
 /**

-- 
LinuxNextTracking


More information about the linux-merge mailing list