Skip to content

Commit eb2703b

Browse files
haiyangzvijay-suman
authored andcommitted
hv_netvsc: Fix panic during namespace deletion with VF
[ Upstream commit 33caa20 ] The existing code move the VF NIC to new namespace when NETDEV_REGISTER is received on netvsc NIC. During deletion of the namespace, default_device_exit_batch() >> default_device_exit_net() is called. When netvsc NIC is moved back and registered to the default namespace, it automatically brings VF NIC back to the default namespace. This will cause the default_device_exit_net() >> for_each_netdev_safe loop unable to detect the list end, and hit NULL ptr: [ 231.449420] mana 7870:00:00.0 enP30832s1: Moved VF to namespace with: eth0 [ 231.449656] BUG: kernel NULL pointer dereference, address: 0000000000000010 [ 231.450246] #PF: supervisor read access in kernel mode [ 231.450579] #PF: error_code(0x0000) - not-present page [ 231.450916] PGD 17b8a8067 P4D 0 [ 231.451163] Oops: Oops: 0000 [#1] SMP NOPTI [ 231.451450] CPU: 82 UID: 0 PID: 1394 Comm: kworker/u768:1 Not tainted 6.16.0-rc4+ #3 VOLUNTARY [ 231.452042] Hardware name: Microsoft Corporation Virtual Machine/Virtual Machine, BIOS Hyper-V UEFI Release v4.1 11/21/2024 [ 231.452692] Workqueue: netns cleanup_net [ 231.452947] RIP: 0010:default_device_exit_batch+0x16c/0x3f0 [ 231.453326] Code: c0 0c f5 b3 e8 d5 db fe ff 48 85 c0 74 15 48 c7 c2 f8 fd ca b2 be 10 00 00 00 48 8d 7d c0 e8 7b 77 25 00 49 8b 86 28 01 00 00 <48> 8b 50 10 4c 8b 2a 4c 8d 62 f0 49 83 ed 10 4c 39 e0 0f 84 d6 00 [ 231.454294] RSP: 0018:ff75fc7c9bf9fd00 EFLAGS: 00010246 [ 231.454610] RAX: 0000000000000000 RBX: 0000000000000002 RCX: 61c8864680b583eb [ 231.455094] RDX: ff1fa9f71462d800 RSI: ff75fc7c9bf9fd38 RDI: 0000000030766564 [ 231.455686] RBP: ff75fc7c9bf9fd78 R08: 0000000000000000 R09: 0000000000000000 [ 231.456126] R10: 0000000000000001 R11: 0000000000000004 R12: ff1fa9f70088e340 [ 231.456621] R13: ff1fa9f70088e340 R14: ffffffffb3f50c20 R15: ff1fa9f7103e6340 [ 231.457161] FS: 0000000000000000(0000) GS:ff1faa6783a08000(0000) knlGS:0000000000000000 [ 231.457707] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 231.458031] CR2: 0000000000000010 CR3: 0000000179ab2006 CR4: 0000000000b73ef0 [ 231.458434] Call Trace: [ 231.458600] <TASK> [ 231.458777] ops_undo_list+0x100/0x220 [ 231.459015] cleanup_net+0x1b8/0x300 [ 231.459285] process_one_work+0x184/0x340 To fix it, move the ns change to a workqueue, and take rtnl_lock to avoid changing the netdev list when default_device_exit_net() is using it. Cc: [email protected] Fixes: 4c26280 ("hv_netvsc: Fix VF namespace also in synthetic NIC NETDEV_REGISTER event") Signed-off-by: Haiyang Zhang <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]> Signed-off-by: Sasha Levin <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]> (cherry picked from commit 3467c4ebb334658c6fcf3eabb64a6e8b2135e010) Signed-off-by: Vijayendra Suman <[email protected]>
1 parent 366c0c8 commit eb2703b

File tree

2 files changed

+31
-1
lines changed

2 files changed

+31
-1
lines changed

