Skip to content

Commit 6bd64ac

Browse files
committed
Merge branch 'stacked_netdevice_locking'
Vlad Yasevich says: ==================== Fix lockdep issues with stacked devices Recent commit dc8eaaa vlan: Fix lockdep warning when vlan dev handle notification attempted to solve lockdep issues with vlans where multiple vlans were stacked. However, the code does not work correctly when the vlan stack is interspersed with other devices in between the vlans. Additionally, similar lockdep issues show up with other devices. This series provides a generic way to solve these issue for any devices that can be stacked. It also addresses the concern for vlan and macvlan devices. I am not sure whether it makes sense to do so for other types like team, vxlan, and bond. Thanks -vlad Since v2: - Remove rcu variants from patch1, since that function is called only under rtnl. - Fix whitespace problems reported by checkpatch Since v1: - Fixed up a goofed-up rebase. * is_vlan_dev() should be bool and that change belongs in patch3. * patch4 should not have any vlan changes in it. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 29e9824 + c674ac3 commit 6bd64ac

File tree

7 files changed

+90
-48
lines changed

7 files changed

+90
-48
lines changed

drivers/net/macvlan.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,11 @@ static struct lock_class_key macvlan_netdev_addr_lock_key;
517517
#define MACVLAN_STATE_MASK \
518518
((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT))
519519

