summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/core/dev.c68
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
5590static int __netdev_adjacent_dev_insert(struct net_device *dev, 5590static 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
5648static void __netdev_adjacent_dev_remove(struct net_device *dev, 5649static 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
5682static int __netdev_adjacent_dev_link_lists(struct net_device *dev, 5684static 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
5705static int __netdev_adjacent_dev_link(struct net_device *dev, 5708static 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
5714static void __netdev_adjacent_dev_unlink_lists(struct net_device *dev, 5718static 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
5723static void __netdev_adjacent_dev_unlink(struct net_device *dev, 5728static 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,
5752static void __netdev_adjacent_dev_unlink_neighbour(struct net_device *dev, 5758static 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);