Commit ec158f77 authored by Stephen Hemminger's avatar Stephen Hemminger Committed by David S. Miller

netvsc: allow driver to be removed even if VF is present

If VF is attached then can still allow netvsc driver module to
be removed. Just have to make sure and do the cleanup.

Also, avoid extra rtnl round trip when calling unregister.
Signed-off-by: default avatarStephen Hemminger <sthemmin@microsoft.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 9a0c48df
...@@ -1839,9 +1839,6 @@ static int netvsc_register_vf(struct net_device *vf_netdev) ...@@ -1839,9 +1839,6 @@ static int netvsc_register_vf(struct net_device *vf_netdev)
netdev_info(ndev, "VF registering: %s\n", vf_netdev->name); netdev_info(ndev, "VF registering: %s\n", vf_netdev->name);
/* Prevent this module from being unloaded while VF is registered */
try_module_get(THIS_MODULE);
dev_hold(vf_netdev); dev_hold(vf_netdev);
rcu_assign_pointer(net_device_ctx->vf_netdev, vf_netdev); rcu_assign_pointer(net_device_ctx->vf_netdev, vf_netdev);
return NOTIFY_OK; return NOTIFY_OK;
...@@ -1885,10 +1882,11 @@ static int netvsc_unregister_vf(struct net_device *vf_netdev) ...@@ -1885,10 +1882,11 @@ static int netvsc_unregister_vf(struct net_device *vf_netdev)
netdev_info(ndev, "VF unregistering: %s\n", vf_netdev->name); netdev_info(ndev, "VF unregistering: %s\n", vf_netdev->name);
netdev_rx_handler_unregister(vf_netdev);
netdev_upper_dev_unlink(vf_netdev, ndev); netdev_upper_dev_unlink(vf_netdev, ndev);
RCU_INIT_POINTER(net_device_ctx->vf_netdev, NULL); RCU_INIT_POINTER(net_device_ctx->vf_netdev, NULL);
dev_put(vf_netdev); dev_put(vf_netdev);
module_put(THIS_MODULE);
return NOTIFY_OK; return NOTIFY_OK;
} }
...@@ -1992,11 +1990,11 @@ static int netvsc_probe(struct hv_device *dev, ...@@ -1992,11 +1990,11 @@ static int netvsc_probe(struct hv_device *dev,
static int netvsc_remove(struct hv_device *dev) static int netvsc_remove(struct hv_device *dev)
{ {
struct net_device *net;
struct net_device_context *ndev_ctx; struct net_device_context *ndev_ctx;
struct net_device *vf_netdev;
struct net_device *net;
net = hv_get_drvdata(dev); net = hv_get_drvdata(dev);
if (net == NULL) { if (net == NULL) {
dev_err(&dev->device, "No net device to remove\n"); dev_err(&dev->device, "No net device to remove\n");
return 0; return 0;
...@@ -2013,12 +2011,15 @@ static int netvsc_remove(struct hv_device *dev) ...@@ -2013,12 +2011,15 @@ static int netvsc_remove(struct hv_device *dev)
* removed. Also blocks mtu and channel changes. * removed. Also blocks mtu and channel changes.
*/ */
rtnl_lock(); rtnl_lock();
vf_netdev = rtnl_dereference(ndev_ctx->vf_netdev);
if (vf_netdev)
netvsc_unregister_vf(vf_netdev);
rndis_filter_device_remove(dev, rndis_filter_device_remove(dev,
rtnl_dereference(ndev_ctx->nvdev)); rtnl_dereference(ndev_ctx->nvdev));
unregister_netdevice(net);
rtnl_unlock(); rtnl_unlock();
unregister_netdev(net);
hv_set_drvdata(dev, NULL); hv_set_drvdata(dev, NULL);
free_percpu(ndev_ctx->vf_stats); free_percpu(ndev_ctx->vf_stats);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment