Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'netvsc-vf-cleanups'

Stephen Hemminger says:

====================
netvsc: transparent VF related cleanups

The first gets rid of unnecessary ref counting, and second
allows removing hv_netvsc driver even if VF present.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+16 -39
+16 -39
drivers/net/hyperv/netvsc_drv.c
··· 1839 1839 1840 1840 netdev_info(ndev, "VF registering: %s\n", vf_netdev->name); 1841 1841 1842 - /* Prevent this module from being unloaded while VF is registered */ 1843 - try_module_get(THIS_MODULE); 1844 - 1845 1842 dev_hold(vf_netdev); 1846 1843 rcu_assign_pointer(net_device_ctx->vf_netdev, vf_netdev); 1847 1844 return NOTIFY_OK; 1848 1845 } 1849 1846 1850 - static int netvsc_vf_up(struct net_device *vf_netdev) 1847 + /* VF up/down change detected, schedule to change data path */ 1848 + static int netvsc_vf_changed(struct net_device *vf_netdev) 1851 1849 { 1852 1850 struct net_device_context *net_device_ctx; 1853 1851 struct netvsc_device *netvsc_dev; 1854 1852 struct net_device *ndev; 1853 + bool vf_is_up = netif_running(vf_netdev); 1855 1854 1856 1855 ndev = get_netvsc_byref(vf_netdev); 1857 1856 if (!ndev) ··· 1861 1862 if (!netvsc_dev) 1862 1863 return NOTIFY_DONE; 1863 1864 1864 - /* Bump refcount when datapath is acvive - Why? */ 1865 - rndis_filter_open(netvsc_dev); 1866 - 1867 - /* notify the host to switch the data path. */ 1868 - netvsc_switch_datapath(ndev, true); 1869 - netdev_info(ndev, "Data path switched to VF: %s\n", vf_netdev->name); 1870 - 1871 - return NOTIFY_OK; 1872 - } 1873 - 1874 - static int netvsc_vf_down(struct net_device *vf_netdev) 1875 - { 1876 - struct net_device_context *net_device_ctx; 1877 - struct netvsc_device *netvsc_dev; 1878 - struct net_device *ndev; 1879 - 1880 - ndev = get_netvsc_byref(vf_netdev); 1881 - if (!ndev) 1882 - return NOTIFY_DONE; 1883 - 1884 - net_device_ctx = netdev_priv(ndev); 1885 - netvsc_dev = rtnl_dereference(net_device_ctx->nvdev); 1886 - if (!netvsc_dev) 1887 - return NOTIFY_DONE; 1888 - 1889 - netvsc_switch_datapath(ndev, false); 1890 - netdev_info(ndev, "Data path switched from VF: %s\n", vf_netdev->name); 1891 - rndis_filter_close(netvsc_dev); 1865 + netvsc_switch_datapath(ndev, vf_is_up); 1866 + netdev_info(ndev, "Data path switched %s VF: %s\n", 1867 + vf_is_up ? "to" : "from", vf_netdev->name); 1892 1868 1893 1869 return NOTIFY_OK; 1894 1870 } ··· 1882 1908 1883 1909 netdev_info(ndev, "VF unregistering: %s\n", vf_netdev->name); 1884 1910 1911 + netdev_rx_handler_unregister(vf_netdev); 1885 1912 netdev_upper_dev_unlink(vf_netdev, ndev); 1886 1913 RCU_INIT_POINTER(net_device_ctx->vf_netdev, NULL); 1887 1914 dev_put(vf_netdev); 1888 - module_put(THIS_MODULE); 1915 + 1889 1916 return NOTIFY_OK; 1890 1917 } 1891 1918 ··· 1990 2015 1991 2016 static int netvsc_remove(struct hv_device *dev) 1992 2017 { 1993 - struct net_device *net; 1994 2018 struct net_device_context *ndev_ctx; 2019 + struct net_device *vf_netdev; 2020 + struct net_device *net; 1995 2021 1996 2022 net = hv_get_drvdata(dev); 1997 - 1998 2023 if (net == NULL) { 1999 2024 dev_err(&dev->device, "No net device to remove\n"); 2000 2025 return 0; ··· 2011 2036 * removed. Also blocks mtu and channel changes. 2012 2037 */ 2013 2038 rtnl_lock(); 2039 + vf_netdev = rtnl_dereference(ndev_ctx->vf_netdev); 2040 + if (vf_netdev) 2041 + netvsc_unregister_vf(vf_netdev); 2042 + 2014 2043 rndis_filter_device_remove(dev, 2015 2044 rtnl_dereference(ndev_ctx->nvdev)); 2045 + unregister_netdevice(net); 2016 2046 rtnl_unlock(); 2017 - 2018 - unregister_netdev(net); 2019 2047 2020 2048 hv_set_drvdata(dev, NULL); 2021 2049 ··· 2077 2099 case NETDEV_UNREGISTER: 2078 2100 return netvsc_unregister_vf(event_dev); 2079 2101 case NETDEV_UP: 2080 - return netvsc_vf_up(event_dev); 2081 2102 case NETDEV_DOWN: 2082 - return netvsc_vf_down(event_dev); 2103 + return netvsc_vf_changed(event_dev); 2083 2104 default: 2084 2105 return NOTIFY_DONE; 2085 2106 }