@@ -2192,6 +2192,7 @@ static int netvsc_vf_join(struct net_device *vf_netdev,
struct net_device *ndev, int context)
{
struct net_device_context *ndev_ctx = netdev_priv(ndev);
+ struct nd_lock *nd_lock, *nd_lock2;
int ret;
ret = netdev_rx_handler_register(vf_netdev,
@@ -2203,8 +2204,12 @@ static int netvsc_vf_join(struct net_device *vf_netdev,
goto rx_handler_failed;
}
+ double_lock_netdev(ndev, &nd_lock, vf_netdev, &nd_lock2);
+ nd_lock_transfer_devices(&nd_lock, &nd_lock2);
+
ret = netdev_master_upper_dev_link(vf_netdev, ndev,
NULL, NULL, NULL);
+ double_unlock_netdev(nd_lock, nd_lock2);
if (ret != 0) {
netdev_err(vf_netdev,
"can not set master device %s (err = %d)\n",
@@ -2797,6 +2802,20 @@ static struct hv_driver netvsc_drv = {
},
};
+static void call_netvsc_register(struct net_device *dev)
+{
+ unsigned long event;
+
+ rtnl_lock();
+ netvsc_prepare_bonding(dev);
+ netvsc_register_vf(dev, VF_REG_IN_NOTIFIER);
+ event = NETDEV_GOING_DOWN;
+ if (netif_running(dev))
+ event = NETDEV_CHANGE;
+ netvsc_vf_changed(dev, event);
+ rtnl_unlock();
+}
+
/*
* On Hyper-V, every VF interface is matched with a corresponding
* synthetic interface. The synthetic interface is presented first
@@ -2814,10 +2833,10 @@ static int netvsc_netdev_event(struct notifier_block *this,
return NOTIFY_DONE;
switch (event) {
- case NETDEV_POST_INIT:
- return netvsc_prepare_bonding(event_dev);
case NETDEV_REGISTER:
- return netvsc_register_vf(event_dev, VF_REG_IN_NOTIFIER);
+ return schedule_delayed_event(event_dev,
+ call_netvsc_register);
+ return NOTIFY_DONE;
case NETDEV_UNREGISTER:
return netvsc_unregister_vf(event_dev);
case NETDEV_UP:
We don't want to do that from netvsc_netdev_event() since we want to make netdevice notifiers be called under nd_lock in future. Also see comments in patch introducing schedule_delayed_event() Signed-off-by: Kirill Tkhai <tkhai@ya.ru> --- drivers/net/hyperv/netvsc_drv.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-)