Skip to content

Commit 54d4434

Browse files
author
Paolo Abeni
committed
Merge branch 'hv_netvsc-fix-race-of-netvsc-vf-register-and-slave-bit'
Haiyang Zhang says: ==================== hv_netvsc: fix race of netvsc, VF register, and slave bit There are some races between netvsc probe, set notifier, VF register, and slave bit setting. This patch set fixes them. ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
2 parents c0e2926 + c807d6c commit 54d4434

File tree

1 file changed

+45
-21
lines changed

1 file changed

+45
-21
lines changed

drivers/net/hyperv/netvsc_drv.c

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2206,9 +2206,6 @@ static int netvsc_vf_join(struct net_device *vf_netdev,
22062206
goto upper_link_failed;
22072207
}
22082208

2209-
/* set slave flag before open to prevent IPv6 addrconf */
2210-
vf_netdev->flags |= IFF_SLAVE;
2211-
22122209
schedule_delayed_work(&ndev_ctx->vf_takeover, VF_TAKEOVER_INT);
22132210

22142211
call_netdevice_notifiers(NETDEV_JOIN, vf_netdev);
@@ -2315,23 +2312,38 @@ static struct net_device *get_netvsc_byslot(const struct net_device *vf_netdev)
23152312

23162313
}
23172314

2318-
/* Fallback path to check synthetic vf with
2319-
* help of mac addr
2315+
/* Fallback path to check synthetic vf with help of mac addr.
2316+
* Because this function can be called before vf_netdev is
2317+
* initialized (NETDEV_POST_INIT) when its perm_addr has not been copied
2318+
* from dev_addr, also try to match to its dev_addr.
2319+
* Note: On Hyper-V and Azure, it's not possible to set a MAC address
2320+
* on a VF that matches to the MAC of a unrelated NETVSC device.
23202321
*/
23212322
list_for_each_entry(ndev_ctx, &netvsc_dev_list, list) {
23222323
ndev = hv_get_drvdata(ndev_ctx->device_ctx);
2323-
if (ether_addr_equal(vf_netdev->perm_addr, ndev->perm_addr)) {
2324-
netdev_notice(vf_netdev,
2325-
"falling back to mac addr based matching\n");
2324+
if (ether_addr_equal(vf_netdev->perm_addr, ndev->perm_addr) ||
2325+
ether_addr_equal(vf_netdev->dev_addr, ndev->perm_addr))
23262326
return ndev;
2327-
}
23282327
}
23292328

23302329
netdev_notice(vf_netdev,
23312330
"no netdev found for vf serial:%u\n", serial);
23322331
return NULL;
23332332
}
23342333

2334+
static int netvsc_prepare_bonding(struct net_device *vf_netdev)
2335+
{
2336+
struct net_device *ndev;
2337+
2338+
ndev = get_netvsc_byslot(vf_netdev);
2339+
if (!ndev)
2340+
return NOTIFY_DONE;
2341+
2342+
/* set slave flag before open to prevent IPv6 addrconf */
2343+
vf_netdev->flags |= IFF_SLAVE;
2344+
return NOTIFY_DONE;
2345+
}
2346+
23352347
static int netvsc_register_vf(struct net_device *vf_netdev)
23362348
{
23372349
struct net_device_context *net_device_ctx;
@@ -2531,25 +2543,30 @@ static int netvsc_probe(struct hv_device *dev,
25312543
goto devinfo_failed;
25322544
}
25332545

2534-
nvdev = rndis_filter_device_add(dev, device_info);
2535-
if (IS_ERR(nvdev)) {
2536-
ret = PTR_ERR(nvdev);
2537-
netdev_err(net, "unable to add netvsc device (ret %d)\n", ret);
2538-
goto rndis_failed;
2539-
}
2540-
2541-
eth_hw_addr_set(net, device_info->mac_adr);
2542-
25432546
/* We must get rtnl lock before scheduling nvdev->subchan_work,
25442547
* otherwise netvsc_subchan_work() can get rtnl lock first and wait
25452548
* all subchannels to show up, but that may not happen because
25462549
* netvsc_probe() can't get rtnl lock and as a result vmbus_onoffer()
25472550
* -> ... -> device_add() -> ... -> __device_attach() can't get
25482551
* the device lock, so all the subchannels can't be processed --
25492552
* finally netvsc_subchan_work() hangs forever.
2553+
*
2554+
* The rtnl lock also needs to be held before rndis_filter_device_add()
2555+
* which advertises nvsp_2_vsc_capability / sriov bit, and triggers
2556+
* VF NIC offering and registering. If VF NIC finished register_netdev()
2557+
* earlier it may cause name based config failure.
25502558
*/
25512559
rtnl_lock();
25522560

2561+
nvdev = rndis_filter_device_add(dev, device_info);
2562+
if (IS_ERR(nvdev)) {
2563+
ret = PTR_ERR(nvdev);
2564+
netdev_err(net, "unable to add netvsc device (ret %d)\n", ret);
2565+
goto rndis_failed;
2566+
}
2567+
2568+
eth_hw_addr_set(net, device_info->mac_adr);
2569+
25532570
if (nvdev->num_chn > 1)
25542571
schedule_work(&nvdev->subchan_work);
25552572

@@ -2586,9 +2603,9 @@ static int netvsc_probe(struct hv_device *dev,
25862603
return 0;
25872604

25882605
register_failed:
2589-
rtnl_unlock();
25902606
rndis_filter_device_remove(dev, nvdev);
25912607
rndis_failed:
2608+
rtnl_unlock();
25922609
netvsc_devinfo_put(device_info);
25932610
devinfo_failed:
25942611
free_percpu(net_device_ctx->vf_stats);
@@ -2753,6 +2770,8 @@ static int netvsc_netdev_event(struct notifier_block *this,
27532770
return NOTIFY_DONE;
27542771

27552772
switch (event) {
2773+
case NETDEV_POST_INIT:
2774+
return netvsc_prepare_bonding(event_dev);
27562775
case NETDEV_REGISTER:
27572776
return netvsc_register_vf(event_dev);
27582777
case NETDEV_UNREGISTER:
@@ -2788,12 +2807,17 @@ static int __init netvsc_drv_init(void)
27882807
}
27892808
netvsc_ring_bytes = ring_size * PAGE_SIZE;
27902809

2810+
register_netdevice_notifier(&netvsc_netdev_notifier);
2811+
27912812
ret = vmbus_driver_register(&netvsc_drv);
27922813
if (ret)
2793-
return ret;
2814+
goto err_vmbus_reg;
27942815

2795-
register_netdevice_notifier(&netvsc_netdev_notifier);
27962816
return 0;
2817+
2818+
err_vmbus_reg:
2819+
unregister_netdevice_notifier(&netvsc_netdev_notifier);
2820+
return ret;
27972821
}
27982822

27992823
MODULE_LICENSE("GPL");

0 commit comments

Comments
 (0)