diff options
-rw-r--r-- | net/core/dev.c | 68 |
1 files changed, 37 insertions, 31 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index c0c291f721d6..f1fe26f66458 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -5589,6 +5589,7 @@ static inline bool netdev_adjacent_is_neigh_list(struct net_device *dev, | |||
5589 | 5589 | ||
5590 | static int __netdev_adjacent_dev_insert(struct net_device *dev, | 5590 | static int __netdev_adjacent_dev_insert(struct net_device *dev, |
5591 | struct net_device *adj_dev, | 5591 | struct net_device *adj_dev, |
5592 | u16 ref_nr, | ||
5592 | struct list_head *dev_list, | 5593 | struct list_head *dev_list, |
5593 | void *private, bool master) | 5594 | void *private, bool master) |
5594 | { | 5595 | { |
@@ -5598,7 +5599,7 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev, | |||
5598 | adj = __netdev_find_adj(adj_dev, dev_list); | 5599 | adj = __netdev_find_adj(adj_dev, dev_list); |
5599 | 5600 | ||
5600 | if (adj) { | 5601 | if (adj) { |
5601 | adj->ref_nr++; | 5602 | adj->ref_nr += ref_nr; |
5602 | return 0; | 5603 | return 0; |
5603 | } | 5604 | } |
5604 | 5605 | ||
@@ -5608,7 +5609,7 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev, | |||
5608 | 5609 | ||
5609 | adj->dev = adj_dev; | 5610 | adj->dev = adj_dev; |
5610 | adj->master = master; | 5611 | adj->master = master; |
5611 | adj->ref_nr = 1; | 5612 | adj->ref_nr = ref_nr; |
5612 | adj->private = private; | 5613 | adj->private = private; |
5613 | dev_hold(adj_dev); | 5614 | dev_hold(adj_dev); |
5614 | 5615 | ||
@@ -5647,6 +5648,7 @@ free_adj: | |||
5647 | 5648 | ||
5648 | static void __netdev_adjacent_dev_remove(struct net_device *dev, | 5649 | static void __netdev_adjacent_dev_remove(struct net_device *dev, |
5649 | struct net_device *adj_dev, | 5650 | struct net_device *adj_dev, |
5651 | u16 ref_nr, | ||
5650 | struct list_head *dev_list) | 5652 | struct list_head *dev_list) |
5651 | { | 5653 | { |
5652 | struct netdev_adjacent *adj; | 5654 | struct netdev_adjacent *adj; |
@@ -5659,10 +5661,10 @@ static void __netdev_adjacent_dev_remove(struct net_device *dev, | |||
5659 | BUG(); | 5661 | BUG(); |
5660 | } | 5662 | } |
5661 | 5663 | ||
5662 | if (adj->ref_nr > 1) { | 5664 | if (adj->ref_nr > ref_nr) { |
5663 | pr_debug("%s to %s ref_nr-- = %d\n", dev->name, adj_dev->name, | 5665 | pr_debug("%s to %s ref_nr-%d = %d\n", dev->name, adj_dev->name, |
5664 | adj->ref_nr-1); | 5666 | ref_nr, adj->ref_nr-ref_nr); |
5665 | adj->ref_nr--; | 5667 | adj->ref_nr -= ref_nr; |
5666 | return; | 5668 | return; |
5667 | } | 5669 | } |
5668 | 5670 | ||
@@ -5681,21 +5683,22 @@ static void __netdev_adjacent_dev_remove(struct net_device *dev, | |||
5681 | 5683 | ||
5682 | static int __netdev_adjacent_dev_link_lists(struct net_device *dev, | 5684 | static int __netdev_adjacent_dev_link_lists(struct net_device *dev, |
5683 | struct net_device *upper_dev, | 5685 | struct net_device *upper_dev, |
5686 | u16 ref_nr, | ||
5684 | struct list_head *up_list, | 5687 | struct list_head *up_list, |
5685 | struct list_head *down_list, | 5688 | struct list_head *down_list, |
5686 | void *private, bool master) | 5689 | void *private, bool master) |
5687 | { | 5690 | { |
5688 | int ret; | 5691 | int ret; |
5689 | 5692 | ||
5690 | ret = __netdev_adjacent_dev_insert(dev, upper_dev, up_list, private, | 5693 | ret = __netdev_adjacent_dev_insert(dev, upper_dev, ref_nr, up_list, |
5691 | master); | 5694 | private, master); |
5692 | if (ret) | 5695 | if (ret) |
5693 | return ret; | 5696 | return ret; |
5694 | 5697 | ||
5695 | ret = __netdev_adjacent_dev_insert(upper_dev, dev, down_list, private, | 5698 | ret = __netdev_adjacent_dev_insert(upper_dev, dev, ref_nr, down_list, |
5696 | false); | 5699 | private, false); |
5697 | if (ret) { | 5700 | if (ret) { |
5698 | __netdev_adjacent_dev_remove(dev, upper_dev, up_list); | 5701 | __netdev_adjacent_dev_remove(dev, upper_dev, ref_nr, up_list); |
5699 | return ret; | 5702 | return ret; |
5700 | } | 5703 | } |
5701 | 5704 | ||
@@ -5703,9 +5706,10 @@ static int __netdev_adjacent_dev_link_lists(struct net_device *dev, | |||
5703 | } | 5706 | } |
5704 | 5707 | ||
5705 | static int __netdev_adjacent_dev_link(struct net_device *dev, | 5708 | static int __netdev_adjacent_dev_link(struct net_device *dev, |
5706 | struct net_device *upper_dev) | 5709 | struct net_device *upper_dev, |
5710 | u16 ref_nr) | ||
5707 | { | 5711 | { |
5708 | return __netdev_adjacent_dev_link_lists(dev, upper_dev, | 5712 | return __netdev_adjacent_dev_link_lists(dev, upper_dev, ref_nr, |
5709 | &dev->all_adj_list.upper, | 5713 | &dev->all_adj_list.upper, |
5710 | &upper_dev->all_adj_list.lower, | 5714 | &upper_dev->all_adj_list.lower, |
5711 | NULL, false); | 5715 | NULL, false); |
@@ -5713,17 +5717,19 @@ static int __netdev_adjacent_dev_link(struct net_device *dev, | |||
5713 | 5717 | ||
5714 | static void __netdev_adjacent_dev_unlink_lists(struct net_device *dev, | 5718 | static void __netdev_adjacent_dev_unlink_lists(struct net_device *dev, |
5715 | struct net_device *upper_dev, | 5719 | struct net_device *upper_dev, |
5720 | u16 ref_nr, | ||
5716 | struct list_head *up_list, | 5721 | struct list_head *up_list, |
5717 | struct list_head *down_list) | 5722 | struct list_head *down_list) |
5718 | { | 5723 | { |
5719 | __netdev_adjacent_dev_remove(dev, upper_dev, up_list); | 5724 | __netdev_adjacent_dev_remove(dev, upper_dev, ref_nr, up_list); |
5720 | __netdev_adjacent_dev_remove(upper_dev, dev, down_list); | 5725 | __netdev_adjacent_dev_remove(upper_dev, dev, ref_nr, down_list); |
5721 | } | 5726 | } |
5722 | 5727 | ||
5723 | static void __netdev_adjacent_dev_unlink(struct net_device *dev, | 5728 | static void __netdev_adjacent_dev_unlink(struct net_device *dev, |
5724 | struct net_device *upper_dev) | 5729 | struct net_device *upper_dev, |
5730 | u16 ref_nr) | ||
5725 | { | 5731 | { |
5726 | __netdev_adjacent_dev_unlink_lists(dev, upper_dev, | 5732 | __netdev_adjacent_dev_unlink_lists(dev, upper_dev, ref_nr, |
5727 | &dev->all_adj_list.upper, | 5733 | &dev->all_adj_list.upper, |
5728 | &upper_dev->all_adj_list.lower); | 5734 | &upper_dev->all_adj_list.lower); |
5729 | } | 5735 | } |
@@ -5732,17 +5738,17 @@ static int __netdev_adjacent_dev_link_neighbour(struct net_device *dev, | |||
5732 | struct net_device *upper_dev, | 5738 | struct net_device *upper_dev, |
5733 | void *private, bool master) | 5739 | void *private, bool master) |
5734 | { | 5740 | { |
5735 | int ret = __netdev_adjacent_dev_link(dev, upper_dev); | 5741 | int ret = __netdev_adjacent_dev_link(dev, upper_dev, 1); |
5736 | 5742 | ||
5737 | if (ret) | 5743 | if (ret) |
5738 | return ret; | 5744 | return ret; |
5739 | 5745 | ||
5740 | ret = __netdev_adjacent_dev_link_lists(dev, upper_dev, | 5746 | ret = __netdev_adjacent_dev_link_lists(dev, upper_dev, 1, |
5741 | &dev->adj_list.upper, | 5747 | &dev->adj_list.upper, |
5742 | &upper_dev->adj_list.lower, | 5748 | &upper_dev->adj_list.lower, |
5743 | private, master); | 5749 | private, master); |
5744 | if (ret) { | 5750 | if (ret) { |
5745 | __netdev_adjacent_dev_unlink(dev, upper_dev); | 5751 | __netdev_adjacent_dev_unlink(dev, upper_dev, 1); |
5746 | return ret; | 5752 | return ret; |
5747 | } | 5753 | } |
5748 | 5754 | ||
@@ -5752,8 +5758,8 @@ static int __netdev_adjacent_dev_link_neighbour(struct net_device *dev, | |||
5752 | static void __netdev_adjacent_dev_unlink_neighbour(struct net_device *dev, | 5758 | static void __netdev_adjacent_dev_unlink_neighbour(struct net_device *dev, |
5753 | struct net_device *upper_dev) | 5759 | struct net_device *upper_dev) |
5754 | { | 5760 | { |
5755 | __netdev_adjacent_dev_unlink(dev, upper_dev); | 5761 | __netdev_adjacent_dev_unlink(dev, upper_dev, 1); |
5756 | __netdev_adjacent_dev_unlink_lists(dev, upper_dev, | 5762 | __netdev_adjacent_dev_unlink_lists(dev, upper_dev, 1, |
5757 | &dev->adj_list.upper, | 5763 | &dev->adj_list.upper, |
5758 | &upper_dev->adj_list.lower); | 5764 | &upper_dev->adj_list.lower); |
5759 | } | 5765 | } |
@@ -5806,7 +5812,7 @@ static int __netdev_upper_dev_link(struct net_device *dev, | |||
5806 | list_for_each_entry(j, &upper_dev->all_adj_list.upper, list) { | 5812 | list_for_each_entry(j, &upper_dev->all_adj_list.upper, list) { |
5807 | pr_debug("Interlinking %s with %s, non-neighbour\n", | 5813 | pr_debug("Interlinking %s with %s, non-neighbour\n", |
5808 | i->dev->name, j->dev->name); | 5814 | i->dev->name, j->dev->name); |
5809 | ret = __netdev_adjacent_dev_link(i->dev, j->dev); | 5815 | ret = __netdev_adjacent_dev_link(i->dev, j->dev, i->ref_nr); |
5810 | if (ret) | 5816 | if (ret) |
5811 | goto rollback_mesh; | 5817 | goto rollback_mesh; |
5812 | } | 5818 | } |
@@ -5816,7 +5822,7 @@ static int __netdev_upper_dev_link(struct net_device *dev, | |||
5816 | list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) { | 5822 | list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) { |
5817 | pr_debug("linking %s's upper device %s with %s\n", | 5823 | pr_debug("linking %s's upper device %s with %s\n", |
5818 | upper_dev->name, i->dev->name, dev->name); | 5824 | upper_dev->name, i->dev->name, dev->name); |
5819 | ret = __netdev_adjacent_dev_link(dev, i->dev); | 5825 | ret = __netdev_adjacent_dev_link(dev, i->dev, i->ref_nr); |
5820 | if (ret) | 5826 | if (ret) |
5821 | goto rollback_upper_mesh; | 5827 | goto rollback_upper_mesh; |
5822 | } | 5828 | } |
@@ -5825,7 +5831,7 @@ static int __netdev_upper_dev_link(struct net_device *dev, | |||
5825 | list_for_each_entry(i, &dev->all_adj_list.lower, list) { | 5831 | list_for_each_entry(i, &dev->all_adj_list.lower, list) { |
5826 | pr_debug("linking %s's lower device %s with %s\n", dev->name, | 5832 | pr_debug("linking %s's lower device %s with %s\n", dev->name, |
5827 | i->dev->name, upper_dev->name); | 5833 | i->dev->name, upper_dev->name); |
5828 | ret = __netdev_adjacent_dev_link(i->dev, upper_dev); | 5834 | ret = __netdev_adjacent_dev_link(i->dev, upper_dev, i->ref_nr); |
5829 | if (ret) | 5835 | if (ret) |
5830 | goto rollback_lower_mesh; | 5836 | goto rollback_lower_mesh; |
5831 | } | 5837 | } |
@@ -5843,7 +5849,7 @@ rollback_lower_mesh: | |||
5843 | list_for_each_entry(i, &dev->all_adj_list.lower, list) { | 5849 | list_for_each_entry(i, &dev->all_adj_list.lower, list) { |
5844 | if (i == to_i) | 5850 | if (i == to_i) |
5845 | break; | 5851 | break; |
5846 | __netdev_adjacent_dev_unlink(i->dev, upper_dev); | 5852 | __netdev_adjacent_dev_unlink(i->dev, upper_dev, i->ref_nr); |
5847 | } | 5853 | } |
5848 | 5854 | ||
5849 | i = NULL; | 5855 | i = NULL; |
@@ -5853,7 +5859,7 @@ rollback_upper_mesh: | |||
5853 | list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) { | 5859 | list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) { |
5854 | if (i == to_i) | 5860 | if (i == to_i) |
5855 | break; | 5861 | break; |
5856 | __netdev_adjacent_dev_unlink(dev, i->dev); | 5862 | __netdev_adjacent_dev_unlink(dev, i->dev, i->ref_nr); |
5857 | } | 5863 | } |
5858 | 5864 | ||
5859 | i = j = NULL; | 5865 | i = j = NULL; |
@@ -5865,7 +5871,7 @@ rollback_mesh: | |||
5865 | list_for_each_entry(j, &upper_dev->all_adj_list.upper, list) { | 5871 | list_for_each_entry(j, &upper_dev->all_adj_list.upper, list) { |
5866 | if (i == to_i && j == to_j) | 5872 | if (i == to_i && j == to_j) |
5867 | break; | 5873 | break; |
5868 | __netdev_adjacent_dev_unlink(i->dev, j->dev); | 5874 | __netdev_adjacent_dev_unlink(i->dev, j->dev, i->ref_nr); |
5869 | } | 5875 | } |
5870 | if (i == to_i) | 5876 | if (i == to_i) |
5871 | break; | 5877 | break; |
@@ -5945,16 +5951,16 @@ void netdev_upper_dev_unlink(struct net_device *dev, | |||
5945 | */ | 5951 | */ |
5946 | list_for_each_entry(i, &dev->all_adj_list.lower, list) | 5952 | list_for_each_entry(i, &dev->all_adj_list.lower, list) |
5947 | list_for_each_entry(j, &upper_dev->all_adj_list.upper, list) | 5953 | list_for_each_entry(j, &upper_dev->all_adj_list.upper, list) |
5948 | __netdev_adjacent_dev_unlink(i->dev, j->dev); | 5954 | __netdev_adjacent_dev_unlink(i->dev, j->dev, i->ref_nr); |
5949 | 5955 | ||
5950 | /* remove also the devices itself from lower/upper device | 5956 | /* remove also the devices itself from lower/upper device |
5951 | * list | 5957 | * list |
5952 | */ | 5958 | */ |
5953 | list_for_each_entry(i, &dev->all_adj_list.lower, list) | 5959 | list_for_each_entry(i, &dev->all_adj_list.lower, list) |
5954 | __netdev_adjacent_dev_unlink(i->dev, upper_dev); | 5960 | __netdev_adjacent_dev_unlink(i->dev, upper_dev, i->ref_nr); |
5955 | 5961 | ||
5956 | list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) | 5962 | list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) |
5957 | __netdev_adjacent_dev_unlink(dev, i->dev); | 5963 | __netdev_adjacent_dev_unlink(dev, i->dev, i->ref_nr); |
5958 | 5964 | ||
5959 | call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, dev, | 5965 | call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, dev, |
5960 | &changeupper_info.info); | 5966 | &changeupper_info.info); |