batman-adv: Remove unnecessary hardif_list_lock

hardif_list_lock is unneccessary because we already ensure that no
multiple admin operations can take place through rtnl_lock.
hardif_list_lock only adds additional overhead and complexity.

Critical functions now check whether they are called with rtnl_lock
using ASSERT_RTNL.

It indirectly fixes the problem that orig_hash_del_if() expects that
only one interface is deleted from hardif_list at a time, but
hardif_remove_interfaces() removes all at once and then calls
orig_hash_del_if().

Reported-by: Linus Lüssing <linus.luessing@web.de>
Signed-off-by: Sven Eckelmann <sven@narfation.org>
This commit is contained in:
Sven Eckelmann 2011-05-03 11:51:38 +02:00
parent 61906ae86d
commit c3caf5196c
4 changed files with 13 additions and 24 deletions

View File

@ -502,7 +502,9 @@ static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr,
rtnl_unlock(); rtnl_unlock();
} }
rtnl_lock();
ret = hardif_enable_interface(hard_iface, buff); ret = hardif_enable_interface(hard_iface, buff);
rtnl_unlock();
out: out:
hardif_free_ref(hard_iface); hardif_free_ref(hard_iface);

View File

@ -31,9 +31,6 @@
#include <linux/if_arp.h> #include <linux/if_arp.h>
/* protect update critical side of hardif_list - but not the content */
static DEFINE_SPINLOCK(hardif_list_lock);
static int batman_skb_recv(struct sk_buff *skb, static int batman_skb_recv(struct sk_buff *skb,
struct net_device *dev, struct net_device *dev,
@ -136,7 +133,7 @@ static void primary_if_select(struct bat_priv *bat_priv,
struct hard_iface *curr_hard_iface; struct hard_iface *curr_hard_iface;
struct batman_packet *batman_packet; struct batman_packet *batman_packet;
spin_lock_bh(&hardif_list_lock); ASSERT_RTNL();
if (new_hard_iface && !atomic_inc_not_zero(&new_hard_iface->refcount)) if (new_hard_iface && !atomic_inc_not_zero(&new_hard_iface->refcount))
new_hard_iface = NULL; new_hard_iface = NULL;
@ -148,7 +145,7 @@ static void primary_if_select(struct bat_priv *bat_priv,
hardif_free_ref(curr_hard_iface); hardif_free_ref(curr_hard_iface);
if (!new_hard_iface) if (!new_hard_iface)
goto out; return;
batman_packet = (struct batman_packet *)(new_hard_iface->packet_buff); batman_packet = (struct batman_packet *)(new_hard_iface->packet_buff);
batman_packet->flags = PRIMARIES_FIRST_HOP; batman_packet->flags = PRIMARIES_FIRST_HOP;
@ -161,9 +158,6 @@ static void primary_if_select(struct bat_priv *bat_priv,
* our new primary interface * our new primary interface
*/ */
atomic_set(&bat_priv->hna_local_changed, 1); atomic_set(&bat_priv->hna_local_changed, 1);
out:
spin_unlock_bh(&hardif_list_lock);
} }
static bool hardif_is_iface_up(struct hard_iface *hard_iface) static bool hardif_is_iface_up(struct hard_iface *hard_iface)
@ -456,6 +450,8 @@ static struct hard_iface *hardif_add_interface(struct net_device *net_dev)
struct hard_iface *hard_iface; struct hard_iface *hard_iface;
int ret; int ret;
ASSERT_RTNL();
ret = is_valid_iface(net_dev); ret = is_valid_iface(net_dev);
if (ret != 1) if (ret != 1)
goto out; goto out;
@ -482,10 +478,7 @@ static struct hard_iface *hardif_add_interface(struct net_device *net_dev)
atomic_set(&hard_iface->refcount, 2); atomic_set(&hard_iface->refcount, 2);
check_known_mac_addr(hard_iface->net_dev); check_known_mac_addr(hard_iface->net_dev);
spin_lock(&hardif_list_lock);
list_add_tail_rcu(&hard_iface->list, &hardif_list); list_add_tail_rcu(&hard_iface->list, &hardif_list);
spin_unlock(&hardif_list_lock);
return hard_iface; return hard_iface;
@ -499,6 +492,8 @@ out:
static void hardif_remove_interface(struct hard_iface *hard_iface) static void hardif_remove_interface(struct hard_iface *hard_iface)
{ {
ASSERT_RTNL();
/* first deactivate interface */ /* first deactivate interface */
if (hard_iface->if_status != IF_NOT_IN_USE) if (hard_iface->if_status != IF_NOT_IN_USE)
hardif_disable_interface(hard_iface); hardif_disable_interface(hard_iface);
@ -514,20 +509,11 @@ static void hardif_remove_interface(struct hard_iface *hard_iface)
void hardif_remove_interfaces(void) void hardif_remove_interfaces(void)
{ {
struct hard_iface *hard_iface, *hard_iface_tmp; struct hard_iface *hard_iface, *hard_iface_tmp;
struct list_head if_queue;
INIT_LIST_HEAD(&if_queue); rtnl_lock();
spin_lock(&hardif_list_lock);
list_for_each_entry_safe(hard_iface, hard_iface_tmp, list_for_each_entry_safe(hard_iface, hard_iface_tmp,
&hardif_list, list) { &hardif_list, list) {
list_del_rcu(&hard_iface->list); list_del_rcu(&hard_iface->list);
list_add_tail(&hard_iface->list, &if_queue);
}
spin_unlock(&hardif_list_lock);
rtnl_lock();
list_for_each_entry_safe(hard_iface, hard_iface_tmp, &if_queue, list) {
hardif_remove_interface(hard_iface); hardif_remove_interface(hard_iface);
} }
rtnl_unlock(); rtnl_unlock();
@ -556,9 +542,7 @@ static int hard_if_event(struct notifier_block *this,
hardif_deactivate_interface(hard_iface); hardif_deactivate_interface(hard_iface);
break; break;
case NETDEV_UNREGISTER: case NETDEV_UNREGISTER:
spin_lock(&hardif_list_lock);
list_del_rcu(&hard_iface->list); list_del_rcu(&hard_iface->list);
spin_unlock(&hardif_list_lock);
hardif_remove_interface(hard_iface); hardif_remove_interface(hard_iface);
break; break;

View File

@ -33,6 +33,9 @@
#include "vis.h" #include "vis.h"
#include "hash.h" #include "hash.h"
/* List manipulations on hardif_list have to be rtnl_lock()'ed,
* list traversals just rcu-locked */
struct list_head hardif_list; struct list_head hardif_list;
unsigned char broadcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; unsigned char broadcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};

View File

@ -819,7 +819,7 @@ struct net_device *softif_create(char *name)
goto out; goto out;
} }
ret = register_netdev(soft_iface); ret = register_netdevice(soft_iface);
if (ret < 0) { if (ret < 0) {
pr_err("Unable to register the batman interface '%s': %i\n", pr_err("Unable to register the batman interface '%s': %i\n",
name, ret); name, ret);