drivers/net/hyperv/hyperv_net.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,6 +1032,7 @@ struct net_device_context {
10321032
struct net_device __rcu *vf_netdev;
10331033
struct netvsc_vf_pcpu_stats __percpu *vf_stats;
10341034
struct delayed_work vf_takeover;
1035+
struct delayed_work vfns_work;
10351036

10361037
/* 1: allocated, serial number is valid. 0: not allocated */
10371038
u32 vf_alloc;
@@ -1046,6 +1047,8 @@ struct net_device_context {
10461047
struct netvsc_device_info *saved_netvsc_dev_info;
10471048
};
10481049

1050+
void netvsc_vfns_work(struct work_struct *w);
1051+
10491052
/* Per channel data */
10501053
struct netvsc_channel {
10511054
struct vmbus_channel *channel;

drivers/net/hyperv/netvsc_drv.c

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2565,6 +2565,7 @@ static int netvsc_probe(struct hv_device *dev,
25652565
spin_lock_init(&net_device_ctx->lock);
25662566
INIT_LIST_HEAD(&net_device_ctx->reconfig_events);
25672567
INIT_DELAYED_WORK(&net_device_ctx->vf_takeover, netvsc_vf_setup);
2568+
INIT_DELAYED_WORK(&net_device_ctx->vfns_work, netvsc_vfns_work);
25682569

25692570
net_device_ctx->vf_stats
25702571
= netdev_alloc_pcpu_stats(struct netvsc_vf_pcpu_stats);
@@ -2703,6 +2704,8 @@ static int netvsc_remove(struct hv_device *dev)
27032704
cancel_delayed_work_sync(&ndev_ctx->dwork);
27042705

27052706
rtnl_lock();
2707+
cancel_delayed_work_sync(&ndev_ctx->vfns_work);
2708+
27062709
nvdev = rtnl_dereference(ndev_ctx->nvdev);
27072710
if (nvdev) {
27082711
cancel_work_sync(&nvdev->subchan_work);
@@ -2745,6 +2748,7 @@ static int netvsc_suspend(struct hv_device *dev)
27452748
cancel_delayed_work_sync(&ndev_ctx->dwork);
27462749

27472750
rtnl_lock();
2751+
cancel_delayed_work_sync(&ndev_ctx->vfns_work);
27482752

27492753
nvdev = rtnl_dereference(ndev_ctx->nvdev);
27502754
if (nvdev == NULL) {
@@ -2838,6 +2842,27 @@ static void netvsc_event_set_vf_ns(struct net_device *ndev)
28382842
}
28392843
}
28402844

2845+
void netvsc_vfns_work(struct work_struct *w)
2846+
{
2847+
struct net_device_context *ndev_ctx =
2848+
container_of(w, struct net_device_context, vfns_work.work);
2849+
struct net_device *ndev;
2850+
2851+
if (!rtnl_trylock()) {
2852+
schedule_delayed_work(&ndev_ctx->vfns_work, 1);
2853+
return;
2854+
}
2855+
2856+
ndev = hv_get_drvdata(ndev_ctx->device_ctx);
2857+
if (!ndev)
2858+
goto out;
2859+
2860+
netvsc_event_set_vf_ns(ndev);
2861+
2862+
out:
2863+
rtnl_unlock();
2864+
}
2865+
28412866
/*
28422867
* On Hyper-V, every VF interface is matched with a corresponding
28432868
* synthetic interface. The synthetic interface is presented first
@@ -2848,10 +2873,12 @@ static int netvsc_netdev_event(struct notifier_block *this,
28482873
unsigned long event, void *ptr)
28492874
{
28502875
struct net_device *event_dev = netdev_notifier_info_to_dev(ptr);
2876+
struct net_device_context *ndev_ctx;
28512877
int ret = 0;
28522878

28532879
if (event_dev->netdev_ops == &device_ops && event == NETDEV_REGISTER) {
2854-
netvsc_event_set_vf_ns(event_dev);
2880+
ndev_ctx = netdev_priv(event_dev);
2881+
schedule_delayed_work(&ndev_ctx->vfns_work, 0);
28552882
return NOTIFY_DONE;
28562883
}
28572884

0 commit comments

Comments
 (0)