|
@@ -67,6 +67,8 @@ static int debug = -1;
|
|
module_param(debug, int, 0444);
|
|
module_param(debug, int, 0444);
|
|
MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
|
|
MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
|
|
|
|
|
|
|
|
+static LIST_HEAD(netvsc_dev_list);
|
|
|
|
+
|
|
static void netvsc_change_rx_flags(struct net_device *net, int change)
|
|
static void netvsc_change_rx_flags(struct net_device *net, int change)
|
|
{
|
|
{
|
|
struct net_device_context *ndev_ctx = netdev_priv(net);
|
|
struct net_device_context *ndev_ctx = netdev_priv(net);
|
|
@@ -1781,13 +1783,10 @@ out_unlock:
|
|
|
|
|
|
static struct net_device *get_netvsc_bymac(const u8 *mac)
|
|
static struct net_device *get_netvsc_bymac(const u8 *mac)
|
|
{
|
|
{
|
|
- struct net_device *dev;
|
|
|
|
-
|
|
|
|
- ASSERT_RTNL();
|
|
|
|
|
|
+ struct net_device_context *ndev_ctx;
|
|
|
|
|
|
- for_each_netdev(&init_net, dev) {
|
|
|
|
- if (dev->netdev_ops != &device_ops)
|
|
|
|
- continue; /* not a netvsc device */
|
|
|
|
|
|
+ list_for_each_entry(ndev_ctx, &netvsc_dev_list, list) {
|
|
|
|
+ struct net_device *dev = hv_get_drvdata(ndev_ctx->device_ctx);
|
|
|
|
|
|
if (ether_addr_equal(mac, dev->perm_addr))
|
|
if (ether_addr_equal(mac, dev->perm_addr))
|
|
return dev;
|
|
return dev;
|
|
@@ -1798,25 +1797,18 @@ static struct net_device *get_netvsc_bymac(const u8 *mac)
|
|
|
|
|
|
static struct net_device *get_netvsc_byref(struct net_device *vf_netdev)
|
|
static struct net_device *get_netvsc_byref(struct net_device *vf_netdev)
|
|
{
|
|
{
|
|
|
|
+ struct net_device_context *net_device_ctx;
|
|
struct net_device *dev;
|
|
struct net_device *dev;
|
|
|
|
|
|
- ASSERT_RTNL();
|
|
|
|
-
|
|
|
|
- for_each_netdev(&init_net, dev) {
|
|
|
|
- struct net_device_context *net_device_ctx;
|
|
|
|
|
|
+ dev = netdev_master_upper_dev_get(vf_netdev);
|
|
|
|
+ if (!dev || dev->netdev_ops != &device_ops)
|
|
|
|
+ return NULL; /* not a netvsc device */
|
|
|
|
|
|
- if (dev->netdev_ops != &device_ops)
|
|
|
|
- continue; /* not a netvsc device */
|
|
|
|
|
|
+ net_device_ctx = netdev_priv(dev);
|
|
|
|
+ if (!rtnl_dereference(net_device_ctx->nvdev))
|
|
|
|
+ return NULL; /* device is removed */
|
|
|
|
|
|
- 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;
|
|
|
|
|
|
+ return dev;
|
|
}
|
|
}
|
|
|
|
|
|
/* Called when VF is injecting data into network stack.
|
|
/* Called when VF is injecting data into network stack.
|
|
@@ -2093,15 +2085,19 @@ static int netvsc_probe(struct hv_device *dev,
|
|
else
|
|
else
|
|
net->max_mtu = ETH_DATA_LEN;
|
|
net->max_mtu = ETH_DATA_LEN;
|
|
|
|
|
|
- ret = register_netdev(net);
|
|
|
|
|
|
+ rtnl_lock();
|
|
|
|
+ ret = register_netdevice(net);
|
|
if (ret != 0) {
|
|
if (ret != 0) {
|
|
pr_err("Unable to register netdev.\n");
|
|
pr_err("Unable to register netdev.\n");
|
|
goto register_failed;
|
|
goto register_failed;
|
|
}
|
|
}
|
|
|
|
|
|
- return ret;
|
|
|
|
|
|
+ list_add(&net_device_ctx->list, &netvsc_dev_list);
|
|
|
|
+ rtnl_unlock();
|
|
|
|
+ return 0;
|
|
|
|
|
|
register_failed:
|
|
register_failed:
|
|
|
|
+ rtnl_unlock();
|
|
rndis_filter_device_remove(dev, nvdev);
|
|
rndis_filter_device_remove(dev, nvdev);
|
|
rndis_failed:
|
|
rndis_failed:
|
|
free_percpu(net_device_ctx->vf_stats);
|
|
free_percpu(net_device_ctx->vf_stats);
|
|
@@ -2147,6 +2143,7 @@ static int netvsc_remove(struct hv_device *dev)
|
|
rndis_filter_device_remove(dev, nvdev);
|
|
rndis_filter_device_remove(dev, nvdev);
|
|
|
|
|
|
unregister_netdevice(net);
|
|
unregister_netdevice(net);
|
|
|
|
+ list_del(&ndev_ctx->list);
|
|
|
|
|
|
rtnl_unlock();
|
|
rtnl_unlock();
|
|
rcu_read_unlock();
|
|
rcu_read_unlock();
|