forked from mirrors/linux
		
	netvsc: refactor notifier/event handling code to use the failover framework
Use the registration/notification framework supported by the generic failover infrastructure. Signed-off-by: Sridhar Samudrala <sridhar.samudrala@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									30c8bd5aa8
								
							
						
					
					
						commit
						1ff78076d8
					
				
					 3 changed files with 60 additions and 165 deletions
				
			
		| 
						 | 
					@ -2,5 +2,6 @@ config HYPERV_NET
 | 
				
			||||||
	tristate "Microsoft Hyper-V virtual network driver"
 | 
						tristate "Microsoft Hyper-V virtual network driver"
 | 
				
			||||||
	depends on HYPERV
 | 
						depends on HYPERV
 | 
				
			||||||
	select UCS2_STRING
 | 
						select UCS2_STRING
 | 
				
			||||||
 | 
						select FAILOVER
 | 
				
			||||||
	help
 | 
						help
 | 
				
			||||||
	  Select this option to enable the Hyper-V virtual network driver.
 | 
						  Select this option to enable the Hyper-V virtual network driver.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -932,6 +932,8 @@ struct net_device_context {
 | 
				
			||||||
	u32 vf_alloc;
 | 
						u32 vf_alloc;
 | 
				
			||||||
	/* Serial number of the VF to team with */
 | 
						/* Serial number of the VF to team with */
 | 
				
			||||||
	u32 vf_serial;
 | 
						u32 vf_serial;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct failover *failover;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Per channel data */
 | 
					/* Per channel data */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,6 +43,7 @@
 | 
				
			||||||
#include <net/pkt_sched.h>
 | 
					#include <net/pkt_sched.h>
 | 
				
			||||||
#include <net/checksum.h>
 | 
					#include <net/checksum.h>
 | 
				
			||||||
#include <net/ip6_checksum.h>
 | 
					#include <net/ip6_checksum.h>
 | 
				
			||||||
 | 
					#include <net/failover.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "hyperv_net.h"
 | 
					#include "hyperv_net.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1779,46 +1780,6 @@ static void netvsc_link_change(struct work_struct *w)
 | 
				
			||||||
	rtnl_unlock();
 | 
						rtnl_unlock();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct net_device *get_netvsc_bymac(const u8 *mac)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct net_device *dev;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ASSERT_RTNL();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for_each_netdev(&init_net, dev) {
 | 
					 | 
				
			||||||
		if (dev->netdev_ops != &device_ops)
 | 
					 | 
				
			||||||
			continue;	/* not a netvsc device */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (ether_addr_equal(mac, dev->perm_addr))
 | 
					 | 
				
			||||||
			return dev;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static struct net_device *get_netvsc_byref(struct net_device *vf_netdev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct net_device *dev;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ASSERT_RTNL();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for_each_netdev(&init_net, dev) {
 | 
					 | 
				
			||||||
		struct net_device_context *net_device_ctx;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (dev->netdev_ops != &device_ops)
 | 
					 | 
				
			||||||
			continue;	/* not a netvsc device */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		net_device_ctx = netdev_priv(dev);
 | 
					 | 
				
			||||||
		if (!rtnl_dereference(net_device_ctx->nvdev))
 | 
					 | 
				
			||||||
			continue;	/* device is removed */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (rtnl_dereference(net_device_ctx->vf_netdev) == vf_netdev)
 | 
					 | 
				
			||||||
			return dev;	/* a match */
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Called when VF is injecting data into network stack.
 | 
					/* Called when VF is injecting data into network stack.
 | 
				
			||||||
 * Change the associated network device from VF to netvsc.
 | 
					 * Change the associated network device from VF to netvsc.
 | 
				
			||||||
 * note: already called with rcu_read_lock
 | 
					 * note: already called with rcu_read_lock
 | 
				
			||||||
| 
						 | 
					@ -1841,46 +1802,6 @@ static rx_handler_result_t netvsc_vf_handle_frame(struct sk_buff **pskb)
 | 
				
			||||||
	return RX_HANDLER_ANOTHER;
 | 
						return RX_HANDLER_ANOTHER;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int netvsc_vf_join(struct net_device *vf_netdev,
 | 
					 | 
				
			||||||
			  struct net_device *ndev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct net_device_context *ndev_ctx = netdev_priv(ndev);
 | 
					 | 
				
			||||||
	int ret;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = netdev_rx_handler_register(vf_netdev,
 | 
					 | 
				
			||||||
					 netvsc_vf_handle_frame, ndev);
 | 
					 | 
				
			||||||
	if (ret != 0) {
 | 
					 | 
				
			||||||
		netdev_err(vf_netdev,
 | 
					 | 
				
			||||||
			   "can not register netvsc VF receive handler (err = %d)\n",
 | 
					 | 
				
			||||||
			   ret);
 | 
					 | 
				
			||||||
		goto rx_handler_failed;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = netdev_master_upper_dev_link(vf_netdev, ndev,
 | 
					 | 
				
			||||||
					   NULL, NULL, NULL);
 | 
					 | 
				
			||||||
	if (ret != 0) {
 | 
					 | 
				
			||||||
		netdev_err(vf_netdev,
 | 
					 | 
				
			||||||
			   "can not set master device %s (err = %d)\n",
 | 
					 | 
				
			||||||
			   ndev->name, ret);
 | 
					 | 
				
			||||||
		goto upper_link_failed;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* set slave flag before open to prevent IPv6 addrconf */
 | 
					 | 
				
			||||||
	vf_netdev->flags |= IFF_SLAVE;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	schedule_delayed_work(&ndev_ctx->vf_takeover, VF_TAKEOVER_INT);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	call_netdevice_notifiers(NETDEV_JOIN, vf_netdev);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	netdev_info(vf_netdev, "joined to %s\n", ndev->name);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
upper_link_failed:
 | 
					 | 
				
			||||||
	netdev_rx_handler_unregister(vf_netdev);
 | 
					 | 
				
			||||||
rx_handler_failed:
 | 
					 | 
				
			||||||
	return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void __netvsc_vf_setup(struct net_device *ndev,
 | 
					static void __netvsc_vf_setup(struct net_device *ndev,
 | 
				
			||||||
			      struct net_device *vf_netdev)
 | 
								      struct net_device *vf_netdev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -1931,85 +1852,95 @@ static void netvsc_vf_setup(struct work_struct *w)
 | 
				
			||||||
	rtnl_unlock();
 | 
						rtnl_unlock();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int netvsc_register_vf(struct net_device *vf_netdev)
 | 
					static int netvsc_pre_register_vf(struct net_device *vf_netdev,
 | 
				
			||||||
 | 
									  struct net_device *ndev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct net_device *ndev;
 | 
					 | 
				
			||||||
	struct net_device_context *net_device_ctx;
 | 
						struct net_device_context *net_device_ctx;
 | 
				
			||||||
	struct netvsc_device *netvsc_dev;
 | 
						struct netvsc_device *netvsc_dev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (vf_netdev->addr_len != ETH_ALEN)
 | 
					 | 
				
			||||||
		return NOTIFY_DONE;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * We will use the MAC address to locate the synthetic interface to
 | 
					 | 
				
			||||||
	 * associate with the VF interface. If we don't find a matching
 | 
					 | 
				
			||||||
	 * synthetic interface, move on.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	ndev = get_netvsc_bymac(vf_netdev->perm_addr);
 | 
					 | 
				
			||||||
	if (!ndev)
 | 
					 | 
				
			||||||
		return NOTIFY_DONE;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	net_device_ctx = netdev_priv(ndev);
 | 
						net_device_ctx = netdev_priv(ndev);
 | 
				
			||||||
	netvsc_dev = rtnl_dereference(net_device_ctx->nvdev);
 | 
						netvsc_dev = rtnl_dereference(net_device_ctx->nvdev);
 | 
				
			||||||
	if (!netvsc_dev || rtnl_dereference(net_device_ctx->vf_netdev))
 | 
						if (!netvsc_dev || rtnl_dereference(net_device_ctx->vf_netdev))
 | 
				
			||||||
		return NOTIFY_DONE;
 | 
							return -ENODEV;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (netvsc_vf_join(vf_netdev, ndev) != 0)
 | 
						return 0;
 | 
				
			||||||
		return NOTIFY_DONE;
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	netdev_info(ndev, "VF registering: %s\n", vf_netdev->name);
 | 
					static int netvsc_register_vf(struct net_device *vf_netdev,
 | 
				
			||||||
 | 
								      struct net_device *ndev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct net_device_context *ndev_ctx = netdev_priv(ndev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* set slave flag before open to prevent IPv6 addrconf */
 | 
				
			||||||
 | 
						vf_netdev->flags |= IFF_SLAVE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						schedule_delayed_work(&ndev_ctx->vf_takeover, VF_TAKEOVER_INT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						call_netdevice_notifiers(NETDEV_JOIN, vf_netdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						netdev_info(vf_netdev, "joined to %s\n", ndev->name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev_hold(vf_netdev);
 | 
						dev_hold(vf_netdev);
 | 
				
			||||||
	rcu_assign_pointer(net_device_ctx->vf_netdev, vf_netdev);
 | 
						rcu_assign_pointer(ndev_ctx->vf_netdev, vf_netdev);
 | 
				
			||||||
	return NOTIFY_OK;
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* VF up/down change detected, schedule to change data path */
 | 
					/* VF up/down change detected, schedule to change data path */
 | 
				
			||||||
static int netvsc_vf_changed(struct net_device *vf_netdev)
 | 
					static int netvsc_vf_changed(struct net_device *vf_netdev,
 | 
				
			||||||
 | 
								     struct net_device *ndev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct net_device_context *net_device_ctx;
 | 
						struct net_device_context *net_device_ctx;
 | 
				
			||||||
	struct netvsc_device *netvsc_dev;
 | 
						struct netvsc_device *netvsc_dev;
 | 
				
			||||||
	struct net_device *ndev;
 | 
					 | 
				
			||||||
	bool vf_is_up = netif_running(vf_netdev);
 | 
						bool vf_is_up = netif_running(vf_netdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ndev = get_netvsc_byref(vf_netdev);
 | 
					 | 
				
			||||||
	if (!ndev)
 | 
					 | 
				
			||||||
		return NOTIFY_DONE;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	net_device_ctx = netdev_priv(ndev);
 | 
						net_device_ctx = netdev_priv(ndev);
 | 
				
			||||||
	netvsc_dev = rtnl_dereference(net_device_ctx->nvdev);
 | 
						netvsc_dev = rtnl_dereference(net_device_ctx->nvdev);
 | 
				
			||||||
	if (!netvsc_dev)
 | 
						if (!netvsc_dev)
 | 
				
			||||||
		return NOTIFY_DONE;
 | 
							return -ENODEV;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	netvsc_switch_datapath(ndev, vf_is_up);
 | 
						netvsc_switch_datapath(ndev, vf_is_up);
 | 
				
			||||||
	netdev_info(ndev, "Data path switched %s VF: %s\n",
 | 
						netdev_info(ndev, "Data path switched %s VF: %s\n",
 | 
				
			||||||
		    vf_is_up ? "to" : "from", vf_netdev->name);
 | 
							    vf_is_up ? "to" : "from", vf_netdev->name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return NOTIFY_OK;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int netvsc_unregister_vf(struct net_device *vf_netdev)
 | 
					static int netvsc_pre_unregister_vf(struct net_device *vf_netdev,
 | 
				
			||||||
 | 
									    struct net_device *ndev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct net_device *ndev;
 | 
					 | 
				
			||||||
	struct net_device_context *net_device_ctx;
 | 
						struct net_device_context *net_device_ctx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ndev = get_netvsc_byref(vf_netdev);
 | 
					 | 
				
			||||||
	if (!ndev)
 | 
					 | 
				
			||||||
		return NOTIFY_DONE;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	net_device_ctx = netdev_priv(ndev);
 | 
						net_device_ctx = netdev_priv(ndev);
 | 
				
			||||||
	cancel_delayed_work_sync(&net_device_ctx->vf_takeover);
 | 
						cancel_delayed_work_sync(&net_device_ctx->vf_takeover);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int netvsc_unregister_vf(struct net_device *vf_netdev,
 | 
				
			||||||
 | 
									struct net_device *ndev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct net_device_context *net_device_ctx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						net_device_ctx = netdev_priv(ndev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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);
 | 
					 | 
				
			||||||
	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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return NOTIFY_OK;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct failover_ops netvsc_failover_ops = {
 | 
				
			||||||
 | 
						.slave_pre_register	= netvsc_pre_register_vf,
 | 
				
			||||||
 | 
						.slave_register		= netvsc_register_vf,
 | 
				
			||||||
 | 
						.slave_pre_unregister	= netvsc_pre_unregister_vf,
 | 
				
			||||||
 | 
						.slave_unregister	= netvsc_unregister_vf,
 | 
				
			||||||
 | 
						.slave_link_change	= netvsc_vf_changed,
 | 
				
			||||||
 | 
						.slave_handle_frame	= netvsc_vf_handle_frame,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int netvsc_probe(struct hv_device *dev,
 | 
					static int netvsc_probe(struct hv_device *dev,
 | 
				
			||||||
			const struct hv_vmbus_device_id *dev_id)
 | 
								const struct hv_vmbus_device_id *dev_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -2099,8 +2030,14 @@ static int netvsc_probe(struct hv_device *dev,
 | 
				
			||||||
		goto register_failed;
 | 
							goto register_failed;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						net_device_ctx->failover = failover_register(net, &netvsc_failover_ops);
 | 
				
			||||||
 | 
						if (IS_ERR(net_device_ctx->failover))
 | 
				
			||||||
 | 
							goto err_failover;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					err_failover:
 | 
				
			||||||
 | 
						unregister_netdev(net);
 | 
				
			||||||
register_failed:
 | 
					register_failed:
 | 
				
			||||||
	rndis_filter_device_remove(dev, nvdev);
 | 
						rndis_filter_device_remove(dev, nvdev);
 | 
				
			||||||
rndis_failed:
 | 
					rndis_failed:
 | 
				
			||||||
| 
						 | 
					@ -2141,13 +2078,15 @@ static int netvsc_remove(struct hv_device *dev)
 | 
				
			||||||
	rtnl_lock();
 | 
						rtnl_lock();
 | 
				
			||||||
	vf_netdev = rtnl_dereference(ndev_ctx->vf_netdev);
 | 
						vf_netdev = rtnl_dereference(ndev_ctx->vf_netdev);
 | 
				
			||||||
	if (vf_netdev)
 | 
						if (vf_netdev)
 | 
				
			||||||
		netvsc_unregister_vf(vf_netdev);
 | 
							failover_slave_unregister(vf_netdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (nvdev)
 | 
						if (nvdev)
 | 
				
			||||||
		rndis_filter_device_remove(dev, nvdev);
 | 
							rndis_filter_device_remove(dev, nvdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unregister_netdevice(net);
 | 
						unregister_netdevice(net);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						failover_unregister(ndev_ctx->failover);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rtnl_unlock();
 | 
						rtnl_unlock();
 | 
				
			||||||
	rcu_read_unlock();
 | 
						rcu_read_unlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2174,54 +2113,8 @@ static struct  hv_driver netvsc_drv = {
 | 
				
			||||||
	.remove = netvsc_remove,
 | 
						.remove = netvsc_remove,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * On Hyper-V, every VF interface is matched with a corresponding
 | 
					 | 
				
			||||||
 * synthetic interface. The synthetic interface is presented first
 | 
					 | 
				
			||||||
 * to the guest. When the corresponding VF instance is registered,
 | 
					 | 
				
			||||||
 * we will take care of switching the data path.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static int netvsc_netdev_event(struct notifier_block *this,
 | 
					 | 
				
			||||||
			       unsigned long event, void *ptr)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct net_device *event_dev = netdev_notifier_info_to_dev(ptr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Skip our own events */
 | 
					 | 
				
			||||||
	if (event_dev->netdev_ops == &device_ops)
 | 
					 | 
				
			||||||
		return NOTIFY_DONE;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Avoid non-Ethernet type devices */
 | 
					 | 
				
			||||||
	if (event_dev->type != ARPHRD_ETHER)
 | 
					 | 
				
			||||||
		return NOTIFY_DONE;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Avoid Vlan dev with same MAC registering as VF */
 | 
					 | 
				
			||||||
	if (is_vlan_dev(event_dev))
 | 
					 | 
				
			||||||
		return NOTIFY_DONE;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Avoid Bonding master dev with same MAC registering as VF */
 | 
					 | 
				
			||||||
	if ((event_dev->priv_flags & IFF_BONDING) &&
 | 
					 | 
				
			||||||
	    (event_dev->flags & IFF_MASTER))
 | 
					 | 
				
			||||||
		return NOTIFY_DONE;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch (event) {
 | 
					 | 
				
			||||||
	case NETDEV_REGISTER:
 | 
					 | 
				
			||||||
		return netvsc_register_vf(event_dev);
 | 
					 | 
				
			||||||
	case NETDEV_UNREGISTER:
 | 
					 | 
				
			||||||
		return netvsc_unregister_vf(event_dev);
 | 
					 | 
				
			||||||
	case NETDEV_UP:
 | 
					 | 
				
			||||||
	case NETDEV_DOWN:
 | 
					 | 
				
			||||||
		return netvsc_vf_changed(event_dev);
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		return NOTIFY_DONE;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static struct notifier_block netvsc_netdev_notifier = {
 | 
					 | 
				
			||||||
	.notifier_call = netvsc_netdev_event,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void __exit netvsc_drv_exit(void)
 | 
					static void __exit netvsc_drv_exit(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unregister_netdevice_notifier(&netvsc_netdev_notifier);
 | 
					 | 
				
			||||||
	vmbus_driver_unregister(&netvsc_drv);
 | 
						vmbus_driver_unregister(&netvsc_drv);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2241,7 +2134,6 @@ static int __init netvsc_drv_init(void)
 | 
				
			||||||
	if (ret)
 | 
						if (ret)
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	register_netdevice_notifier(&netvsc_netdev_notifier);
 | 
					 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue