aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorSven Eckelmann <sven@narfation.org>2011-01-28 12:34:07 -0500
committerSven Eckelmann <sven@narfation.org>2011-01-30 04:32:08 -0500
commit1181e1daace88018b2ff66592aa10a4791d705ff (patch)
tree7cea108c5063c61b74904070396c98c4b1bf29fa /net
parentdda9fc6b2c59f056e7a2b313b8423b14a4df25a9 (diff)
batman-adv: Make vis info stack traversal threadsafe
The batman-adv vis server has to a stack which stores all information about packets which should be send later. This stack is protected with a spinlock that is used to prevent concurrent write access to it. The send_vis_packets function has to take all elements from the stack and send them to other hosts over the primary interface. The send will be initiated without the lock which protects the stack. The implementation using list_for_each_entry_safe has the problem that it stores the next element as "safe ptr" to allow the deletion of the current element in the list. The list may be modified during the unlock/lock pair in the loop body which may make the safe pointer not pointing to correct next element. It is safer to remove and use the first element from the stack until no elements are available. This does not need reduntant information which would have to be validated each time the lock was removed. Reported-by: Russell Senior <russell@personaltelco.net> Signed-off-by: Sven Eckelmann <sven@narfation.org>
Diffstat (limited to 'net')
-rw-r--r--net/batman-adv/vis.c7
1 files changed, 4 insertions, 3 deletions
diff --git a/net/batman-adv/vis.c b/net/batman-adv/vis.c
index 988296cdf7c5..de1022cacaf7 100644
--- a/net/batman-adv/vis.c
+++ b/net/batman-adv/vis.c
@@ -816,7 +816,7 @@ static void send_vis_packets(struct work_struct *work)
816 container_of(work, struct delayed_work, work); 816 container_of(work, struct delayed_work, work);
817 struct bat_priv *bat_priv = 817 struct bat_priv *bat_priv =
818 container_of(delayed_work, struct bat_priv, vis_work); 818 container_of(delayed_work, struct bat_priv, vis_work);
819 struct vis_info *info, *temp; 819 struct vis_info *info;
820 820
821 spin_lock_bh(&bat_priv->vis_hash_lock); 821 spin_lock_bh(&bat_priv->vis_hash_lock);
822 purge_vis_packets(bat_priv); 822 purge_vis_packets(bat_priv);
@@ -826,8 +826,9 @@ static void send_vis_packets(struct work_struct *work)
826 send_list_add(bat_priv, bat_priv->my_vis_info); 826 send_list_add(bat_priv, bat_priv->my_vis_info);
827 } 827 }
828 828
829 list_for_each_entry_safe(info, temp, &bat_priv->vis_send_list, 829 while (!list_empty(&bat_priv->vis_send_list)) {
830 send_list) { 830 info = list_first_entry(&bat_priv->vis_send_list,
831 typeof(*info), send_list);
831 832
832 kref_get(&info->refcount); 833 kref_get(&info->refcount);
833 spin_unlock_bh(&bat_priv->vis_hash_lock); 834 spin_unlock_bh(&bat_priv->vis_hash_lock);