Skip to content

Commit 7b83f52

Browse files
shemmingerdavem330
authored andcommitted
netvsc: make sure and unregister datapath
Go back to switching datapath directly in the notifier callback. Otherwise datapath might not get switched on unregister. No need for calling the NOTIFY_PEERS notifier since that is only for a gratitious ARP/ND packet; but that is not required with Hyper-V because both VF and synthetic NIC have the same MAC address. Reported-by: Vitaly Kuznetsov <[email protected]> Fixes: 0c19556 ("netvsc: transparent VF management") Signed-off-by: Stephen Hemminger <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent c99c287 commit 7b83f52

File tree

3 files changed

+28
-48
lines changed

3 files changed

+28
-48
lines changed

drivers/net/hyperv/hyperv_net.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -724,14 +724,11 @@ struct net_device_context {
724724
struct net_device __rcu *vf_netdev;
725725
struct netvsc_vf_pcpu_stats __percpu *vf_stats;
726726
struct work_struct vf_takeover;
727-
struct work_struct vf_notify;
728727

729728
/* 1: allocated, serial number is valid. 0: not allocated */
730729
u32 vf_alloc;
731730
/* Serial number of the VF to team with */
732731
u32 vf_serial;
733-
734-
bool datapath; /* 0 - synthetic, 1 - VF nic */
735732
};
736733

737734
/* Per channel data */

drivers/net/hyperv/netvsc.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,6 @@ void netvsc_switch_datapath(struct net_device *ndev, bool vf)
6060
sizeof(struct nvsp_message),
6161
(unsigned long)init_pkt,
6262
VM_PKT_DATA_INBAND, 0);
63-
64-
net_device_ctx->datapath = vf;
6563
}
6664

6765
static struct netvsc_device *alloc_net_device(void)

drivers/net/hyperv/netvsc_drv.c

Lines changed: 28 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1649,63 +1649,49 @@ static int netvsc_register_vf(struct net_device *vf_netdev)
16491649
return NOTIFY_OK;
16501650
}
16511651

1652-
/* Change datapath */
1653-
static void netvsc_vf_update(struct work_struct *w)
1652+
static int netvsc_vf_up(struct net_device *vf_netdev)
16541653
{
1655-
struct net_device_context *ndev_ctx
1656-
= container_of(w, struct net_device_context, vf_notify);
1657-
struct net_device *ndev = hv_get_drvdata(ndev_ctx->device_ctx);
1654+
struct net_device_context *net_device_ctx;
16581655
struct netvsc_device *netvsc_dev;
1659-
struct net_device *vf_netdev;
1660-
bool vf_is_up;
1661-
1662-
if (!rtnl_trylock()) {
1663-
schedule_work(w);
1664-
return;
1665-
}
1656+
struct net_device *ndev;
16661657

1667-
vf_netdev = rtnl_dereference(ndev_ctx->vf_netdev);
1668-
if (!vf_netdev)
1669-
goto unlock;
1658+
ndev = get_netvsc_byref(vf_netdev);
1659+
if (!ndev)
1660+
return NOTIFY_DONE;
16701661

1671-
netvsc_dev = rtnl_dereference(ndev_ctx->nvdev);
1662+
net_device_ctx = netdev_priv(ndev);
1663+
netvsc_dev = rtnl_dereference(net_device_ctx->nvdev);
16721664
if (!netvsc_dev)
1673-
goto unlock;
1674-
1675-
vf_is_up = netif_running(vf_netdev);
1676-
if (vf_is_up != ndev_ctx->datapath) {
1677-
if (vf_is_up) {
1678-
netdev_info(ndev, "VF up: %s\n", vf_netdev->name);
1679-
rndis_filter_open(netvsc_dev);
1680-
netvsc_switch_datapath(ndev, true);
1681-
netdev_info(ndev, "Data path switched to VF: %s\n",
1682-
vf_netdev->name);
1683-
} else {
1684-
netdev_info(ndev, "VF down: %s\n", vf_netdev->name);
1685-
netvsc_switch_datapath(ndev, false);
1686-
rndis_filter_close(netvsc_dev);
1687-
netdev_info(ndev, "Data path switched from VF: %s\n",
1688-
vf_netdev->name);
1689-
}
1665+
return NOTIFY_DONE;
16901666

1691-
/* Now notify peers through VF device. */
1692-
call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, ndev);
1693-
}
1694-
unlock:
1695-
rtnl_unlock();
1667+
/* Bump refcount when datapath is acvive - Why? */
1668+
rndis_filter_open(netvsc_dev);
1669+
1670+
/* notify the host to switch the data path. */
1671+
netvsc_switch_datapath(ndev, true);
1672+
netdev_info(ndev, "Data path switched to VF: %s\n", vf_netdev->name);
1673+
1674+
return NOTIFY_OK;
16961675
}
16971676

1698-
static int netvsc_vf_notify(struct net_device *vf_netdev)
1677+
static int netvsc_vf_down(struct net_device *vf_netdev)
16991678
{
17001679
struct net_device_context *net_device_ctx;
1680+
struct netvsc_device *netvsc_dev;
17011681
struct net_device *ndev;
17021682

17031683
ndev = get_netvsc_byref(vf_netdev);
17041684
if (!ndev)
17051685
return NOTIFY_DONE;
17061686

17071687
net_device_ctx = netdev_priv(ndev);
1708-
schedule_work(&net_device_ctx->vf_notify);
1688+
netvsc_dev = rtnl_dereference(net_device_ctx->nvdev);
1689+
if (!netvsc_dev)
1690+
return NOTIFY_DONE;
1691+
1692+
netvsc_switch_datapath(ndev, false);
1693+
netdev_info(ndev, "Data path switched from VF: %s\n", vf_netdev->name);
1694+
rndis_filter_close(netvsc_dev);
17091695

17101696
return NOTIFY_OK;
17111697
}
@@ -1721,7 +1707,6 @@ static int netvsc_unregister_vf(struct net_device *vf_netdev)
17211707

17221708
net_device_ctx = netdev_priv(ndev);
17231709
cancel_work_sync(&net_device_ctx->vf_takeover);
1724-
cancel_work_sync(&net_device_ctx->vf_notify);
17251710

17261711
netdev_info(ndev, "VF unregistering: %s\n", vf_netdev->name);
17271712

@@ -1764,7 +1749,6 @@ static int netvsc_probe(struct hv_device *dev,
17641749
spin_lock_init(&net_device_ctx->lock);
17651750
INIT_LIST_HEAD(&net_device_ctx->reconfig_events);
17661751
INIT_WORK(&net_device_ctx->vf_takeover, netvsc_vf_setup);
1767-
INIT_WORK(&net_device_ctx->vf_notify, netvsc_vf_update);
17681752

17691753
net_device_ctx->vf_stats
17701754
= netdev_alloc_pcpu_stats(struct netvsc_vf_pcpu_stats);
@@ -1915,8 +1899,9 @@ static int netvsc_netdev_event(struct notifier_block *this,
19151899
case NETDEV_UNREGISTER:
19161900
return netvsc_unregister_vf(event_dev);
19171901
case NETDEV_UP:
1902+
return netvsc_vf_up(event_dev);
19181903
case NETDEV_DOWN:
1919-
return netvsc_vf_notify(event_dev);
1904+
return netvsc_vf_down(event_dev);
19201905
default:
19211906
return NOTIFY_DONE;
19221907
}

0 commit comments

Comments
 (0)