|
@@ -5589,6 +5589,7 @@ static inline bool netdev_adjacent_is_neigh_list(struct net_device *dev,
|
|
|
|
|
|
static int __netdev_adjacent_dev_insert(struct net_device *dev,
|
|
static int __netdev_adjacent_dev_insert(struct net_device *dev,
|
|
struct net_device *adj_dev,
|
|
struct net_device *adj_dev,
|
|
|
|
+ u16 ref_nr,
|
|
struct list_head *dev_list,
|
|
struct list_head *dev_list,
|
|
void *private, bool master)
|
|
void *private, bool master)
|
|
{
|
|
{
|
|
@@ -5598,7 +5599,7 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,
|
|
adj = __netdev_find_adj(adj_dev, dev_list);
|
|
adj = __netdev_find_adj(adj_dev, dev_list);
|
|
|
|
|
|
if (adj) {
|
|
if (adj) {
|
|
- adj->ref_nr++;
|
|
|
|
|
|
+ adj->ref_nr += ref_nr;
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -5608,7 +5609,7 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,
|
|
|
|
|
|
adj->dev = adj_dev;
|
|
adj->dev = adj_dev;
|
|
adj->master = master;
|
|
adj->master = master;
|
|
- adj->ref_nr = 1;
|
|
|
|
|
|
+ adj->ref_nr = ref_nr;
|
|
adj->private = private;
|
|
adj->private = private;
|
|
dev_hold(adj_dev);
|
|
dev_hold(adj_dev);
|
|
|
|
|
|
@@ -5647,6 +5648,7 @@ free_adj:
|
|
|
|
|
|
static void __netdev_adjacent_dev_remove(struct net_device *dev,
|
|
static void __netdev_adjacent_dev_remove(struct net_device *dev,
|
|
struct net_device *adj_dev,
|
|
struct net_device *adj_dev,
|
|
|
|
+ u16 ref_nr,
|
|
struct list_head *dev_list)
|
|
struct list_head *dev_list)
|
|
{
|
|
{
|
|
struct netdev_adjacent *adj;
|
|
struct netdev_adjacent *adj;
|
|
@@ -5659,10 +5661,10 @@ static void __netdev_adjacent_dev_remove(struct net_device *dev,
|
|
BUG();
|
|
BUG();
|
|
}
|
|
}
|
|
|
|
|
|
- if (adj->ref_nr > 1) {
|
|
|
|
- pr_debug("%s to %s ref_nr-- = %d\n", dev->name, adj_dev->name,
|
|
|
|
- adj->ref_nr-1);
|
|
|
|
- adj->ref_nr--;
|
|
|
|
|
|
+ if (adj->ref_nr > ref_nr) {
|
|
|
|
+ pr_debug("%s to %s ref_nr-%d = %d\n", dev->name, adj_dev->name,
|
|
|
|
+ ref_nr, adj->ref_nr-ref_nr);
|
|
|
|
+ adj->ref_nr -= ref_nr;
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -5681,21 +5683,22 @@ static void __netdev_adjacent_dev_remove(struct net_device *dev,
|
|
|
|
|
|
static int __netdev_adjacent_dev_link_lists(struct net_device *dev,
|
|
static int __netdev_adjacent_dev_link_lists(struct net_device *dev,
|
|
struct net_device *upper_dev,
|
|
struct net_device *upper_dev,
|
|
|
|
+ u16 ref_nr,
|
|
struct list_head *up_list,
|
|
struct list_head *up_list,
|
|
struct list_head *down_list,
|
|
struct list_head *down_list,
|
|
void *private, bool master)
|
|
void *private, bool master)
|
|
{
|
|
{
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
- ret = __netdev_adjacent_dev_insert(dev, upper_dev, up_list, private,
|
|
|
|
- master);
|
|
|
|
|
|
+ ret = __netdev_adjacent_dev_insert(dev, upper_dev, ref_nr, up_list,
|
|
|
|
+ private, master);
|
|
if (ret)
|
|
if (ret)
|
|
return ret;
|
|
return ret;
|
|
|
|
|
|
- ret = __netdev_adjacent_dev_insert(upper_dev, dev, down_list, private,
|
|
|
|
- false);
|
|
|
|
|
|
+ ret = __netdev_adjacent_dev_insert(upper_dev, dev, ref_nr, down_list,
|
|
|
|
+ private, false);
|
|
if (ret) {
|
|
if (ret) {
|
|
- __netdev_adjacent_dev_remove(dev, upper_dev, up_list);
|
|
|
|
|
|
+ __netdev_adjacent_dev_remove(dev, upper_dev, ref_nr, up_list);
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -5703,9 +5706,10 @@ static int __netdev_adjacent_dev_link_lists(struct net_device *dev,
|
|
}
|
|
}
|
|
|
|
|
|
static int __netdev_adjacent_dev_link(struct net_device *dev,
|
|
static int __netdev_adjacent_dev_link(struct net_device *dev,
|
|
- struct net_device *upper_dev)
|
|
|
|
|
|
+ struct net_device *upper_dev,
|
|
|
|
+ u16 ref_nr)
|
|
{
|
|
{
|
|
- return __netdev_adjacent_dev_link_lists(dev, upper_dev,
|
|
|
|
|
|
+ return __netdev_adjacent_dev_link_lists(dev, upper_dev, ref_nr,
|
|
&dev->all_adj_list.upper,
|
|
&dev->all_adj_list.upper,
|
|
&upper_dev->all_adj_list.lower,
|
|
&upper_dev->all_adj_list.lower,
|
|
NULL, false);
|
|
NULL, false);
|
|
@@ -5713,17 +5717,19 @@ static int __netdev_adjacent_dev_link(struct net_device *dev,
|
|
|
|
|
|
static void __netdev_adjacent_dev_unlink_lists(struct net_device *dev,
|
|
static void __netdev_adjacent_dev_unlink_lists(struct net_device *dev,
|
|
struct net_device *upper_dev,
|
|
struct net_device *upper_dev,
|
|
|
|
+ u16 ref_nr,
|
|
struct list_head *up_list,
|
|
struct list_head *up_list,
|
|
struct list_head *down_list)
|
|
struct list_head *down_list)
|
|
{
|
|
{
|
|
- __netdev_adjacent_dev_remove(dev, upper_dev, up_list);
|
|
|
|
- __netdev_adjacent_dev_remove(upper_dev, dev, down_list);
|
|
|
|
|
|
+ __netdev_adjacent_dev_remove(dev, upper_dev, ref_nr, up_list);
|
|
|
|
+ __netdev_adjacent_dev_remove(upper_dev, dev, ref_nr, down_list);
|
|
}
|
|
}
|
|
|
|
|
|
static void __netdev_adjacent_dev_unlink(struct net_device *dev,
|
|
static void __netdev_adjacent_dev_unlink(struct net_device *dev,
|
|
- struct net_device *upper_dev)
|
|
|
|
|
|
+ struct net_device *upper_dev,
|
|
|
|
+ u16 ref_nr)
|
|
{
|
|
{
|
|
- __netdev_adjacent_dev_unlink_lists(dev, upper_dev,
|
|
|
|
|
|
+ __netdev_adjacent_dev_unlink_lists(dev, upper_dev, ref_nr,
|
|
&dev->all_adj_list.upper,
|
|
&dev->all_adj_list.upper,
|
|
&upper_dev->all_adj_list.lower);
|
|
&upper_dev->all_adj_list.lower);
|
|
}
|
|
}
|
|
@@ -5732,17 +5738,17 @@ static int __netdev_adjacent_dev_link_neighbour(struct net_device *dev,
|
|
struct net_device *upper_dev,
|
|
struct net_device *upper_dev,
|
|
void *private, bool master)
|
|
void *private, bool master)
|
|
{
|
|
{
|
|
- int ret = __netdev_adjacent_dev_link(dev, upper_dev);
|
|
|
|
|
|
+ int ret = __netdev_adjacent_dev_link(dev, upper_dev, 1);
|
|
|
|
|
|
if (ret)
|
|
if (ret)
|
|
return ret;
|
|
return ret;
|
|
|
|
|
|
- ret = __netdev_adjacent_dev_link_lists(dev, upper_dev,
|
|
|
|
|
|
+ ret = __netdev_adjacent_dev_link_lists(dev, upper_dev, 1,
|
|
&dev->adj_list.upper,
|
|
&dev->adj_list.upper,
|
|
&upper_dev->adj_list.lower,
|
|
&upper_dev->adj_list.lower,
|
|
private, master);
|
|
private, master);
|
|
if (ret) {
|
|
if (ret) {
|
|
- __netdev_adjacent_dev_unlink(dev, upper_dev);
|
|
|
|
|
|
+ __netdev_adjacent_dev_unlink(dev, upper_dev, 1);
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -5752,8 +5758,8 @@ static int __netdev_adjacent_dev_link_neighbour(struct net_device *dev,
|
|
static void __netdev_adjacent_dev_unlink_neighbour(struct net_device *dev,
|
|
static void __netdev_adjacent_dev_unlink_neighbour(struct net_device *dev,
|
|
struct net_device *upper_dev)
|
|
struct net_device *upper_dev)
|
|
{
|
|
{
|
|
- __netdev_adjacent_dev_unlink(dev, upper_dev);
|
|
|
|
- __netdev_adjacent_dev_unlink_lists(dev, upper_dev,
|
|
|
|
|
|
+ __netdev_adjacent_dev_unlink(dev, upper_dev, 1);
|
|
|
|
+ __netdev_adjacent_dev_unlink_lists(dev, upper_dev, 1,
|
|
&dev->adj_list.upper,
|
|
&dev->adj_list.upper,
|
|
&upper_dev->adj_list.lower);
|
|
&upper_dev->adj_list.lower);
|
|
}
|
|
}
|
|
@@ -5806,7 +5812,7 @@ static int __netdev_upper_dev_link(struct net_device *dev,
|
|
list_for_each_entry(j, &upper_dev->all_adj_list.upper, list) {
|
|
list_for_each_entry(j, &upper_dev->all_adj_list.upper, list) {
|
|
pr_debug("Interlinking %s with %s, non-neighbour\n",
|
|
pr_debug("Interlinking %s with %s, non-neighbour\n",
|
|
i->dev->name, j->dev->name);
|
|
i->dev->name, j->dev->name);
|
|
- ret = __netdev_adjacent_dev_link(i->dev, j->dev);
|
|
|
|
|
|
+ ret = __netdev_adjacent_dev_link(i->dev, j->dev, i->ref_nr);
|
|
if (ret)
|
|
if (ret)
|
|
goto rollback_mesh;
|
|
goto rollback_mesh;
|
|
}
|
|
}
|
|
@@ -5816,7 +5822,7 @@ static int __netdev_upper_dev_link(struct net_device *dev,
|
|
list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) {
|
|
list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) {
|
|
pr_debug("linking %s's upper device %s with %s\n",
|
|
pr_debug("linking %s's upper device %s with %s\n",
|
|
upper_dev->name, i->dev->name, dev->name);
|
|
upper_dev->name, i->dev->name, dev->name);
|
|
- ret = __netdev_adjacent_dev_link(dev, i->dev);
|
|
|
|
|
|
+ ret = __netdev_adjacent_dev_link(dev, i->dev, i->ref_nr);
|
|
if (ret)
|
|
if (ret)
|
|
goto rollback_upper_mesh;
|
|
goto rollback_upper_mesh;
|
|
}
|
|
}
|
|
@@ -5825,7 +5831,7 @@ static int __netdev_upper_dev_link(struct net_device *dev,
|
|
list_for_each_entry(i, &dev->all_adj_list.lower, list) {
|
|
list_for_each_entry(i, &dev->all_adj_list.lower, list) {
|
|
pr_debug("linking %s's lower device %s with %s\n", dev->name,
|
|
pr_debug("linking %s's lower device %s with %s\n", dev->name,
|
|
i->dev->name, upper_dev->name);
|
|
i->dev->name, upper_dev->name);
|
|
- ret = __netdev_adjacent_dev_link(i->dev, upper_dev);
|
|
|
|
|
|
+ ret = __netdev_adjacent_dev_link(i->dev, upper_dev, i->ref_nr);
|
|
if (ret)
|
|
if (ret)
|
|
goto rollback_lower_mesh;
|
|
goto rollback_lower_mesh;
|
|
}
|
|
}
|
|
@@ -5843,7 +5849,7 @@ rollback_lower_mesh:
|
|
list_for_each_entry(i, &dev->all_adj_list.lower, list) {
|
|
list_for_each_entry(i, &dev->all_adj_list.lower, list) {
|
|
if (i == to_i)
|
|
if (i == to_i)
|
|
break;
|
|
break;
|
|
- __netdev_adjacent_dev_unlink(i->dev, upper_dev);
|
|
|
|
|
|
+ __netdev_adjacent_dev_unlink(i->dev, upper_dev, i->ref_nr);
|
|
}
|
|
}
|
|
|
|
|
|
i = NULL;
|
|
i = NULL;
|
|
@@ -5853,7 +5859,7 @@ rollback_upper_mesh:
|
|
list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) {
|
|
list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) {
|
|
if (i == to_i)
|
|
if (i == to_i)
|
|
break;
|
|
break;
|
|
- __netdev_adjacent_dev_unlink(dev, i->dev);
|
|
|
|
|
|
+ __netdev_adjacent_dev_unlink(dev, i->dev, i->ref_nr);
|
|
}
|
|
}
|
|
|
|
|
|
i = j = NULL;
|
|
i = j = NULL;
|
|
@@ -5865,7 +5871,7 @@ rollback_mesh:
|
|
list_for_each_entry(j, &upper_dev->all_adj_list.upper, list) {
|
|
list_for_each_entry(j, &upper_dev->all_adj_list.upper, list) {
|
|
if (i == to_i && j == to_j)
|
|
if (i == to_i && j == to_j)
|
|
break;
|
|
break;
|
|
- __netdev_adjacent_dev_unlink(i->dev, j->dev);
|
|
|
|
|
|
+ __netdev_adjacent_dev_unlink(i->dev, j->dev, i->ref_nr);
|
|
}
|
|
}
|
|
if (i == to_i)
|
|
if (i == to_i)
|
|
break;
|
|
break;
|
|
@@ -5945,16 +5951,16 @@ void netdev_upper_dev_unlink(struct net_device *dev,
|
|
*/
|
|
*/
|
|
list_for_each_entry(i, &dev->all_adj_list.lower, list)
|
|
list_for_each_entry(i, &dev->all_adj_list.lower, list)
|
|
list_for_each_entry(j, &upper_dev->all_adj_list.upper, list)
|
|
list_for_each_entry(j, &upper_dev->all_adj_list.upper, list)
|
|
- __netdev_adjacent_dev_unlink(i->dev, j->dev);
|
|
|
|
|
|
+ __netdev_adjacent_dev_unlink(i->dev, j->dev, i->ref_nr);
|
|
|
|
|
|
/* remove also the devices itself from lower/upper device
|
|
/* remove also the devices itself from lower/upper device
|
|
* list
|
|
* list
|
|
*/
|
|
*/
|
|
list_for_each_entry(i, &dev->all_adj_list.lower, list)
|
|
list_for_each_entry(i, &dev->all_adj_list.lower, list)
|
|
- __netdev_adjacent_dev_unlink(i->dev, upper_dev);
|
|
|
|
|
|
+ __netdev_adjacent_dev_unlink(i->dev, upper_dev, i->ref_nr);
|
|
|
|
|
|
list_for_each_entry(i, &upper_dev->all_adj_list.upper, list)
|
|
list_for_each_entry(i, &upper_dev->all_adj_list.upper, list)
|
|
- __netdev_adjacent_dev_unlink(dev, i->dev);
|
|
|
|
|
|
+ __netdev_adjacent_dev_unlink(dev, i->dev, i->ref_nr);
|
|
|
|
|
|
call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, dev,
|
|
call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, dev,
|
|
&changeupper_info.info);
|
|
&changeupper_info.info);
|