diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 6f142f03716d04effac77f0e2210879eff3daddb..733ec283ed1b9e85f9181f67116052f88bb49951 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -493,10 +493,48 @@ static void vlan_dev_change_rx_flags(struct net_device *dev, int change) } } +static int vlan_calculate_locking_subclass(struct net_device *real_dev) +{ + int subclass = 0; + + while (is_vlan_dev(real_dev)) { + subclass++; + real_dev = vlan_dev_priv(real_dev)->real_dev; + } + + return subclass; +} + +static void vlan_dev_mc_sync(struct net_device *to, struct net_device *from) +{ + int err = 0, subclass; + + subclass = vlan_calculate_locking_subclass(to); + + spin_lock_nested(&to->addr_list_lock, subclass); + err = __hw_addr_sync(&to->mc, &from->mc, to->addr_len); + if (!err) + __dev_set_rx_mode(to); + spin_unlock(&to->addr_list_lock); +} + +static void vlan_dev_uc_sync(struct net_device *to, struct net_device *from) +{ + int err = 0, subclass; + + subclass = vlan_calculate_locking_subclass(to); + + spin_lock_nested(&to->addr_list_lock, subclass); + err = __hw_addr_sync(&to->uc, &from->uc, to->addr_len); + if (!err) + __dev_set_rx_mode(to); + spin_unlock(&to->addr_list_lock); +} + static void vlan_dev_set_rx_mode(struct net_device *vlan_dev) { - dev_mc_sync(vlan_dev_priv(vlan_dev)->real_dev, vlan_dev); - dev_uc_sync(vlan_dev_priv(vlan_dev)->real_dev, vlan_dev); + vlan_dev_mc_sync(vlan_dev_priv(vlan_dev)->real_dev, vlan_dev); + vlan_dev_uc_sync(vlan_dev_priv(vlan_dev)->real_dev, vlan_dev); } /* @@ -608,9 +646,7 @@ static int vlan_dev_init(struct net_device *dev) SET_NETDEV_DEVTYPE(dev, &vlan_type); - if (is_vlan_dev(real_dev)) - subclass = 1; - + subclass = vlan_calculate_locking_subclass(dev); vlan_dev_set_lockdep_class(dev, subclass); vlan_dev_priv(dev)->vlan_pcpu_stats = netdev_alloc_pcpu_stats(struct vlan_pcpu_stats); diff --git a/net/core/dev.c b/net/core/dev.c index 5b3042e69f85646961a910977e041fc16a94cc78..d2c8a06b3a9883b618c55a8cddf0929a4bcd049f 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5238,6 +5238,7 @@ void __dev_set_rx_mode(struct net_device *dev) if (ops->ndo_set_rx_mode) ops->ndo_set_rx_mode(dev); } +EXPORT_SYMBOL(__dev_set_rx_mode); void dev_set_rx_mode(struct net_device *dev) {