mirror of
https://github.com/torvalds/linux.git
synced 2026-01-25 15:03:52 +08:00
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: 97246d6d21 ("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>
This commit is contained in:
committed by
Jakub Kicinski
parent
c1f4cb8a8d
commit
3ec5233049
@@ -183,7 +183,7 @@ int netvsc_vf_setxdp(struct net_device *vf_netdev, struct bpf_prog *prog)
|
||||
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);
|
||||
|
||||
@@ -2462,8 +2462,6 @@ static int netvsc_unregister_vf(struct net_device *vf_netdev)
|
||||
|
||||
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 *dev,
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -9968,6 +9968,7 @@ int netif_xdp_propagate(struct net_device *dev, struct netdev_bpf *bpf)
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user