Re: [added to the 4.1 stable tree] switchdev: Require RTNL mutex to be held when sending FDB notifications

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Sasha,

Wed, Mar 02, 2016 at 10:23:52PM IST, sasha.levin@xxxxxxxxxx wrote:
>From: Ido Schimmel <idosch@xxxxxxxxxxxx>
>
>This patch has been added to the 4.1 stable tree. If you have any
>objections, please let us know.
>
>===============
>
>[ 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.

You removed the fdb_lock bits from the commit below since they aren't
present in kernel 4.1. Can you remove it from the description as well?
Should probably be:

"Also, remove switchdev_mutex, as it's no longer needed when RTNL mutex
is held."

Thanks, Ido.

>
>Fixes: 03bf0c281234 ("switchdev: introduce switchdev notifier")
>Signed-off-by: Ido Schimmel <idosch@xxxxxxxxxxxx>
>Signed-off-by: Jiri Pirko <jiri@xxxxxxxxxxxx>
>Signed-off-by: David S. Miller <davem@xxxxxxxxxxxxx>
>Signed-off-by: Sasha Levin <sasha.levin@xxxxxxxxxx>
>---
> drivers/net/ethernet/rocker/rocker.c |  2 ++
> net/bridge/br.c                      |  3 +--
> net/switchdev/switchdev.c            | 15 ++++++++-------
> 3 files changed, 11 insertions(+), 9 deletions(-)
>
>diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c
>index 73b6fc2..4fedf7f 100644
>--- a/drivers/net/ethernet/rocker/rocker.c
>+++ b/drivers/net/ethernet/rocker/rocker.c
>@@ -3384,12 +3384,14 @@ static void rocker_port_fdb_learn_work(struct work_struct *work)
> 	info.addr = lw->addr;
> 	info.vid = lw->vid;
> 
>+	rtnl_lock();
> 	if (learned && removing)
> 		call_netdev_switch_notifiers(NETDEV_SWITCH_FDB_DEL,
> 					     lw->dev, &info.info);
> 	else if (learned && !removing)
> 		call_netdev_switch_notifiers(NETDEV_SWITCH_FDB_ADD,
> 					     lw->dev, &info.info);
>+	rtnl_unlock();
> 
> 	kfree(work);
> }
>diff --git a/net/bridge/br.c b/net/bridge/br.c
>index 02c24cf..c72e01c 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 055453d..a8dbe80 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);
>-- 
>2.5.0
>
--
To unsubscribe from this list: send the line "unsubscribe stable" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]