diff options
Diffstat (limited to 'net/8021q/vlan_dev.c')
| -rw-r--r-- | net/8021q/vlan_dev.c | 46 | 
1 files changed, 41 insertions, 5 deletions
| diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 6f142f03716d..733ec283ed1b 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); | 
