static int __netdev_adjacent_dev_insert(struct net_device *dev,
struct net_device *adj_dev,
+ u16 ref_nr,
bool neighbour, bool master,
bool upper)
{
if (adj) {
BUG_ON(neighbour);
- adj->ref_nr++;
+ adj->ref_nr += ref_nr;
return 0;
}
adj->dev = adj_dev;
adj->master = master;
adj->neighbour = neighbour;
- adj->ref_nr = 1;
+ adj->ref_nr = ref_nr;
dev_hold(adj_dev);
pr_debug("dev_hold for %s, because of %s link added from %s to %s\n",
static inline int __netdev_upper_dev_insert(struct net_device *dev,
struct net_device *udev,
+ u16 ref_nr,
bool master, bool neighbour)
{
- return __netdev_adjacent_dev_insert(dev, udev, neighbour, master,
- true);
+ return __netdev_adjacent_dev_insert(dev, udev, ref_nr, neighbour,
+ master, true);
}
static inline int __netdev_lower_dev_insert(struct net_device *dev,
struct net_device *ldev,
+ u16 ref_nr,
bool neighbour)
{
- return __netdev_adjacent_dev_insert(dev, ldev, neighbour, false,
+ return __netdev_adjacent_dev_insert(dev, ldev, ref_nr, neighbour, false,
false);
}
void __netdev_adjacent_dev_remove(struct net_device *dev,
- struct net_device *adj_dev, bool upper)
+ struct net_device *adj_dev, u16 ref_nr,
+ bool upper)
{
struct netdev_adjacent *adj;
if (!adj)
BUG();
- if (adj->ref_nr > 1) {
- adj->ref_nr--;
+ if (adj->ref_nr > ref_nr) {
+ adj->ref_nr -= ref_nr;
return;
}
}
static inline void __netdev_upper_dev_remove(struct net_device *dev,
- struct net_device *udev)
+ struct net_device *udev,
+ u16 ref_nr)
{
- return __netdev_adjacent_dev_remove(dev, udev, true);
+ return __netdev_adjacent_dev_remove(dev, udev, ref_nr, true);
}
static inline void __netdev_lower_dev_remove(struct net_device *dev,
- struct net_device *ldev)
+ struct net_device *ldev,
+ u16 ref_nr)
{
- return __netdev_adjacent_dev_remove(dev, ldev, false);
+ return __netdev_adjacent_dev_remove(dev, ldev, ref_nr, false);
}
int __netdev_adjacent_dev_insert_link(struct net_device *dev,
struct net_device *upper_dev,
- bool master, bool neighbour)
+ u16 ref_nr, bool master, bool neighbour)
{
int ret;
- ret = __netdev_upper_dev_insert(dev, upper_dev, master, neighbour);
+ ret = __netdev_upper_dev_insert(dev, upper_dev, ref_nr, master,
+ neighbour);
if (ret)
return ret;
- ret = __netdev_lower_dev_insert(upper_dev, dev, neighbour);
+ ret = __netdev_lower_dev_insert(upper_dev, dev, ref_nr, neighbour);
if (ret) {
- __netdev_upper_dev_remove(dev, upper_dev);
+ __netdev_upper_dev_remove(dev, upper_dev, ref_nr);
return ret;
}
}
static inline int __netdev_adjacent_dev_link(struct net_device *dev,
- struct net_device *udev)
+ struct net_device *udev,
+ u16 ref_nr)
{
- return __netdev_adjacent_dev_insert_link(dev, udev, false, false);
+ return __netdev_adjacent_dev_insert_link(dev, udev, ref_nr, false,
+ false);
}
static inline int __netdev_adjacent_dev_link_neighbour(struct net_device *dev,
struct net_device *udev,
bool master)
{
- return __netdev_adjacent_dev_insert_link(dev, udev, master, true);
+ return __netdev_adjacent_dev_insert_link(dev, udev, 1, master, true);
}
void __netdev_adjacent_dev_unlink(struct net_device *dev,
- struct net_device *upper_dev)
+ struct net_device *upper_dev, u16 ref_nr)
{
- __netdev_upper_dev_remove(dev, upper_dev);
- __netdev_lower_dev_remove(upper_dev, dev);
+ __netdev_upper_dev_remove(dev, upper_dev, ref_nr);
+ __netdev_lower_dev_remove(upper_dev, dev, ref_nr);
}
*/
list_for_each_entry(i, &dev->lower_dev_list, list) {
list_for_each_entry(j, &upper_dev->upper_dev_list, list) {
- ret = __netdev_adjacent_dev_link(i->dev, j->dev);
+ ret = __netdev_adjacent_dev_link(i->dev, j->dev,
+ i->ref_nr);
if (ret)
goto rollback_mesh;
}
/* add dev to every upper_dev's upper device */
list_for_each_entry(i, &upper_dev->upper_dev_list, list) {
- ret = __netdev_adjacent_dev_link(dev, i->dev);
+ ret = __netdev_adjacent_dev_link(dev, i->dev, i->ref_nr);
if (ret)
goto rollback_upper_mesh;
}
/* add upper_dev to every dev's lower device */
list_for_each_entry(i, &dev->lower_dev_list, list) {
- ret = __netdev_adjacent_dev_link(i->dev, upper_dev);
+ ret = __netdev_adjacent_dev_link(i->dev, upper_dev, i->ref_nr);
if (ret)
goto rollback_lower_mesh;
}
list_for_each_entry(i, &dev->lower_dev_list, list) {
if (i == to_i)
break;
- __netdev_adjacent_dev_unlink(i->dev, upper_dev);
+ __netdev_adjacent_dev_unlink(i->dev, upper_dev, i->ref_nr);
}
i = NULL;
list_for_each_entry(i, &upper_dev->upper_dev_list, list) {
if (i == to_i)
break;
- __netdev_adjacent_dev_unlink(dev, i->dev);
+ __netdev_adjacent_dev_unlink(dev, i->dev, i->ref_nr);
}
i = j = NULL;
list_for_each_entry(j, &upper_dev->upper_dev_list, list) {
if (i == to_i && j == to_j)
break;
- __netdev_adjacent_dev_unlink(i->dev, j->dev);
+ __netdev_adjacent_dev_unlink(i->dev, j->dev, i->ref_nr);
}
if (i == to_i)
break;
}
- __netdev_adjacent_dev_unlink(dev, upper_dev);
+ __netdev_adjacent_dev_unlink(dev, upper_dev, 1);
return ret;
}
struct netdev_adjacent *i, *j;
ASSERT_RTNL();
- __netdev_adjacent_dev_unlink(dev, upper_dev);
+ __netdev_adjacent_dev_unlink(dev, upper_dev, 1);
/* Here is the tricky part. We must remove all dev's lower
* devices from all upper_dev's upper devices and vice
*/
list_for_each_entry(i, &dev->lower_dev_list, list)
list_for_each_entry(j, &upper_dev->upper_dev_list, 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
* list
*/
list_for_each_entry(i, &dev->lower_dev_list, 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->upper_dev_list, list)
- __netdev_adjacent_dev_unlink(dev, i->dev);
+ __netdev_adjacent_dev_unlink(dev, i->dev, i->ref_nr);
call_netdevice_notifiers(NETDEV_CHANGEUPPER, dev);
}