diff options
Diffstat (limited to 'drivers/net/hyperv')
| -rw-r--r-- | drivers/net/hyperv/netvsc_drv.c | 38 | 
1 files changed, 14 insertions, 24 deletions
| diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index dd294783b5c5..2d59138db7f3 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -44,6 +44,7 @@ struct net_device_context {  	/* point back to our device context */  	struct hv_device *device_ctx;  	struct delayed_work dwork; +	struct work_struct work;  }; @@ -51,30 +52,22 @@ static int ring_size = 128;  module_param(ring_size, int, S_IRUGO);  MODULE_PARM_DESC(ring_size, "Ring buffer size (# of pages)"); -struct set_multicast_work { -	struct work_struct work; -	struct net_device *net; -}; -  static void do_set_multicast(struct work_struct *w)  { -	struct set_multicast_work *swk = -		container_of(w, struct set_multicast_work, work); -	struct net_device *net = swk->net; - -	struct net_device_context *ndevctx = netdev_priv(net); +	struct net_device_context *ndevctx = +		container_of(w, struct net_device_context, work);  	struct netvsc_device *nvdev;  	struct rndis_device *rdev;  	nvdev = hv_get_drvdata(ndevctx->device_ctx); -	if (nvdev == NULL) -		goto out; +	if (nvdev == NULL || nvdev->ndev == NULL) +		return;  	rdev = nvdev->extension;  	if (rdev == NULL) -		goto out; +		return; -	if (net->flags & IFF_PROMISC) +	if (nvdev->ndev->flags & IFF_PROMISC)  		rndis_filter_set_packet_filter(rdev,  			NDIS_PACKET_TYPE_PROMISCUOUS);  	else @@ -82,21 +75,13 @@ static void do_set_multicast(struct work_struct *w)  			NDIS_PACKET_TYPE_BROADCAST |  			NDIS_PACKET_TYPE_ALL_MULTICAST |  			NDIS_PACKET_TYPE_DIRECTED); - -out: -	kfree(w);  }  static void netvsc_set_multicast_list(struct net_device *net)  { -	struct set_multicast_work *swk = -		kmalloc(sizeof(struct set_multicast_work), GFP_ATOMIC); -	if (swk == NULL) -		return; +	struct net_device_context *net_device_ctx = netdev_priv(net); -	swk->net = net; -	INIT_WORK(&swk->work, do_set_multicast); -	schedule_work(&swk->work); +	schedule_work(&net_device_ctx->work);  }  static int netvsc_open(struct net_device *net) @@ -125,6 +110,8 @@ static int netvsc_close(struct net_device *net)  	netif_tx_disable(net); +	/* Make sure netvsc_set_multicast_list doesn't re-enable filter! */ +	cancel_work_sync(&net_device_ctx->work);  	ret = rndis_filter_close(device_obj);  	if (ret != 0)  		netdev_err(net, "unable to close device (ret %d).\n", ret); @@ -335,6 +322,7 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu)  	nvdev->start_remove = true;  	cancel_delayed_work_sync(&ndevctx->dwork); +	cancel_work_sync(&ndevctx->work);  	netif_tx_disable(ndev);  	rndis_filter_device_remove(hdev); @@ -403,6 +391,7 @@ static int netvsc_probe(struct hv_device *dev,  	net_device_ctx->device_ctx = dev;  	hv_set_drvdata(dev, net);  	INIT_DELAYED_WORK(&net_device_ctx->dwork, netvsc_send_garp); +	INIT_WORK(&net_device_ctx->work, do_set_multicast);  	net->netdev_ops = &device_ops; @@ -456,6 +445,7 @@ static int netvsc_remove(struct hv_device *dev)  	ndev_ctx = netdev_priv(net);  	cancel_delayed_work_sync(&ndev_ctx->dwork); +	cancel_work_sync(&ndev_ctx->work);  	/* Stop outbound asap */  	netif_tx_disable(net); |