]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
netvsc: uses RCU instead of removal flag
authorstephen hemminger <stephen@networkplumber.org>
Wed, 22 Mar 2017 21:51:01 +0000 (14:51 -0700)
committerDavid S. Miller <davem@davemloft.net>
Thu, 23 Mar 2017 02:38:56 +0000 (19:38 -0700)
It is cleaner to use RCU protected pointer (nvdev_ctx->nvdev)
to indicate device is in removed state, rather than having a separate
boolean flag. By using the pointer the context can be checked
by static checkers and dynamic lockdep.

Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/hyperv/hyperv_net.h
drivers/net/hyperv/netvsc.c
drivers/net/hyperv/netvsc_drv.c

index 0ade21f95d7183d09c6ff9c58f15266c05295db8..907f55960ba8e54440c210c7ade03800cfead497 100644 (file)
@@ -708,9 +708,6 @@ struct net_device_context {
        u32 speed;
        struct netvsc_ethtool_stats eth_stats;
 
-       /* the device is going away */
-       bool start_remove;
-
        /* State to manage the associated VF interface. */
        struct net_device __rcu *vf_netdev;
 
index ab9118d620abba410fc071850b1f11bd14fac129..1f17d948f9b0356e1673fafe5968e8c75ca10f2d 100644 (file)
@@ -605,7 +605,6 @@ static void netvsc_send_tx_complete(struct netvsc_device *net_device,
 {
        struct sk_buff *skb = (struct sk_buff *)(unsigned long)desc->trans_id;
        struct net_device *ndev = hv_get_drvdata(device);
-       struct net_device_context *net_device_ctx = netdev_priv(ndev);
        struct vmbus_channel *channel = device->channel;
        u16 q_idx = 0;
        int queue_sends;
@@ -639,7 +638,6 @@ static void netvsc_send_tx_complete(struct netvsc_device *net_device,
                wake_up(&net_device->wait_drain);
 
        if (netif_tx_queue_stopped(netdev_get_tx_queue(ndev, q_idx)) &&
-           !net_device_ctx->start_remove &&
            (hv_ringbuf_avail_percent(&channel->outbound) > RING_AVAIL_PERCENT_HIWATER ||
             queue_sends < 1))
                netif_tx_wake_queue(netdev_get_tx_queue(ndev, q_idx));
@@ -1326,8 +1324,6 @@ int netvsc_device_add(struct hv_device *device,
        /* Writing nvdev pointer unlocks netvsc_send(), make sure chn_table is
         * populated.
         */
-       wmb();
-
        rcu_assign_pointer(net_device_ctx->nvdev, net_device);
 
        /* Connect with the NetVsp */
index d8a70d07eeecd0dd967cfb884ffbe30ac6483fca..eb7ae79d47bb4b1619e4c148392ef8cbe7c71352 100644 (file)
@@ -760,7 +760,7 @@ static int netvsc_set_channels(struct net_device *net,
        if (count > net->num_tx_queues || count > net->num_rx_queues)
                return -EINVAL;
 
-       if (net_device_ctx->start_remove || !nvdev || nvdev->destroy)
+       if (!nvdev || nvdev->destroy)
                return -ENODEV;
 
        if (nvdev->nvsp_version < NVSP_PROTOCOL_VERSION_5)
@@ -776,7 +776,6 @@ static int netvsc_set_channels(struct net_device *net,
                        return ret;
        }
 
-       net_device_ctx->start_remove = true;
        rndis_filter_device_remove(dev, nvdev);
 
        ret = netvsc_set_queues(net, dev, count);
@@ -785,8 +784,6 @@ static int netvsc_set_channels(struct net_device *net,
        else
                netvsc_set_queues(net, dev, nvdev->num_chn);
 
-       net_device_ctx->start_remove = false;
-
        if (was_running)
                ret = netvsc_open(net);
 
@@ -860,7 +857,7 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu)
        bool was_running;
        int ret;
 
-       if (ndevctx->start_remove || !nvdev || nvdev->destroy)
+       if (!nvdev || nvdev->destroy)
                return -ENODEV;
 
        was_running = netif_running(ndev);
@@ -875,7 +872,6 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu)
        device_info.num_chn = nvdev->num_chn;
        device_info.max_num_vrss_chns = nvdev->num_chn;
 
-       ndevctx->start_remove = true;
        rndis_filter_device_remove(hdev, nvdev);
 
        /* 'nvdev' has been freed in rndis_filter_device_remove() ->
@@ -888,8 +884,6 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu)
 
        rndis_filter_device_add(hdev, &device_info);
 
-       ndevctx->start_remove = false;
-
        if (was_running)
                ret = netvsc_open(ndev);
 
@@ -1245,10 +1239,10 @@ static void netvsc_link_change(struct work_struct *w)
        unsigned long flags, next_reconfig, delay;
 
        rtnl_lock();
-       if (ndev_ctx->start_remove)
+       net_device = rtnl_dereference(ndev_ctx->nvdev);
+       if (!net_device)
                goto out_unlock;
 
-       net_device = rtnl_dereference(ndev_ctx->nvdev);
        rdev = net_device->extension;
 
        next_reconfig = ndev_ctx->last_reconfig + LINKCHANGE_INT;
@@ -1509,8 +1503,6 @@ static int netvsc_probe(struct hv_device *dev,
 
        hv_set_drvdata(dev, net);
 
-       net_device_ctx->start_remove = false;
-
        INIT_DELAYED_WORK(&net_device_ctx->dwork, netvsc_link_change);
        INIT_WORK(&net_device_ctx->work, do_set_multicast);
 
@@ -1579,26 +1571,20 @@ static int netvsc_remove(struct hv_device *dev)
 
        ndev_ctx = netdev_priv(net);
 
-       /* Avoid racing with netvsc_change_mtu()/netvsc_set_channels()
-        * removing the device.
-        */
-       rtnl_lock();
-       ndev_ctx->start_remove = true;
-       rtnl_unlock();
+       netif_device_detach(net);
 
        cancel_delayed_work_sync(&ndev_ctx->dwork);
        cancel_work_sync(&ndev_ctx->work);
 
-       /* Stop outbound asap */
-       netif_tx_disable(net);
-
-       unregister_netdev(net);
-
        /*
         * Call to the vsc driver to let it know that the device is being
-        * removed
+        * removed. Also blocks mtu and channel changes.
         */
+       rtnl_lock();
        rndis_filter_device_remove(dev, ndev_ctx->nvdev);
+       rtnl_unlock();
+
+       unregister_netdev(net);
 
        hv_set_drvdata(dev, NULL);