| From foo@baz Wed May 28 21:03:54 PDT 2014 |
| From: Vlad Yasevich <vyasevic@redhat.com> |
| Date: Fri, 16 May 2014 17:04:55 -0400 |
| Subject: vlan: Fix lockdep warning with stacked vlan devices. |
| |
| From: Vlad Yasevich <vyasevic@redhat.com> |
| |
| [ Upstream commit d38569ab2bba6e6b3233acfc3a84cdbcfbd1f79f ] |
| |
| This reverts commit dc8eaaa006350d24030502a4521542e74b5cb39f. |
| vlan: Fix lockdep warning when vlan dev handle notification |
| |
| Instead we use the new new API to find the lock subclass of |
| our vlan device. This way we can support configurations where |
| vlans are interspersed with other devices: |
| bond -> vlan -> macvlan -> vlan |
| |
| Signed-off-by: Vlad Yasevich <vyasevic@redhat.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| include/linux/if_vlan.h | 3 +- |
| net/8021q/vlan.c | 1 |
| net/8021q/vlan_dev.c | 53 +++++++++--------------------------------------- |
| net/core/dev.c | 1 |
| 4 files changed, 13 insertions(+), 45 deletions(-) |
| |
| --- a/include/linux/if_vlan.h |
| +++ b/include/linux/if_vlan.h |
| @@ -73,7 +73,7 @@ static inline struct vlan_ethhdr *vlan_e |
| /* found in socket.c */ |
| extern void vlan_ioctl_set(int (*hook)(struct net *, void __user *)); |
| |
| -static inline int is_vlan_dev(struct net_device *dev) |
| +static inline bool is_vlan_dev(struct net_device *dev) |
| { |
| return dev->priv_flags & IFF_802_1Q_VLAN; |
| } |
| @@ -158,6 +158,7 @@ struct vlan_dev_priv { |
| #ifdef CONFIG_NET_POLL_CONTROLLER |
| struct netpoll *netpoll; |
| #endif |
| + unsigned int nest_level; |
| }; |
| |
| static inline struct vlan_dev_priv *vlan_dev_priv(const struct net_device *dev) |
| --- a/net/8021q/vlan.c |
| +++ b/net/8021q/vlan.c |
| @@ -169,6 +169,7 @@ int register_vlan_dev(struct net_device |
| if (err < 0) |
| goto out_uninit_mvrp; |
| |
| + vlan->nest_level = dev_get_nest_level(real_dev, is_vlan_dev) + 1; |
| err = register_netdevice(dev); |
| if (err < 0) |
| goto out_uninit_mvrp; |
| --- a/net/8021q/vlan_dev.c |
| +++ b/net/8021q/vlan_dev.c |
| @@ -493,48 +493,10 @@ static void vlan_dev_change_rx_flags(str |
| } |
| } |
| |
| -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) |
| { |
| - 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); |
| + dev_mc_sync(vlan_dev_priv(vlan_dev)->real_dev, vlan_dev); |
| + dev_uc_sync(vlan_dev_priv(vlan_dev)->real_dev, vlan_dev); |
| } |
| |
| /* |
| @@ -562,6 +524,11 @@ static void vlan_dev_set_lockdep_class(s |
| netdev_for_each_tx_queue(dev, vlan_dev_set_lockdep_one, &subclass); |
| } |
| |
| +static int vlan_dev_get_lock_subclass(struct net_device *dev) |
| +{ |
| + return vlan_dev_priv(dev)->nest_level; |
| +} |
| + |
| static const struct header_ops vlan_header_ops = { |
| .create = vlan_dev_hard_header, |
| .rebuild = vlan_dev_rebuild_header, |
| @@ -597,7 +564,7 @@ static const struct net_device_ops vlan_ |
| static int vlan_dev_init(struct net_device *dev) |
| { |
| struct net_device *real_dev = vlan_dev_priv(dev)->real_dev; |
| - int subclass = 0, i; |
| + int i; |
| |
| netif_carrier_off(dev); |
| |
| @@ -646,8 +613,7 @@ static int vlan_dev_init(struct net_devi |
| |
| SET_NETDEV_DEVTYPE(dev, &vlan_type); |
| |
| - subclass = vlan_calculate_locking_subclass(dev); |
| - vlan_dev_set_lockdep_class(dev, subclass); |
| + vlan_dev_set_lockdep_class(dev, vlan_dev_get_lock_subclass(dev)); |
| |
| vlan_dev_priv(dev)->vlan_pcpu_stats = alloc_percpu(struct vlan_pcpu_stats); |
| if (!vlan_dev_priv(dev)->vlan_pcpu_stats) |
| @@ -827,6 +793,7 @@ static const struct net_device_ops vlan_ |
| .ndo_netpoll_cleanup = vlan_dev_netpoll_cleanup, |
| #endif |
| .ndo_fix_features = vlan_dev_fix_features, |
| + .ndo_get_lock_subclass = vlan_dev_get_lock_subclass, |
| }; |
| |
| void vlan_setup(struct net_device *dev) |
| --- a/net/core/dev.c |
| +++ b/net/core/dev.c |
| @@ -5269,7 +5269,6 @@ void __dev_set_rx_mode(struct net_device |
| 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) |
| { |