90 lines
3.1 KiB
Diff
90 lines
3.1 KiB
Diff
From c3e0e5bd29d97f8e5663026e8c2f25e08f1c4544 Mon Sep 17 00:00:00 2001
|
|
From: Saurabh Sengar <ssengar@linux.microsoft.com>
|
|
Date: Thu, 29 May 2025 03:18:30 -0700
|
|
Subject: hv_netvsc: fix potential deadlock in netvsc_vf_setxdp()
|
|
|
|
The MANA driver's probe registers netdevice via the following call chain:
|
|
|
|
mana_probe()
|
|
register_netdev()
|
|
register_netdevice()
|
|
|
|
register_netdevice() calls notifier callback for netvsc driver,
|
|
holding the netdev mutex via netdev_lock_ops().
|
|
|
|
Further this netvsc notifier callback end up attempting to acquire the
|
|
same lock again in dev_xdp_propagate() leading to deadlock.
|
|
|
|
netvsc_netdev_event()
|
|
netvsc_vf_setxdp()
|
|
dev_xdp_propagate()
|
|
|
|
This deadlock was not observed so far because net_shaper_ops was never set,
|
|
and thus the lock was effectively a no-op in this case. Fix this by using
|
|
netif_xdp_propagate() instead of dev_xdp_propagate() to avoid recursive
|
|
locking in this path.
|
|
|
|
And, since no deadlock is observed on the other path which is via
|
|
netvsc_probe, add the lock exclusivly for that path.
|
|
|
|
Also, clean up the unregistration path by removing the unnecessary call to
|
|
netvsc_vf_setxdp(), since unregister_netdevice_many_notify() already
|
|
performs this cleanup via dev_xdp_uninstall().
|
|
|
|
Fixes: 97246d6d21c2 ("net: hold netdev instance lock during ndo_bpf")
|
|
Cc: stable@vger.kernel.org
|
|
Signed-off-by: Saurabh Sengar <ssengar@linux.microsoft.com>
|
|
Tested-by: Erni Sri Satya Vennela <ernis@linux.microsoft.com>
|
|
Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
|
|
Reviewed-by: Subbaraya Sundeep <sbhatta@marvell.com>
|
|
Link: https://patch.msgid.link/1748513910-23963-1-git-send-email-ssengar@linux.microsoft.com
|
|
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
|
---
|
|
drivers/net/hyperv/netvsc_bpf.c | 2 +-
|
|
drivers/net/hyperv/netvsc_drv.c | 4 ++--
|
|
net/core/dev.c | 1 +
|
|
3 files changed, 4 insertions(+), 3 deletions(-)
|
|
|
|
--- a/drivers/net/hyperv/netvsc_bpf.c
|
|
+++ b/drivers/net/hyperv/netvsc_bpf.c
|
|
@@ -183,7 +183,7 @@ int netvsc_vf_setxdp(struct net_device *
|
|
xdp.command = XDP_SETUP_PROG;
|
|
xdp.prog = prog;
|
|
|
|
- ret = dev_xdp_propagate(vf_netdev, &xdp);
|
|
+ ret = netif_xdp_propagate(vf_netdev, &xdp);
|
|
|
|
if (ret && prog)
|
|
bpf_prog_put(prog);
|
|
--- a/drivers/net/hyperv/netvsc_drv.c
|
|
+++ b/drivers/net/hyperv/netvsc_drv.c
|
|
@@ -2462,8 +2462,6 @@ static int netvsc_unregister_vf(struct n
|
|
|
|
netdev_info(ndev, "VF unregistering: %s\n", vf_netdev->name);
|
|
|
|
- netvsc_vf_setxdp(vf_netdev, NULL);
|
|
-
|
|
reinit_completion(&net_device_ctx->vf_add);
|
|
netdev_rx_handler_unregister(vf_netdev);
|
|
netdev_upper_dev_unlink(vf_netdev, ndev);
|
|
@@ -2631,7 +2629,9 @@ static int netvsc_probe(struct hv_device
|
|
continue;
|
|
|
|
netvsc_prepare_bonding(vf_netdev);
|
|
+ netdev_lock_ops(vf_netdev);
|
|
netvsc_register_vf(vf_netdev, VF_REG_IN_PROBE);
|
|
+ netdev_unlock_ops(vf_netdev);
|
|
__netvsc_vf_setup(net, vf_netdev);
|
|
break;
|
|
}
|
|
--- a/net/core/dev.c
|
|
+++ b/net/core/dev.c
|
|
@@ -9863,6 +9863,7 @@ int netif_xdp_propagate(struct net_devic
|
|
|
|
return dev->netdev_ops->ndo_bpf(dev, bpf);
|
|
}
|
|
+EXPORT_SYMBOL_GPL(netif_xdp_propagate);
|
|
|
|
u32 dev_xdp_prog_id(struct net_device *dev, enum bpf_xdp_mode mode)
|
|
{
|