520+
static int macvlan_get_nest_level(struct net_device *dev)
521+
{
522+
return ((struct macvlan_dev *)netdev_priv(dev))->nest_level;
523+
}
524+
520525
static void macvlan_set_lockdep_class_one(struct net_device *dev,
521526
struct netdev_queue *txq,
522527
void *_unused)
@@ -527,8 +532,9 @@ static void macvlan_set_lockdep_class_one(struct net_device *dev,
527532

528533
static void macvlan_set_lockdep_class(struct net_device *dev)
529534
{
530-
lockdep_set_class(&dev->addr_list_lock,
531-
&macvlan_netdev_addr_lock_key);
535+
lockdep_set_class_and_subclass(&dev->addr_list_lock,
536+
&macvlan_netdev_addr_lock_key,
537+
macvlan_get_nest_level(dev));
532538
netdev_for_each_tx_queue(dev, macvlan_set_lockdep_class_one, NULL);
533539
}
534540

@@ -723,6 +729,7 @@ static const struct net_device_ops macvlan_netdev_ops = {
723729
.ndo_fdb_add = macvlan_fdb_add,
724730
.ndo_fdb_del = macvlan_fdb_del,
725731
.ndo_fdb_dump = ndo_dflt_fdb_dump,
732+
.ndo_get_lock_subclass = macvlan_get_nest_level,
726733
};
727734

728735
void macvlan_common_setup(struct net_device *dev)
@@ -851,6 +858,7 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
851858
vlan->dev = dev;
852859
vlan->port = port;
853860
vlan->set_features = MACVLAN_FEATURES;
861+
vlan->nest_level = dev_get_nest_level(lowerdev, netif_is_macvlan) + 1;
854862

855863
vlan->mode = MACVLAN_MODE_VEPA;
856864
if (data && data[IFLA_MACVLAN_MODE])

include/linux/if_macvlan.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ struct macvlan_dev {
5656
int numqueues;
5757
netdev_features_t tap_features;
5858
int minor;
59+
int nest_level;
5960
};
6061

6162
static inline void macvlan_count_rx(const struct macvlan_dev *vlan,

include/linux/if_vlan.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ static inline struct vlan_ethhdr *vlan_eth_hdr(const struct sk_buff *skb)
7373
/* found in socket.c */
7474
extern void vlan_ioctl_set(int (*hook)(struct net *, void __user *));
7575

76-
static inline int is_vlan_dev(struct net_device *dev)
76+
static inline bool is_vlan_dev(struct net_device *dev)
7777
{
7878
return dev->priv_flags & IFF_802_1Q_VLAN;
7979
}
@@ -159,6 +159,7 @@ struct vlan_dev_priv {
159159
#ifdef CONFIG_NET_POLL_CONTROLLER
160160
struct netpoll *netpoll;
161161
#endif
162+
unsigned int nest_level;
162163
};
163164

164165
static inline struct vlan_dev_priv *vlan_dev_priv(const struct net_device *dev)

include/linux/netdevice.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1144,6 +1144,7 @@ struct net_device_ops {
11441144
netdev_tx_t (*ndo_dfwd_start_xmit) (struct sk_buff *skb,
11451145
struct net_device *dev,
11461146
void *priv);
1147+
int (*ndo_get_lock_subclass)(struct net_device *dev);
11471148
};
11481149

11491150
/**
@@ -2950,7 +2951,12 @@ static inline void netif_addr_lock(struct net_device *dev)
29502951

29512952
static inline void netif_addr_lock_nested(struct net_device *dev)
29522953
{
2953-
spin_lock_nested(&dev->addr_list_lock, SINGLE_DEPTH_NESTING);
2954+
int subclass = SINGLE_DEPTH_NESTING;
2955+
2956+
if (dev->netdev_ops->ndo_get_lock_subclass)
2957+
subclass = dev->netdev_ops->ndo_get_lock_subclass(dev);
2958+
2959+
spin_lock_nested(&dev->addr_list_lock, subclass);
29542960
}
29552961

29562962
static inline void netif_addr_lock_bh(struct net_device *dev)
@@ -3077,6 +3083,14 @@ void *netdev_lower_get_next_private_rcu(struct net_device *dev,
30773083
priv; \
30783084
priv = netdev_lower_get_next_private_rcu(dev, &(iter)))
30793085

3086+
void *netdev_lower_get_next(struct net_device *dev,
3087+
struct list_head **iter);
3088+
#define netdev_for_each_lower_dev(dev, ldev, iter) \
3089+
for (iter = &(dev)->adj_list.lower, \
3090+
ldev = netdev_lower_get_next(dev, &(iter)); \
3091+
ldev; \
3092+
ldev = netdev_lower_get_next(dev, &(iter)))
3093+
30803094
void *netdev_adjacent_get_private(struct list_head *adj_list);
30813095
void *netdev_lower_get_first_private_rcu(struct net_device *dev);
30823096
struct net_device *netdev_master_upper_dev_get(struct net_device *dev);
@@ -3092,6 +3106,8 @@ void netdev_upper_dev_unlink(struct net_device *dev,
30923106
void netdev_adjacent_rename_links(struct net_device *dev, char *oldname);
30933107
void *netdev_lower_dev_get_private(struct net_device *dev,
30943108
struct net_device *lower_dev);
3109+
int dev_get_nest_level(struct net_device *dev,
3110+
bool (*type_check)(struct net_device *dev));
30953111
int skb_checksum_help(struct sk_buff *skb);
30963112
struct sk_buff *__skb_gso_segment(struct sk_buff *skb,
30973113
netdev_features_t features, bool tx_path);

net/8021q/vlan.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ int register_vlan_dev(struct net_device *dev)
169169
if (err < 0)
170170
goto out_uninit_mvrp;
171171

172+
vlan->nest_level = dev_get_nest_level(real_dev, is_vlan_dev) + 1;
172173
err = register_netdevice(dev);
173174
if (err < 0)
174175
goto out_uninit_mvrp;

net/8021q/vlan_dev.c

Lines changed: 9 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -493,48 +493,10 @@ static void vlan_dev_change_rx_flags(struct net_device *dev, int change)
493493
}
494494
}
495495

496-
static int vlan_calculate_locking_subclass(struct net_device *real_dev)
497-
{
498-
int subclass = 0;
499-
500-
while (is_vlan_dev(real_dev)) {
501-
subclass++;
502-
real_dev = vlan_dev_priv(real_dev)->real_dev;
503-
}
504-
505-
return subclass;
506-
}
507-
508-
static void vlan_dev_mc_sync(struct net_device *to, struct net_device *from)
509-
{
510-
int err = 0, subclass;
511-
512-
subclass = vlan_calculate_locking_subclass(to);
513-
514-
spin_lock_nested(&to->addr_list_lock, subclass);
515-
err = __hw_addr_sync(&to->mc, &from->mc, to->addr_len);
516-
if (!err)
517-
__dev_set_rx_mode(to);
518-
spin_unlock(&to->addr_list_lock);
519-
}
520-
521-
static void vlan_dev_uc_sync(struct net_device *to, struct net_device *from)
522-
{
523-
int err = 0, subclass;
524-
525-
subclass = vlan_calculate_locking_subclass(to);
526-
527-
spin_lock_nested(&to->addr_list_lock, subclass);
528-
err = __hw_addr_sync(&to->uc, &from->uc, to->addr_len);
529-
if (!err)
530-
__dev_set_rx_mode(to);
531-
spin_unlock(&to->addr_list_lock);
532-
}
533-
534496
static void vlan_dev_set_rx_mode(struct net_device *vlan_dev)
535497
{
536-
vlan_dev_mc_sync(vlan_dev_priv(vlan_dev)->real_dev, vlan_dev);
537-
vlan_dev_uc_sync(vlan_dev_priv(vlan_dev)->real_dev, vlan_dev);
498+
dev_mc_sync(vlan_dev_priv(vlan_dev)->real_dev, vlan_dev);
499+
dev_uc_sync(vlan_dev_priv(vlan_dev)->real_dev, vlan_dev);
538500
}
539501

540502
/*
@@ -562,6 +524,11 @@ static void vlan_dev_set_lockdep_class(struct net_device *dev, int subclass)
562524
netdev_for_each_tx_queue(dev, vlan_dev_set_lockdep_one, &subclass);
563525
}
564526

527+
static int vlan_dev_get_lock_subclass(struct net_device *dev)
528+
{
529+
return vlan_dev_priv(dev)->nest_level;
530+
}
531+
565532
static const struct header_ops vlan_header_ops = {
566533
.create = vlan_dev_hard_header,
567534
.rebuild = vlan_dev_rebuild_header,
@@ -597,7 +564,6 @@ static const struct net_device_ops vlan_netdev_ops;
597564
static int vlan_dev_init(struct net_device *dev)
598565
{
599566
struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
600-
int subclass = 0;
601567

602568
netif_carrier_off(dev);
603569

@@ -646,8 +612,7 @@ static int vlan_dev_init(struct net_device *dev)
646612

647613
SET_NETDEV_DEVTYPE(dev, &vlan_type);
648614

649-
subclass = vlan_calculate_locking_subclass(dev);
650-
vlan_dev_set_lockdep_class(dev, subclass);
615+
vlan_dev_set_lockdep_class(dev, vlan_dev_get_lock_subclass(dev));
651616

652617
vlan_dev_priv(dev)->vlan_pcpu_stats = netdev_alloc_pcpu_stats(struct vlan_pcpu_stats);
653618
if (!vlan_dev_priv(dev)->vlan_pcpu_stats)
@@ -819,6 +784,7 @@ static const struct net_device_ops vlan_netdev_ops = {
819784
.ndo_netpoll_cleanup = vlan_dev_netpoll_cleanup,
820785
#endif
821786
.ndo_fix_features = vlan_dev_fix_features,
787+
.ndo_get_lock_subclass = vlan_dev_get_lock_subclass,
822788
};
823789

824790
void vlan_setup(struct net_device *dev)

net/core/dev.c

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4622,6 +4622,32 @@ void *netdev_lower_get_next_private_rcu(struct net_device *dev,
46224622
}
46234623
EXPORT_SYMBOL(netdev_lower_get_next_private_rcu);
46244624

4625+
/**
4626+
* netdev_lower_get_next - Get the next device from the lower neighbour
4627+
* list
4628+
* @dev: device
4629+
* @iter: list_head ** of the current position
4630+
*
4631+
* Gets the next netdev_adjacent from the dev's lower neighbour
4632+
* list, starting from iter position. The caller must hold RTNL lock or
4633+
* its own locking that guarantees that the neighbour lower
4634+
* list will remain unchainged.
4635+
*/
4636+
void *netdev_lower_get_next(struct net_device *dev, struct list_head **iter)
4637+
{
4638+
struct netdev_adjacent *lower;
4639+
4640+
lower = list_entry((*iter)->next, struct netdev_adjacent, list);
4641+
4642+
if (&lower->list == &dev->adj_list.lower)
4643+
return NULL;
4644+
4645+
*iter = &lower->list;
4646+
4647+
return lower->dev;
4648+
}
4649+
EXPORT_SYMBOL(netdev_lower_get_next);
4650+
46254651
/**
46264652
* netdev_lower_get_first_private_rcu - Get the first ->private from the
46274653
* lower neighbour list, RCU
@@ -5072,6 +5098,30 @@ void *netdev_lower_dev_get_private(struct net_device *dev,
50725098
}
50735099
EXPORT_SYMBOL(netdev_lower_dev_get_private);
50745100

5101+
5102+
int dev_get_nest_level(struct net_device *dev,
5103+
bool (*type_check)(struct net_device *dev))
5104+
{
5105+
struct net_device *lower = NULL;
5106+
struct list_head *iter;
5107+
int max_nest = -1;
5108+
int nest;
5109+
5110+
ASSERT_RTNL();
5111+
5112+
netdev_for_each_lower_dev(dev, lower, iter) {
5113+
nest = dev_get_nest_level(lower, type_check);
5114+
if (max_nest < nest)
5115+
max_nest = nest;
5116+
}
5117+
5118+
if (type_check(dev))
5119+
max_nest++;
5120+
5121+
return max_nest;
5122+
}
5123+
EXPORT_SYMBOL(dev_get_nest_level);
5124+
50755125
static void dev_change_rx_flags(struct net_device *dev, int flags)
50765126
{
50775127
const struct net_device_ops *ops = dev->netdev_ops;
@@ -5237,7 +5287,6 @@ void __dev_set_rx_mode(struct net_device *dev)
52375287
if (ops->ndo_set_rx_mode)
52385288
ops->ndo_set_rx_mode(dev);
52395289
}
5240-
EXPORT_SYMBOL(__dev_set_rx_mode);
52415290

52425291
void dev_set_rx_mode(struct net_device *dev)
52435292
{

0 commit comments

Comments
 (0)