summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorIdo Schimmel <idosch@mellanox.com>2016-01-27 15:16:43 +0100
committerSasha Levin <sasha.levin@oracle.com>2016-03-04 10:25:47 -0500
commit4c62ddf7e39943b356157b4c2196a71825c8328c (patch)
treee26c8c9dfb9ce21455679d78655a35578569bd28 /net
parent257a04782588b4b97ac005a044f85947f792be44 (diff)
switchdev: Require RTNL mutex to be held when sending FDB notifications
[ Upstream commit 4f2c6ae5c64c353fb1b0425e4747e5603feadba1 ] When switchdev drivers process FDB notifications from the underlying device they resolve the netdev to which the entry points to and notify the bridge using the switchdev notifier. However, since the RTNL mutex is not held there is nothing preventing the netdev from disappearing in the middle, which will cause br_switchdev_event() to dereference a non-existing netdev. Make switchdev drivers hold the lock at the beginning of the notification processing session and release it once it ends, after notifying the bridge. Also, remove switchdev_mutex and fdb_lock, as they are no longer needed when RTNL mutex is held. Fixes: 03bf0c281234 ("switchdev: introduce switchdev notifier") Signed-off-by: Ido Schimmel <idosch@mellanox.com> Signed-off-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
Diffstat (limited to 'net')
-rw-r--r--net/bridge/br.c3
-rw-r--r--net/switchdev/switchdev.c15
2 files changed, 9 insertions, 9 deletions
diff --git a/net/bridge/br.c b/net/bridge/br.c
index 02c24cf63c34..c72e01cf09d0 100644
--- a/net/bridge/br.c
+++ b/net/bridge/br.c
@@ -121,6 +121,7 @@ static struct notifier_block br_device_notifier = {
.notifier_call = br_device_event
};
+/* called with RTNL */
static int br_netdev_switch_event(struct notifier_block *unused,
unsigned long event, void *ptr)
{
@@ -130,7 +131,6 @@ static int br_netdev_switch_event(struct notifier_block *unused,
struct netdev_switch_notifier_fdb_info *fdb_info;
int err = NOTIFY_DONE;
- rtnl_lock();
p = br_port_get_rtnl(dev);
if (!p)
goto out;
@@ -155,7 +155,6 @@ static int br_netdev_switch_event(struct notifier_block *unused,
}
out:
- rtnl_unlock();
return err;
}
diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c
index 055453d48668..a8dbe8001e46 100644
--- a/net/switchdev/switchdev.c
+++ b/net/switchdev/switchdev.c
@@ -15,6 +15,7 @@
#include <linux/mutex.h>
#include <linux/notifier.h>
#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
#include <net/ip_fib.h>
#include <net/switchdev.h>
@@ -64,7 +65,6 @@ int netdev_switch_port_stp_update(struct net_device *dev, u8 state)
}
EXPORT_SYMBOL_GPL(netdev_switch_port_stp_update);
-static DEFINE_MUTEX(netdev_switch_mutex);
static RAW_NOTIFIER_HEAD(netdev_switch_notif_chain);
/**
@@ -79,9 +79,9 @@ int register_netdev_switch_notifier(struct notifier_block *nb)
{
int err;
- mutex_lock(&netdev_switch_mutex);
+ rtnl_lock();
err = raw_notifier_chain_register(&netdev_switch_notif_chain, nb);
- mutex_unlock(&netdev_switch_mutex);
+ rtnl_unlock();
return err;
}
EXPORT_SYMBOL_GPL(register_netdev_switch_notifier);
@@ -97,9 +97,9 @@ int unregister_netdev_switch_notifier(struct notifier_block *nb)
{
int err;
- mutex_lock(&netdev_switch_mutex);
+ rtnl_lock();
err = raw_notifier_chain_unregister(&netdev_switch_notif_chain, nb);
- mutex_unlock(&netdev_switch_mutex);
+ rtnl_unlock();
return err;
}
EXPORT_SYMBOL_GPL(unregister_netdev_switch_notifier);
@@ -113,16 +113,17 @@ EXPORT_SYMBOL_GPL(unregister_netdev_switch_notifier);
* Call all network notifier blocks. This should be called by driver
* when it needs to propagate hardware event.
* Return values are same as for atomic_notifier_call_chain().
+ * rtnl_lock must be held.
*/
int call_netdev_switch_notifiers(unsigned long val, struct net_device *dev,
struct netdev_switch_notifier_info *info)
{
int err;
+ ASSERT_RTNL();
+
info->dev = dev;
- mutex_lock(&netdev_switch_mutex);
err = raw_notifier_call_chain(&netdev_switch_notif_chain, val, info);
- mutex_unlock(&netdev_switch_mutex);
return err;
}
EXPORT_SYMBOL_GPL(call_netdev_switch_notifiers);