netvsc: move filter setting to rndis_device
The work queue and handling of network filter parameters should be in rndis_device. This gets rid of warning from RCU checks, eliminates a race and cleans up code. Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
a5ecd43992
commit
4f19c0d807
|
@ -171,6 +171,8 @@ struct rndis_device {
|
||||||
spinlock_t request_lock;
|
spinlock_t request_lock;
|
||||||
struct list_head req_list;
|
struct list_head req_list;
|
||||||
|
|
||||||
|
struct work_struct mcast_work;
|
||||||
|
|
||||||
u8 hw_mac_adr[ETH_ALEN];
|
u8 hw_mac_adr[ETH_ALEN];
|
||||||
u8 rss_key[NETVSC_HASH_KEYLEN];
|
u8 rss_key[NETVSC_HASH_KEYLEN];
|
||||||
u16 ind_table[ITAB_NUM];
|
u16 ind_table[ITAB_NUM];
|
||||||
|
@ -201,6 +203,7 @@ int rndis_filter_open(struct netvsc_device *nvdev);
|
||||||
int rndis_filter_close(struct netvsc_device *nvdev);
|
int rndis_filter_close(struct netvsc_device *nvdev);
|
||||||
int rndis_filter_device_add(struct hv_device *dev,
|
int rndis_filter_device_add(struct hv_device *dev,
|
||||||
struct netvsc_device_info *info);
|
struct netvsc_device_info *info);
|
||||||
|
void rndis_filter_update(struct netvsc_device *nvdev);
|
||||||
void rndis_filter_device_remove(struct hv_device *dev,
|
void rndis_filter_device_remove(struct hv_device *dev,
|
||||||
struct netvsc_device *nvdev);
|
struct netvsc_device *nvdev);
|
||||||
int rndis_filter_set_rss_param(struct rndis_device *rdev,
|
int rndis_filter_set_rss_param(struct rndis_device *rdev,
|
||||||
|
@ -211,7 +214,6 @@ int rndis_filter_receive(struct net_device *ndev,
|
||||||
struct vmbus_channel *channel,
|
struct vmbus_channel *channel,
|
||||||
void *data, u32 buflen);
|
void *data, u32 buflen);
|
||||||
|
|
||||||
int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter);
|
|
||||||
int rndis_filter_set_device_mac(struct net_device *ndev, char *mac);
|
int rndis_filter_set_device_mac(struct net_device *ndev, char *mac);
|
||||||
|
|
||||||
void netvsc_switch_datapath(struct net_device *nv_dev, bool vf);
|
void netvsc_switch_datapath(struct net_device *nv_dev, bool vf);
|
||||||
|
@ -696,7 +698,6 @@ struct net_device_context {
|
||||||
/* list protection */
|
/* list protection */
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
|
|
||||||
struct work_struct work;
|
|
||||||
u32 msg_enable; /* debug level */
|
u32 msg_enable; /* debug level */
|
||||||
|
|
||||||
u32 tx_checksum_mask;
|
u32 tx_checksum_mask;
|
||||||
|
|
|
@ -56,37 +56,12 @@ static int debug = -1;
|
||||||
module_param(debug, int, S_IRUGO);
|
module_param(debug, int, S_IRUGO);
|
||||||
MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
|
MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
|
||||||
|
|
||||||
static void do_set_multicast(struct work_struct *w)
|
|
||||||
{
|
|
||||||
struct net_device_context *ndevctx =
|
|
||||||
container_of(w, struct net_device_context, work);
|
|
||||||
struct hv_device *device_obj = ndevctx->device_ctx;
|
|
||||||
struct net_device *ndev = hv_get_drvdata(device_obj);
|
|
||||||
struct netvsc_device *nvdev = rcu_dereference(ndevctx->nvdev);
|
|
||||||
struct rndis_device *rdev;
|
|
||||||
|
|
||||||
if (!nvdev)
|
|
||||||
return;
|
|
||||||
|
|
||||||
rdev = nvdev->extension;
|
|
||||||
if (rdev == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (ndev->flags & IFF_PROMISC)
|
|
||||||
rndis_filter_set_packet_filter(rdev,
|
|
||||||
NDIS_PACKET_TYPE_PROMISCUOUS);
|
|
||||||
else
|
|
||||||
rndis_filter_set_packet_filter(rdev,
|
|
||||||
NDIS_PACKET_TYPE_BROADCAST |
|
|
||||||
NDIS_PACKET_TYPE_ALL_MULTICAST |
|
|
||||||
NDIS_PACKET_TYPE_DIRECTED);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void netvsc_set_multicast_list(struct net_device *net)
|
static void netvsc_set_multicast_list(struct net_device *net)
|
||||||
{
|
{
|
||||||
struct net_device_context *net_device_ctx = netdev_priv(net);
|
struct net_device_context *net_device_ctx = netdev_priv(net);
|
||||||
|
struct netvsc_device *nvdev = rtnl_dereference(net_device_ctx->nvdev);
|
||||||
|
|
||||||
schedule_work(&net_device_ctx->work);
|
rndis_filter_update(nvdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int netvsc_open(struct net_device *net)
|
static int netvsc_open(struct net_device *net)
|
||||||
|
@ -123,8 +98,6 @@ static int netvsc_close(struct net_device *net)
|
||||||
|
|
||||||
netif_tx_disable(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(nvdev);
|
ret = rndis_filter_close(nvdev);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
netdev_err(net, "unable to close device (ret %d).\n", ret);
|
netdev_err(net, "unable to close device (ret %d).\n", ret);
|
||||||
|
@ -1563,7 +1536,6 @@ static int netvsc_probe(struct hv_device *dev,
|
||||||
hv_set_drvdata(dev, net);
|
hv_set_drvdata(dev, net);
|
||||||
|
|
||||||
INIT_DELAYED_WORK(&net_device_ctx->dwork, netvsc_link_change);
|
INIT_DELAYED_WORK(&net_device_ctx->dwork, netvsc_link_change);
|
||||||
INIT_WORK(&net_device_ctx->work, do_set_multicast);
|
|
||||||
|
|
||||||
spin_lock_init(&net_device_ctx->lock);
|
spin_lock_init(&net_device_ctx->lock);
|
||||||
INIT_LIST_HEAD(&net_device_ctx->reconfig_events);
|
INIT_LIST_HEAD(&net_device_ctx->reconfig_events);
|
||||||
|
@ -1633,7 +1605,6 @@ static int netvsc_remove(struct hv_device *dev)
|
||||||
netif_device_detach(net);
|
netif_device_detach(net);
|
||||||
|
|
||||||
cancel_delayed_work_sync(&ndev_ctx->dwork);
|
cancel_delayed_work_sync(&ndev_ctx->dwork);
|
||||||
cancel_work_sync(&ndev_ctx->work);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Call to the vsc driver to let it know that the device is being
|
* Call to the vsc driver to let it know that the device is being
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
|
|
||||||
#include "hyperv_net.h"
|
#include "hyperv_net.h"
|
||||||
|
|
||||||
|
static void rndis_set_multicast(struct work_struct *w);
|
||||||
|
|
||||||
#define RNDIS_EXT_LEN PAGE_SIZE
|
#define RNDIS_EXT_LEN PAGE_SIZE
|
||||||
struct rndis_request {
|
struct rndis_request {
|
||||||
|
@ -76,6 +77,7 @@ static struct rndis_device *get_rndis_device(void)
|
||||||
spin_lock_init(&device->request_lock);
|
spin_lock_init(&device->request_lock);
|
||||||
|
|
||||||
INIT_LIST_HEAD(&device->req_list);
|
INIT_LIST_HEAD(&device->req_list);
|
||||||
|
INIT_WORK(&device->mcast_work, rndis_set_multicast);
|
||||||
|
|
||||||
device->state = RNDIS_DEV_UNINITIALIZED;
|
device->state = RNDIS_DEV_UNINITIALIZED;
|
||||||
|
|
||||||
|
@ -815,7 +817,8 @@ static int rndis_filter_query_link_speed(struct rndis_device *dev)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter)
|
static int rndis_filter_set_packet_filter(struct rndis_device *dev,
|
||||||
|
u32 new_filter)
|
||||||
{
|
{
|
||||||
struct rndis_request *request;
|
struct rndis_request *request;
|
||||||
struct rndis_set_request *set;
|
struct rndis_set_request *set;
|
||||||
|
@ -846,6 +849,28 @@ int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rndis_set_multicast(struct work_struct *w)
|
||||||
|
{
|
||||||
|
struct rndis_device *rdev
|
||||||
|
= container_of(w, struct rndis_device, mcast_work);
|
||||||
|
|
||||||
|
if (rdev->ndev->flags & IFF_PROMISC)
|
||||||
|
rndis_filter_set_packet_filter(rdev,
|
||||||
|
NDIS_PACKET_TYPE_PROMISCUOUS);
|
||||||
|
else
|
||||||
|
rndis_filter_set_packet_filter(rdev,
|
||||||
|
NDIS_PACKET_TYPE_BROADCAST |
|
||||||
|
NDIS_PACKET_TYPE_ALL_MULTICAST |
|
||||||
|
NDIS_PACKET_TYPE_DIRECTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rndis_filter_update(struct netvsc_device *nvdev)
|
||||||
|
{
|
||||||
|
struct rndis_device *rdev = nvdev->extension;
|
||||||
|
|
||||||
|
schedule_work(&rdev->mcast_work);
|
||||||
|
}
|
||||||
|
|
||||||
static int rndis_filter_init_device(struct rndis_device *dev)
|
static int rndis_filter_init_device(struct rndis_device *dev)
|
||||||
{
|
{
|
||||||
struct rndis_request *request;
|
struct rndis_request *request;
|
||||||
|
@ -973,6 +998,9 @@ static int rndis_filter_close_device(struct rndis_device *dev)
|
||||||
if (dev->state != RNDIS_DEV_DATAINITIALIZED)
|
if (dev->state != RNDIS_DEV_DATAINITIALIZED)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
/* Make sure rndis_set_multicast doesn't re-enable filter! */
|
||||||
|
cancel_work_sync(&dev->mcast_work);
|
||||||
|
|
||||||
ret = rndis_filter_set_packet_filter(dev, 0);
|
ret = rndis_filter_set_packet_filter(dev, 0);
|
||||||
if (ret == -ENODEV)
|
if (ret == -ENODEV)
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
Loading…
Reference in New Issue