Merge branch 'net-core-fix-a-lockdep-splat-in-the-dev_addr_list'
Taehee Yoo says: ==================== net: core: fix a lockdep splat in the dev_addr_list. This patchset is to avoid lockdep splat. When a stacked interface graph is changed, netif_addr_lock() is called recursively and it internally calls spin_lock_nested(). The parameter of spin_lock_nested() is 'dev->lower_level', this is called subclass. The problem of 'dev->lower_level' is that while 'dev->lower_level' is being used as a subclass of spin_lock_nested(), its value can be changed. So, spin_lock_nested() would be called recursively with the same subclass value, the lockdep understands a deadlock. In order to avoid this, a new variable is needed and it is going to be used as a parameter of spin_lock_nested(). The first and second patch is a preparation patch for the third patch. In the third patch, the problem will be fixed. The first patch is to add __netdev_upper_dev_unlink(). An existed netdev_upper_dev_unlink() is renamed to __netdev_upper_dev_unlink(). and netdev_upper_dev_unlink() is added as an wrapper of this function. The second patch is to add the netdev_nested_priv structure. netdev_walk_all_{ upper | lower }_dev() pass both private functions and "data" pointer to handle their own things. At this point, the data pointer type is void *. In order to make it easier to expand common variables and functions, this new netdev_nested_priv structure is added. The third patch is to add a new variable 'nested_level' into the net_device structure. This variable will be used as a parameter of spin_lock_nested() of dev->addr_list_lock. Due to this variable, it can avoid lockdep splat. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
0ba56b89fa
|
@ -1320,9 +1320,10 @@ struct net_device *rdma_read_gid_attr_ndev_rcu(const struct ib_gid_attr *attr)
|
|||
}
|
||||
EXPORT_SYMBOL(rdma_read_gid_attr_ndev_rcu);
|
||||
|
||||
static int get_lower_dev_vlan(struct net_device *lower_dev, void *data)
|
||||
static int get_lower_dev_vlan(struct net_device *lower_dev,
|
||||
struct netdev_nested_priv *priv)
|
||||
{
|
||||
u16 *vlan_id = data;
|
||||
u16 *vlan_id = (u16 *)priv->data;
|
||||
|
||||
if (is_vlan_dev(lower_dev))
|
||||
*vlan_id = vlan_dev_vlan_id(lower_dev);
|
||||
|
@ -1348,6 +1349,9 @@ static int get_lower_dev_vlan(struct net_device *lower_dev, void *data)
|
|||
int rdma_read_gid_l2_fields(const struct ib_gid_attr *attr,
|
||||
u16 *vlan_id, u8 *smac)
|
||||
{
|
||||
struct netdev_nested_priv priv = {
|
||||
.data = (void *)vlan_id,
|
||||
};
|
||||
struct net_device *ndev;
|
||||
|
||||
rcu_read_lock();
|
||||
|
@ -1368,7 +1372,7 @@ int rdma_read_gid_l2_fields(const struct ib_gid_attr *attr,
|
|||
* the lower vlan device for this gid entry.
|
||||
*/
|
||||
netdev_walk_all_lower_dev_rcu(attr->ndev,
|
||||
get_lower_dev_vlan, vlan_id);
|
||||
get_lower_dev_vlan, &priv);
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
|
|
@ -2865,9 +2865,10 @@ struct iboe_prio_tc_map {
|
|||
bool found;
|
||||
};
|
||||
|
||||
static int get_lower_vlan_dev_tc(struct net_device *dev, void *data)
|
||||
static int get_lower_vlan_dev_tc(struct net_device *dev,
|
||||
struct netdev_nested_priv *priv)
|
||||
{
|
||||
struct iboe_prio_tc_map *map = data;
|
||||
struct iboe_prio_tc_map *map = (struct iboe_prio_tc_map *)priv->data;
|
||||
|
||||
if (is_vlan_dev(dev))
|
||||
map->output_tc = get_vlan_ndev_tc(dev, map->input_prio);
|
||||
|
@ -2886,16 +2887,18 @@ static int iboe_tos_to_sl(struct net_device *ndev, int tos)
|
|||
{
|
||||
struct iboe_prio_tc_map prio_tc_map = {};
|
||||
int prio = rt_tos2priority(tos);
|
||||
struct netdev_nested_priv priv;
|
||||
|
||||
/* If VLAN device, get it directly from the VLAN netdev */
|
||||
if (is_vlan_dev(ndev))
|
||||
return get_vlan_ndev_tc(ndev, prio);
|
||||
|
||||
prio_tc_map.input_prio = prio;
|
||||
priv.data = (void *)&prio_tc_map;
|
||||
rcu_read_lock();
|
||||
netdev_walk_all_lower_dev_rcu(ndev,
|
||||
get_lower_vlan_dev_tc,
|
||||
&prio_tc_map);
|
||||
&priv);
|
||||
rcu_read_unlock();
|
||||
/* If map is found from lower device, use it; Otherwise
|
||||
* continue with the current netdevice to get priority to tc map.
|
||||
|
|
|
@ -531,10 +531,11 @@ struct upper_list {
|
|||
struct net_device *upper;
|
||||
};
|
||||
|
||||
static int netdev_upper_walk(struct net_device *upper, void *data)
|
||||
static int netdev_upper_walk(struct net_device *upper,
|
||||
struct netdev_nested_priv *priv)
|
||||
{
|
||||
struct upper_list *entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
|
||||
struct list_head *upper_list = data;
|
||||
struct list_head *upper_list = (struct list_head *)priv->data;
|
||||
|
||||
if (!entry)
|
||||
return 0;
|
||||
|
@ -553,12 +554,14 @@ static void handle_netdev_upper(struct ib_device *ib_dev, u8 port,
|
|||
struct net_device *ndev))
|
||||
{
|
||||
struct net_device *ndev = cookie;
|
||||
struct netdev_nested_priv priv;
|
||||
struct upper_list *upper_iter;
|
||||
struct upper_list *upper_temp;
|
||||
LIST_HEAD(upper_list);
|
||||
|
||||
priv.data = &upper_list;
|
||||
rcu_read_lock();
|
||||
netdev_walk_all_upper_dev_rcu(ndev, netdev_upper_walk, &upper_list);
|
||||
netdev_walk_all_upper_dev_rcu(ndev, netdev_upper_walk, &priv);
|
||||
rcu_read_unlock();
|
||||
|
||||
handle_netdev(ib_dev, port, ndev);
|
||||
|
|
|
@ -342,9 +342,10 @@ struct ipoib_walk_data {
|
|||
struct net_device *result;
|
||||
};
|
||||
|
||||
static int ipoib_upper_walk(struct net_device *upper, void *_data)
|
||||
static int ipoib_upper_walk(struct net_device *upper,
|
||||
struct netdev_nested_priv *priv)
|
||||
{
|
||||
struct ipoib_walk_data *data = _data;
|
||||
struct ipoib_walk_data *data = (struct ipoib_walk_data *)priv->data;
|
||||
int ret = 0;
|
||||
|
||||
if (ipoib_is_dev_match_addr_rcu(data->addr, upper)) {
|
||||
|
@ -368,10 +369,12 @@ static int ipoib_upper_walk(struct net_device *upper, void *_data)
|
|||
static struct net_device *ipoib_get_net_dev_match_addr(
|
||||
const struct sockaddr *addr, struct net_device *dev)
|
||||
{
|
||||
struct netdev_nested_priv priv;
|
||||
struct ipoib_walk_data data = {
|
||||
.addr = addr,
|
||||
};
|
||||
|
||||
priv.data = (void *)&data;
|
||||
rcu_read_lock();
|
||||
if (ipoib_is_dev_match_addr_rcu(addr, dev)) {
|
||||
dev_hold(dev);
|
||||
|
@ -379,7 +382,7 @@ static struct net_device *ipoib_get_net_dev_match_addr(
|
|||
goto out;
|
||||
}
|
||||
|
||||
netdev_walk_all_upper_dev_rcu(dev, ipoib_upper_walk, &data);
|
||||
netdev_walk_all_upper_dev_rcu(dev, ipoib_upper_walk, &priv);
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
return data.result;
|
||||
|
|
|
@ -942,9 +942,10 @@ struct alb_walk_data {
|
|||
bool strict_match;
|
||||
};
|
||||
|
||||
static int alb_upper_dev_walk(struct net_device *upper, void *_data)
|
||||
static int alb_upper_dev_walk(struct net_device *upper,
|
||||
struct netdev_nested_priv *priv)
|
||||
{
|
||||
struct alb_walk_data *data = _data;
|
||||
struct alb_walk_data *data = (struct alb_walk_data *)priv->data;
|
||||
bool strict_match = data->strict_match;
|
||||
struct bonding *bond = data->bond;
|
||||
struct slave *slave = data->slave;
|
||||
|
@ -983,6 +984,7 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[],
|
|||
bool strict_match)
|
||||
{
|
||||
struct bonding *bond = bond_get_bond_by_slave(slave);
|
||||
struct netdev_nested_priv priv;
|
||||
struct alb_walk_data data = {
|
||||
.strict_match = strict_match,
|
||||
.mac_addr = mac_addr,
|
||||
|
@ -990,6 +992,7 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[],
|
|||
.bond = bond,
|
||||
};
|
||||
|
||||
priv.data = (void *)&data;
|
||||
/* send untagged */
|
||||
alb_send_lp_vid(slave, mac_addr, 0, 0);
|
||||
|
||||
|
@ -997,7 +1000,7 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[],
|
|||
* for that device.
|
||||
*/
|
||||
rcu_read_lock();
|
||||
netdev_walk_all_upper_dev_rcu(bond->dev, alb_upper_dev_walk, &data);
|
||||
netdev_walk_all_upper_dev_rcu(bond->dev, alb_upper_dev_walk, &priv);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
|
|
|
@ -2511,22 +2511,26 @@ re_arm:
|
|||
}
|
||||
}
|
||||
|
||||
static int bond_upper_dev_walk(struct net_device *upper, void *data)
|
||||
static int bond_upper_dev_walk(struct net_device *upper,
|
||||
struct netdev_nested_priv *priv)
|
||||
{
|
||||
__be32 ip = *((__be32 *)data);
|
||||
__be32 ip = *(__be32 *)priv->data;
|
||||
|
||||
return ip == bond_confirm_addr(upper, 0, ip);
|
||||
}
|
||||
|
||||
static bool bond_has_this_ip(struct bonding *bond, __be32 ip)
|
||||
{
|
||||
struct netdev_nested_priv priv = {
|
||||
.data = (void *)&ip,
|
||||
};
|
||||
bool ret = false;
|
||||
|
||||
if (ip == bond_confirm_addr(bond->dev, 0, ip))
|
||||
return true;
|
||||
|
||||
rcu_read_lock();
|
||||
if (netdev_walk_all_upper_dev_rcu(bond->dev, bond_upper_dev_walk, &ip))
|
||||
if (netdev_walk_all_upper_dev_rcu(bond->dev, bond_upper_dev_walk, &priv))
|
||||
ret = true;
|
||||
rcu_read_unlock();
|
||||
|
||||
|
|
|
@ -5396,9 +5396,10 @@ static int ixgbe_fwd_ring_up(struct ixgbe_adapter *adapter,
|
|||
return err;
|
||||
}
|
||||
|
||||
static int ixgbe_macvlan_up(struct net_device *vdev, void *data)
|
||||
static int ixgbe_macvlan_up(struct net_device *vdev,
|
||||
struct netdev_nested_priv *priv)
|
||||
{
|
||||
struct ixgbe_adapter *adapter = data;
|
||||
struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)priv->data;
|
||||
struct ixgbe_fwd_adapter *accel;
|
||||
|
||||
if (!netif_is_macvlan(vdev))
|
||||
|
@ -5415,8 +5416,12 @@ static int ixgbe_macvlan_up(struct net_device *vdev, void *data)
|
|||
|
||||
static void ixgbe_configure_dfwd(struct ixgbe_adapter *adapter)
|
||||
{
|
||||
struct netdev_nested_priv priv = {
|
||||
.data = (void *)adapter,
|
||||
};
|
||||
|
||||
netdev_walk_all_upper_dev_rcu(adapter->netdev,
|
||||
ixgbe_macvlan_up, adapter);
|
||||
ixgbe_macvlan_up, &priv);
|
||||
}
|
||||
|
||||
static void ixgbe_configure(struct ixgbe_adapter *adapter)
|
||||
|
@ -9023,9 +9028,10 @@ static void ixgbe_set_prio_tc_map(struct ixgbe_adapter *adapter)
|
|||
}
|
||||
|
||||
#endif /* CONFIG_IXGBE_DCB */
|
||||
static int ixgbe_reassign_macvlan_pool(struct net_device *vdev, void *data)
|
||||
static int ixgbe_reassign_macvlan_pool(struct net_device *vdev,
|
||||
struct netdev_nested_priv *priv)
|
||||
{
|
||||
struct ixgbe_adapter *adapter = data;
|
||||
struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)priv->data;
|
||||
struct ixgbe_fwd_adapter *accel;
|
||||
int pool;
|
||||
|
||||
|
@ -9062,13 +9068,16 @@ static int ixgbe_reassign_macvlan_pool(struct net_device *vdev, void *data)
|
|||
static void ixgbe_defrag_macvlan_pools(struct net_device *dev)
|
||||
{
|
||||
struct ixgbe_adapter *adapter = netdev_priv(dev);
|
||||
struct netdev_nested_priv priv = {
|
||||
.data = (void *)adapter,
|
||||
};
|
||||
|
||||
/* flush any stale bits out of the fwd bitmask */
|
||||
bitmap_clear(adapter->fwd_bitmask, 1, 63);
|
||||
|
||||
/* walk through upper devices reassigning pools */
|
||||
netdev_walk_all_upper_dev_rcu(dev, ixgbe_reassign_macvlan_pool,
|
||||
adapter);
|
||||
&priv);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -9242,14 +9251,18 @@ struct upper_walk_data {
|
|||
u8 queue;
|
||||
};
|
||||
|
||||
static int get_macvlan_queue(struct net_device *upper, void *_data)
|
||||
static int get_macvlan_queue(struct net_device *upper,
|
||||
struct netdev_nested_priv *priv)
|
||||
{
|
||||
if (netif_is_macvlan(upper)) {
|
||||
struct ixgbe_fwd_adapter *vadapter = macvlan_accel_priv(upper);
|
||||
struct upper_walk_data *data = _data;
|
||||
struct ixgbe_adapter *adapter = data->adapter;
|
||||
int ifindex = data->ifindex;
|
||||
struct ixgbe_adapter *adapter;
|
||||
struct upper_walk_data *data;
|
||||
int ifindex;
|
||||
|
||||
data = (struct upper_walk_data *)priv->data;
|
||||
ifindex = data->ifindex;
|
||||
adapter = data->adapter;
|
||||
if (vadapter && upper->ifindex == ifindex) {
|
||||
data->queue = adapter->rx_ring[vadapter->rx_base_queue]->reg_idx;
|
||||
data->action = data->queue;
|
||||
|
@ -9265,6 +9278,7 @@ static int handle_redirect_action(struct ixgbe_adapter *adapter, int ifindex,
|
|||
{
|
||||
struct ixgbe_ring_feature *vmdq = &adapter->ring_feature[RING_F_VMDQ];
|
||||
unsigned int num_vfs = adapter->num_vfs, vf;
|
||||
struct netdev_nested_priv priv;
|
||||
struct upper_walk_data data;
|
||||
struct net_device *upper;
|
||||
|
||||
|
@ -9284,8 +9298,9 @@ static int handle_redirect_action(struct ixgbe_adapter *adapter, int ifindex,
|
|||
data.ifindex = ifindex;
|
||||
data.action = 0;
|
||||
data.queue = 0;
|
||||
priv.data = (void *)&data;
|
||||
if (netdev_walk_all_upper_dev_rcu(adapter->netdev,
|
||||
get_macvlan_queue, &data)) {
|
||||
get_macvlan_queue, &priv)) {
|
||||
*action = data.action;
|
||||
*queue = data.queue;
|
||||
|
||||
|
|
|
@ -3690,13 +3690,13 @@ bool mlxsw_sp_port_dev_check(const struct net_device *dev)
|
|||
return dev->netdev_ops == &mlxsw_sp_port_netdev_ops;
|
||||
}
|
||||
|
||||
static int mlxsw_sp_lower_dev_walk(struct net_device *lower_dev, void *data)
|
||||
static int mlxsw_sp_lower_dev_walk(struct net_device *lower_dev,
|
||||
struct netdev_nested_priv *priv)
|
||||
{
|
||||
struct mlxsw_sp_port **p_mlxsw_sp_port = data;
|
||||
int ret = 0;
|
||||
|
||||
if (mlxsw_sp_port_dev_check(lower_dev)) {
|
||||
*p_mlxsw_sp_port = netdev_priv(lower_dev);
|
||||
priv->data = (void *)netdev_priv(lower_dev);
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
|
@ -3705,15 +3705,16 @@ static int mlxsw_sp_lower_dev_walk(struct net_device *lower_dev, void *data)
|
|||
|
||||
struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find(struct net_device *dev)
|
||||
{
|
||||
struct mlxsw_sp_port *mlxsw_sp_port;
|
||||
struct netdev_nested_priv priv = {
|
||||
.data = NULL,
|
||||
};
|
||||
|
||||
if (mlxsw_sp_port_dev_check(dev))
|
||||
return netdev_priv(dev);
|
||||
|
||||
mlxsw_sp_port = NULL;
|
||||
netdev_walk_all_lower_dev(dev, mlxsw_sp_lower_dev_walk, &mlxsw_sp_port);
|
||||
netdev_walk_all_lower_dev(dev, mlxsw_sp_lower_dev_walk, &priv);
|
||||
|
||||
return mlxsw_sp_port;
|
||||
return (struct mlxsw_sp_port *)priv.data;
|
||||
}
|
||||
|
||||
struct mlxsw_sp *mlxsw_sp_lower_get(struct net_device *dev)
|
||||
|
@ -3726,16 +3727,17 @@ struct mlxsw_sp *mlxsw_sp_lower_get(struct net_device *dev)
|
|||
|
||||
struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find_rcu(struct net_device *dev)
|
||||
{
|
||||
struct mlxsw_sp_port *mlxsw_sp_port;
|
||||
struct netdev_nested_priv priv = {
|
||||
.data = NULL,
|
||||
};
|
||||
|
||||
if (mlxsw_sp_port_dev_check(dev))
|
||||
return netdev_priv(dev);
|
||||
|
||||
mlxsw_sp_port = NULL;
|
||||
netdev_walk_all_lower_dev_rcu(dev, mlxsw_sp_lower_dev_walk,
|
||||
&mlxsw_sp_port);
|
||||
&priv);
|
||||
|
||||
return mlxsw_sp_port;
|
||||
return (struct mlxsw_sp_port *)priv.data;
|
||||
}
|
||||
|
||||
struct mlxsw_sp_port *mlxsw_sp_port_lower_dev_hold(struct net_device *dev)
|
||||
|
|
|
@ -7351,9 +7351,10 @@ int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event,
|
|||
return err;
|
||||
}
|
||||
|
||||
static int __mlxsw_sp_rif_macvlan_flush(struct net_device *dev, void *data)
|
||||
static int __mlxsw_sp_rif_macvlan_flush(struct net_device *dev,
|
||||
struct netdev_nested_priv *priv)
|
||||
{
|
||||
struct mlxsw_sp_rif *rif = data;
|
||||
struct mlxsw_sp_rif *rif = (struct mlxsw_sp_rif *)priv->data;
|
||||
|
||||
if (!netif_is_macvlan(dev))
|
||||
return 0;
|
||||
|
@ -7364,12 +7365,16 @@ static int __mlxsw_sp_rif_macvlan_flush(struct net_device *dev, void *data)
|
|||
|
||||
static int mlxsw_sp_rif_macvlan_flush(struct mlxsw_sp_rif *rif)
|
||||
{
|
||||
struct netdev_nested_priv priv = {
|
||||
.data = (void *)rif,
|
||||
};
|
||||
|
||||
if (!netif_is_macvlan_port(rif->dev))
|
||||
return 0;
|
||||
|
||||
netdev_warn(rif->dev, "Router interface is deleted. Upper macvlans will not work\n");
|
||||
return netdev_walk_all_upper_dev_rcu(rif->dev,
|
||||
__mlxsw_sp_rif_macvlan_flush, rif);
|
||||
__mlxsw_sp_rif_macvlan_flush, &priv);
|
||||
}
|
||||
|
||||
static void mlxsw_sp_rif_subport_setup(struct mlxsw_sp_rif *rif,
|
||||
|
|
|
@ -136,9 +136,9 @@ bool mlxsw_sp_bridge_device_is_offloaded(const struct mlxsw_sp *mlxsw_sp,
|
|||
}
|
||||
|
||||
static int mlxsw_sp_bridge_device_upper_rif_destroy(struct net_device *dev,
|
||||
void *data)
|
||||
struct netdev_nested_priv *priv)
|
||||
{
|
||||
struct mlxsw_sp *mlxsw_sp = data;
|
||||
struct mlxsw_sp *mlxsw_sp = priv->data;
|
||||
|
||||
mlxsw_sp_rif_destroy_by_dev(mlxsw_sp, dev);
|
||||
return 0;
|
||||
|
@ -147,10 +147,14 @@ static int mlxsw_sp_bridge_device_upper_rif_destroy(struct net_device *dev,
|
|||
static void mlxsw_sp_bridge_device_rifs_destroy(struct mlxsw_sp *mlxsw_sp,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct netdev_nested_priv priv = {
|
||||
.data = (void *)mlxsw_sp,
|
||||
};
|
||||
|
||||
mlxsw_sp_rif_destroy_by_dev(mlxsw_sp, dev);
|
||||
netdev_walk_all_upper_dev_rcu(dev,
|
||||
mlxsw_sp_bridge_device_upper_rif_destroy,
|
||||
mlxsw_sp);
|
||||
&priv);
|
||||
}
|
||||
|
||||
static int mlxsw_sp_bridge_device_vxlan_init(struct mlxsw_sp_bridge *bridge,
|
||||
|
|
|
@ -3099,9 +3099,10 @@ struct rocker_walk_data {
|
|||
struct rocker_port *port;
|
||||
};
|
||||
|
||||
static int rocker_lower_dev_walk(struct net_device *lower_dev, void *_data)
|
||||
static int rocker_lower_dev_walk(struct net_device *lower_dev,
|
||||
struct netdev_nested_priv *priv)
|
||||
{
|
||||
struct rocker_walk_data *data = _data;
|
||||
struct rocker_walk_data *data = (struct rocker_walk_data *)priv->data;
|
||||
int ret = 0;
|
||||
|
||||
if (rocker_port_dev_check_under(lower_dev, data->rocker)) {
|
||||
|
@ -3115,6 +3116,7 @@ static int rocker_lower_dev_walk(struct net_device *lower_dev, void *_data)
|
|||
struct rocker_port *rocker_port_dev_lower_find(struct net_device *dev,
|
||||
struct rocker *rocker)
|
||||
{
|
||||
struct netdev_nested_priv priv;
|
||||
struct rocker_walk_data data;
|
||||
|
||||
if (rocker_port_dev_check_under(dev, rocker))
|
||||
|
@ -3122,7 +3124,8 @@ struct rocker_port *rocker_port_dev_lower_find(struct net_device *dev,
|
|||
|
||||
data.rocker = rocker;
|
||||
data.port = NULL;
|
||||
netdev_walk_all_lower_dev(dev, rocker_lower_dev_walk, &data);
|
||||
priv.data = (void *)&data;
|
||||
netdev_walk_all_lower_dev(dev, rocker_lower_dev_walk, &priv);
|
||||
|
||||
return data.port;
|
||||
}
|
||||
|
|
|
@ -671,9 +671,10 @@ bool qtnf_netdev_is_qtn(const struct net_device *ndev)
|
|||
return ndev->netdev_ops == &qtnf_netdev_ops;
|
||||
}
|
||||
|
||||
static int qtnf_check_br_ports(struct net_device *dev, void *data)
|
||||
static int qtnf_check_br_ports(struct net_device *dev,
|
||||
struct netdev_nested_priv *priv)
|
||||
{
|
||||
struct net_device *ndev = data;
|
||||
struct net_device *ndev = (struct net_device *)priv->data;
|
||||
|
||||
if (dev != ndev && netdev_port_same_parent_id(dev, ndev))
|
||||
return -ENOTSUPP;
|
||||
|
@ -686,6 +687,9 @@ static int qtnf_core_netdevice_event(struct notifier_block *nb,
|
|||
{
|
||||
struct net_device *ndev = netdev_notifier_info_to_dev(ptr);
|
||||
const struct netdev_notifier_changeupper_info *info;
|
||||
struct netdev_nested_priv priv = {
|
||||
.data = (void *)ndev,
|
||||
};
|
||||
struct net_device *brdev;
|
||||
struct qtnf_vif *vif;
|
||||
struct qtnf_bus *bus;
|
||||
|
@ -725,7 +729,7 @@ static int qtnf_core_netdevice_event(struct notifier_block *nb,
|
|||
} else {
|
||||
ret = netdev_walk_all_lower_dev(brdev,
|
||||
qtnf_check_br_ports,
|
||||
ndev);
|
||||
&priv);
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
|
@ -1955,6 +1955,7 @@ struct net_device {
|
|||
unsigned short type;
|
||||
unsigned short hard_header_len;
|
||||
unsigned char min_header_len;
|
||||
unsigned char name_assign_type;
|
||||
|
||||
unsigned short needed_headroom;
|
||||
unsigned short needed_tailroom;
|
||||
|
@ -1965,21 +1966,28 @@ struct net_device {
|
|||
unsigned char addr_len;
|
||||
unsigned char upper_level;
|
||||
unsigned char lower_level;
|
||||
|
||||
unsigned short neigh_priv_len;
|
||||
unsigned short dev_id;
|
||||
unsigned short dev_port;
|
||||
spinlock_t addr_list_lock;
|
||||
unsigned char name_assign_type;
|
||||
bool uc_promisc;
|
||||
|
||||
struct netdev_hw_addr_list uc;
|
||||
struct netdev_hw_addr_list mc;
|
||||
struct netdev_hw_addr_list dev_addrs;
|
||||
|
||||
#ifdef CONFIG_SYSFS
|
||||
struct kset *queues_kset;
|
||||
#endif
|
||||
#ifdef CONFIG_LOCKDEP
|
||||
struct list_head unlink_list;
|
||||
#endif
|
||||
unsigned int promiscuity;
|
||||
unsigned int allmulti;
|
||||
bool uc_promisc;
|
||||
#ifdef CONFIG_LOCKDEP
|
||||
unsigned char nested_level;
|
||||
#endif
|
||||
|
||||
|
||||
/* Protocol-specific pointers */
|
||||
|
@ -4260,17 +4268,23 @@ static inline void netif_tx_disable(struct net_device *dev)
|
|||
|
||||
static inline void netif_addr_lock(struct net_device *dev)
|
||||
{
|
||||
spin_lock(&dev->addr_list_lock);
|
||||
}
|
||||
unsigned char nest_level = 0;
|
||||
|
||||
static inline void netif_addr_lock_nested(struct net_device *dev)
|
||||
{
|
||||
spin_lock_nested(&dev->addr_list_lock, dev->lower_level);
|
||||
#ifdef CONFIG_LOCKDEP
|
||||
nest_level = dev->nested_level;
|
||||
#endif
|
||||
spin_lock_nested(&dev->addr_list_lock, nest_level);
|
||||
}
|
||||
|
||||
static inline void netif_addr_lock_bh(struct net_device *dev)
|
||||
{
|
||||
spin_lock_bh(&dev->addr_list_lock);
|
||||
unsigned char nest_level = 0;
|
||||
|
||||
#ifdef CONFIG_LOCKDEP
|
||||
nest_level = dev->nested_level;
|
||||
#endif
|
||||
local_bh_disable();
|
||||
spin_lock_nested(&dev->addr_list_lock, nest_level);
|
||||
}
|
||||
|
||||
static inline void netif_addr_unlock(struct net_device *dev)
|
||||
|
@ -4455,12 +4469,38 @@ extern int dev_rx_weight;
|
|||
extern int dev_tx_weight;
|
||||
extern int gro_normal_batch;
|
||||
|
||||
enum {
|
||||
NESTED_SYNC_IMM_BIT,
|
||||
NESTED_SYNC_TODO_BIT,
|
||||
};
|
||||
|
||||
#define __NESTED_SYNC_BIT(bit) ((u32)1 << (bit))
|
||||
#define __NESTED_SYNC(name) __NESTED_SYNC_BIT(NESTED_SYNC_ ## name ## _BIT)
|
||||
|
||||
#define NESTED_SYNC_IMM __NESTED_SYNC(IMM)
|
||||
#define NESTED_SYNC_TODO __NESTED_SYNC(TODO)
|
||||
|
||||
struct netdev_nested_priv {
|
||||
unsigned char flags;
|
||||
void *data;
|
||||
};
|
||||
|
||||
bool netdev_has_upper_dev(struct net_device *dev, struct net_device *upper_dev);
|
||||
struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev,
|
||||
struct list_head **iter);
|
||||
struct net_device *netdev_all_upper_get_next_dev_rcu(struct net_device *dev,
|
||||
struct list_head **iter);
|
||||
|
||||
#ifdef CONFIG_LOCKDEP
|
||||
static LIST_HEAD(net_unlink_list);
|
||||
|
||||
static inline void net_unlink_todo(struct net_device *dev)
|
||||
{
|
||||
if (list_empty(&dev->unlink_list))
|
||||
list_add_tail(&dev->unlink_list, &net_unlink_list);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* iterate through upper list, must be called under RCU read lock */
|
||||
#define netdev_for_each_upper_dev_rcu(dev, updev, iter) \
|
||||
for (iter = &(dev)->adj_list.upper, \
|
||||
|
@ -4470,8 +4510,8 @@ struct net_device *netdev_all_upper_get_next_dev_rcu(struct net_device *dev,
|
|||
|
||||
int netdev_walk_all_upper_dev_rcu(struct net_device *dev,
|
||||
int (*fn)(struct net_device *upper_dev,
|
||||
void *data),
|
||||
void *data);
|
||||
struct netdev_nested_priv *priv),
|
||||
struct netdev_nested_priv *priv);
|
||||
|
||||
bool netdev_has_upper_dev_all_rcu(struct net_device *dev,
|
||||
struct net_device *upper_dev);
|
||||
|
@ -4508,12 +4548,12 @@ struct net_device *netdev_next_lower_dev_rcu(struct net_device *dev,
|
|||
struct list_head **iter);
|
||||
int netdev_walk_all_lower_dev(struct net_device *dev,
|
||||
int (*fn)(struct net_device *lower_dev,
|
||||
void *data),
|
||||
void *data);
|
||||
struct netdev_nested_priv *priv),
|
||||
struct netdev_nested_priv *priv);
|
||||
int netdev_walk_all_lower_dev_rcu(struct net_device *dev,
|
||||
int (*fn)(struct net_device *lower_dev,
|
||||
void *data),
|
||||
void *data);
|
||||
struct netdev_nested_priv *priv),
|
||||
struct netdev_nested_priv *priv);
|
||||
|
||||
void *netdev_adjacent_get_private(struct list_head *adj_list);
|
||||
void *netdev_lower_get_first_private_rcu(struct net_device *dev);
|
||||
|
|
|
@ -88,9 +88,10 @@ static void br_arp_send(struct net_bridge *br, struct net_bridge_port *p,
|
|||
}
|
||||
}
|
||||
|
||||
static int br_chk_addr_ip(struct net_device *dev, void *data)
|
||||
static int br_chk_addr_ip(struct net_device *dev,
|
||||
struct netdev_nested_priv *priv)
|
||||
{
|
||||
__be32 ip = *(__be32 *)data;
|
||||
__be32 ip = *(__be32 *)priv->data;
|
||||
struct in_device *in_dev;
|
||||
__be32 addr = 0;
|
||||
|
||||
|
@ -107,11 +108,15 @@ static int br_chk_addr_ip(struct net_device *dev, void *data)
|
|||
|
||||
static bool br_is_local_ip(struct net_device *dev, __be32 ip)
|
||||
{
|
||||
if (br_chk_addr_ip(dev, &ip))
|
||||
struct netdev_nested_priv priv = {
|
||||
.data = (void *)&ip,
|
||||
};
|
||||
|
||||
if (br_chk_addr_ip(dev, &priv))
|
||||
return true;
|
||||
|
||||
/* check if ip is configured on upper dev */
|
||||
if (netdev_walk_all_upper_dev_rcu(dev, br_chk_addr_ip, &ip))
|
||||
if (netdev_walk_all_upper_dev_rcu(dev, br_chk_addr_ip, &priv))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
@ -361,9 +366,10 @@ static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p,
|
|||
}
|
||||
}
|
||||
|
||||
static int br_chk_addr_ip6(struct net_device *dev, void *data)
|
||||
static int br_chk_addr_ip6(struct net_device *dev,
|
||||
struct netdev_nested_priv *priv)
|
||||
{
|
||||
struct in6_addr *addr = (struct in6_addr *)data;
|
||||
struct in6_addr *addr = (struct in6_addr *)priv->data;
|
||||
|
||||
if (ipv6_chk_addr(dev_net(dev), addr, dev, 0))
|
||||
return 1;
|
||||
|
@ -374,11 +380,15 @@ static int br_chk_addr_ip6(struct net_device *dev, void *data)
|
|||
static bool br_is_local_ip6(struct net_device *dev, struct in6_addr *addr)
|
||||
|
||||
{
|
||||
if (br_chk_addr_ip6(dev, addr))
|
||||
struct netdev_nested_priv priv = {
|
||||
.data = (void *)addr,
|
||||
};
|
||||
|
||||
if (br_chk_addr_ip6(dev, &priv))
|
||||
return true;
|
||||
|
||||
/* check if ip is configured on upper dev */
|
||||
if (netdev_walk_all_upper_dev_rcu(dev, br_chk_addr_ip6, addr))
|
||||
if (netdev_walk_all_upper_dev_rcu(dev, br_chk_addr_ip6, &priv))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
|
|
@ -1360,7 +1360,7 @@ static int br_vlan_is_bind_vlan_dev(const struct net_device *dev)
|
|||
}
|
||||
|
||||
static int br_vlan_is_bind_vlan_dev_fn(struct net_device *dev,
|
||||
__always_unused void *data)
|
||||
__always_unused struct netdev_nested_priv *priv)
|
||||
{
|
||||
return br_vlan_is_bind_vlan_dev(dev);
|
||||
}
|
||||
|
@ -1383,9 +1383,9 @@ struct br_vlan_bind_walk_data {
|
|||
};
|
||||
|
||||
static int br_vlan_match_bind_vlan_dev_fn(struct net_device *dev,
|
||||
void *data_in)
|
||||
struct netdev_nested_priv *priv)
|
||||
{
|
||||
struct br_vlan_bind_walk_data *data = data_in;
|
||||
struct br_vlan_bind_walk_data *data = priv->data;
|
||||
int found = 0;
|
||||
|
||||
if (br_vlan_is_bind_vlan_dev(dev) &&
|
||||
|
@ -1403,10 +1403,13 @@ br_vlan_get_upper_bind_vlan_dev(struct net_device *dev, u16 vid)
|
|||
struct br_vlan_bind_walk_data data = {
|
||||
.vid = vid,
|
||||
};
|
||||
struct netdev_nested_priv priv = {
|
||||
.data = (void *)&data,
|
||||
};
|
||||
|
||||
rcu_read_lock();
|
||||
netdev_walk_all_upper_dev_rcu(dev, br_vlan_match_bind_vlan_dev_fn,
|
||||
&data);
|
||||
&priv);
|
||||
rcu_read_unlock();
|
||||
|
||||
return data.result;
|
||||
|
@ -1487,9 +1490,9 @@ struct br_vlan_link_state_walk_data {
|
|||
};
|
||||
|
||||
static int br_vlan_link_state_change_fn(struct net_device *vlan_dev,
|
||||
void *data_in)
|
||||
struct netdev_nested_priv *priv)
|
||||
{
|
||||
struct br_vlan_link_state_walk_data *data = data_in;
|
||||
struct br_vlan_link_state_walk_data *data = priv->data;
|
||||
|
||||
if (br_vlan_is_bind_vlan_dev(vlan_dev))
|
||||
br_vlan_set_vlan_dev_state(data->br, vlan_dev);
|
||||
|
@ -1503,10 +1506,13 @@ static void br_vlan_link_state_change(struct net_device *dev,
|
|||
struct br_vlan_link_state_walk_data data = {
|
||||
.br = br
|
||||
};
|
||||
struct netdev_nested_priv priv = {
|
||||
.data = (void *)&data,
|
||||
};
|
||||
|
||||
rcu_read_lock();
|
||||
netdev_walk_all_upper_dev_rcu(dev, br_vlan_link_state_change_fn,
|
||||
&data);
|
||||
&priv);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
|
|
164
net/core/dev.c
164
net/core/dev.c
|
@ -6812,9 +6812,10 @@ static struct netdev_adjacent *__netdev_find_adj(struct net_device *adj_dev,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static int ____netdev_has_upper_dev(struct net_device *upper_dev, void *data)
|
||||
static int ____netdev_has_upper_dev(struct net_device *upper_dev,
|
||||
struct netdev_nested_priv *priv)
|
||||
{
|
||||
struct net_device *dev = data;
|
||||
struct net_device *dev = (struct net_device *)priv->data;
|
||||
|
||||
return upper_dev == dev;
|
||||
}
|
||||
|
@ -6831,10 +6832,14 @@ static int ____netdev_has_upper_dev(struct net_device *upper_dev, void *data)
|
|||
bool netdev_has_upper_dev(struct net_device *dev,
|
||||
struct net_device *upper_dev)
|
||||
{
|
||||
struct netdev_nested_priv priv = {
|
||||
.data = (void *)upper_dev,
|
||||
};
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
return netdev_walk_all_upper_dev_rcu(dev, ____netdev_has_upper_dev,
|
||||
upper_dev);
|
||||
&priv);
|
||||
}
|
||||
EXPORT_SYMBOL(netdev_has_upper_dev);
|
||||
|
||||
|
@ -6851,8 +6856,12 @@ EXPORT_SYMBOL(netdev_has_upper_dev);
|
|||
bool netdev_has_upper_dev_all_rcu(struct net_device *dev,
|
||||
struct net_device *upper_dev)
|
||||
{
|
||||
struct netdev_nested_priv priv = {
|
||||
.data = (void *)upper_dev,
|
||||
};
|
||||
|
||||
return !!netdev_walk_all_upper_dev_rcu(dev, ____netdev_has_upper_dev,
|
||||
upper_dev);
|
||||
&priv);
|
||||
}
|
||||
EXPORT_SYMBOL(netdev_has_upper_dev_all_rcu);
|
||||
|
||||
|
@ -6997,8 +7006,8 @@ static struct net_device *netdev_next_upper_dev_rcu(struct net_device *dev,
|
|||
|
||||
static int __netdev_walk_all_upper_dev(struct net_device *dev,
|
||||
int (*fn)(struct net_device *dev,
|
||||
void *data),
|
||||
void *data)
|
||||
struct netdev_nested_priv *priv),
|
||||
struct netdev_nested_priv *priv)
|
||||
{
|
||||
struct net_device *udev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];
|
||||
struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1];
|
||||
|
@ -7010,7 +7019,7 @@ static int __netdev_walk_all_upper_dev(struct net_device *dev,
|
|||
|
||||
while (1) {
|
||||
if (now != dev) {
|
||||
ret = fn(now, data);
|
||||
ret = fn(now, priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
@ -7046,8 +7055,8 @@ static int __netdev_walk_all_upper_dev(struct net_device *dev,
|
|||
|
||||
int netdev_walk_all_upper_dev_rcu(struct net_device *dev,
|
||||
int (*fn)(struct net_device *dev,
|
||||
void *data),
|
||||
void *data)
|
||||
struct netdev_nested_priv *priv),
|
||||
struct netdev_nested_priv *priv)
|
||||
{
|
||||
struct net_device *udev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];
|
||||
struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1];
|
||||
|
@ -7058,7 +7067,7 @@ int netdev_walk_all_upper_dev_rcu(struct net_device *dev,
|
|||
|
||||
while (1) {
|
||||
if (now != dev) {
|
||||
ret = fn(now, data);
|
||||
ret = fn(now, priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
@ -7094,10 +7103,15 @@ EXPORT_SYMBOL_GPL(netdev_walk_all_upper_dev_rcu);
|
|||
static bool __netdev_has_upper_dev(struct net_device *dev,
|
||||
struct net_device *upper_dev)
|
||||
{
|
||||
struct netdev_nested_priv priv = {
|
||||
.flags = 0,
|
||||
.data = (void *)upper_dev,
|
||||
};
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
return __netdev_walk_all_upper_dev(dev, ____netdev_has_upper_dev,
|
||||
upper_dev);
|
||||
&priv);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -7215,8 +7229,8 @@ static struct net_device *__netdev_next_lower_dev(struct net_device *dev,
|
|||
|
||||
int netdev_walk_all_lower_dev(struct net_device *dev,
|
||||
int (*fn)(struct net_device *dev,
|
||||
void *data),
|
||||
void *data)
|
||||
struct netdev_nested_priv *priv),
|
||||
struct netdev_nested_priv *priv)
|
||||
{
|
||||
struct net_device *ldev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];
|
||||
struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1];
|
||||
|
@ -7227,7 +7241,7 @@ int netdev_walk_all_lower_dev(struct net_device *dev,
|
|||
|
||||
while (1) {
|
||||
if (now != dev) {
|
||||
ret = fn(now, data);
|
||||
ret = fn(now, priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
@ -7262,8 +7276,8 @@ EXPORT_SYMBOL_GPL(netdev_walk_all_lower_dev);
|
|||
|
||||
static int __netdev_walk_all_lower_dev(struct net_device *dev,
|
||||
int (*fn)(struct net_device *dev,
|
||||
void *data),
|
||||
void *data)
|
||||
struct netdev_nested_priv *priv),
|
||||
struct netdev_nested_priv *priv)
|
||||
{
|
||||
struct net_device *ldev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];
|
||||
struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1];
|
||||
|
@ -7275,7 +7289,7 @@ static int __netdev_walk_all_lower_dev(struct net_device *dev,
|
|||
|
||||
while (1) {
|
||||
if (now != dev) {
|
||||
ret = fn(now, data);
|
||||
ret = fn(now, priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
@ -7364,22 +7378,34 @@ static u8 __netdev_lower_depth(struct net_device *dev)
|
|||
return max_depth;
|
||||
}
|
||||
|
||||
static int __netdev_update_upper_level(struct net_device *dev, void *data)
|
||||
static int __netdev_update_upper_level(struct net_device *dev,
|
||||
struct netdev_nested_priv *__unused)
|
||||
{
|
||||
dev->upper_level = __netdev_upper_depth(dev) + 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __netdev_update_lower_level(struct net_device *dev, void *data)
|
||||
static int __netdev_update_lower_level(struct net_device *dev,
|
||||
struct netdev_nested_priv *priv)
|
||||
{
|
||||
dev->lower_level = __netdev_lower_depth(dev) + 1;
|
||||
|
||||
#ifdef CONFIG_LOCKDEP
|
||||
if (!priv)
|
||||
return 0;
|
||||
|
||||
if (priv->flags & NESTED_SYNC_IMM)
|
||||
dev->nested_level = dev->lower_level - 1;
|
||||
if (priv->flags & NESTED_SYNC_TODO)
|
||||
net_unlink_todo(dev);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int netdev_walk_all_lower_dev_rcu(struct net_device *dev,
|
||||
int (*fn)(struct net_device *dev,
|
||||
void *data),
|
||||
void *data)
|
||||
struct netdev_nested_priv *priv),
|
||||
struct netdev_nested_priv *priv)
|
||||
{
|
||||
struct net_device *ldev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];
|
||||
struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1];
|
||||
|
@ -7390,7 +7416,7 @@ int netdev_walk_all_lower_dev_rcu(struct net_device *dev,
|
|||
|
||||
while (1) {
|
||||
if (now != dev) {
|
||||
ret = fn(now, data);
|
||||
ret = fn(now, priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
@ -7650,6 +7676,7 @@ static void __netdev_adjacent_dev_unlink_neighbour(struct net_device *dev,
|
|||
static int __netdev_upper_dev_link(struct net_device *dev,
|
||||
struct net_device *upper_dev, bool master,
|
||||
void *upper_priv, void *upper_info,
|
||||
struct netdev_nested_priv *priv,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct netdev_notifier_changeupper_info changeupper_info = {
|
||||
|
@ -7706,9 +7733,9 @@ static int __netdev_upper_dev_link(struct net_device *dev,
|
|||
__netdev_update_upper_level(dev, NULL);
|
||||
__netdev_walk_all_lower_dev(dev, __netdev_update_upper_level, NULL);
|
||||
|
||||
__netdev_update_lower_level(upper_dev, NULL);
|
||||
__netdev_update_lower_level(upper_dev, priv);
|
||||
__netdev_walk_all_upper_dev(upper_dev, __netdev_update_lower_level,
|
||||
NULL);
|
||||
priv);
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -7733,8 +7760,13 @@ int netdev_upper_dev_link(struct net_device *dev,
|
|||
struct net_device *upper_dev,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct netdev_nested_priv priv = {
|
||||
.flags = NESTED_SYNC_IMM | NESTED_SYNC_TODO,
|
||||
.data = NULL,
|
||||
};
|
||||
|
||||
return __netdev_upper_dev_link(dev, upper_dev, false,
|
||||
NULL, NULL, extack);
|
||||
NULL, NULL, &priv, extack);
|
||||
}
|
||||
EXPORT_SYMBOL(netdev_upper_dev_link);
|
||||
|
||||
|
@ -7757,21 +7789,19 @@ int netdev_master_upper_dev_link(struct net_device *dev,
|
|||
void *upper_priv, void *upper_info,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct netdev_nested_priv priv = {
|
||||
.flags = NESTED_SYNC_IMM | NESTED_SYNC_TODO,
|
||||
.data = NULL,
|
||||
};
|
||||
|
||||
return __netdev_upper_dev_link(dev, upper_dev, true,
|
||||
upper_priv, upper_info, extack);
|
||||
upper_priv, upper_info, &priv, extack);
|
||||
}
|
||||
EXPORT_SYMBOL(netdev_master_upper_dev_link);
|
||||
|
||||
/**
|
||||
* netdev_upper_dev_unlink - Removes a link to upper device
|
||||
* @dev: device
|
||||
* @upper_dev: new upper device
|
||||
*
|
||||
* Removes a link to device which is upper to this one. The caller must hold
|
||||
* the RTNL lock.
|
||||
*/
|
||||
void netdev_upper_dev_unlink(struct net_device *dev,
|
||||
struct net_device *upper_dev)
|
||||
static void __netdev_upper_dev_unlink(struct net_device *dev,
|
||||
struct net_device *upper_dev,
|
||||
struct netdev_nested_priv *priv)
|
||||
{
|
||||
struct netdev_notifier_changeupper_info changeupper_info = {
|
||||
.info = {
|
||||
|
@ -7796,9 +7826,28 @@ void netdev_upper_dev_unlink(struct net_device *dev,
|
|||
__netdev_update_upper_level(dev, NULL);
|
||||
__netdev_walk_all_lower_dev(dev, __netdev_update_upper_level, NULL);
|
||||
|
||||
__netdev_update_lower_level(upper_dev, NULL);
|
||||
__netdev_update_lower_level(upper_dev, priv);
|
||||
__netdev_walk_all_upper_dev(upper_dev, __netdev_update_lower_level,
|
||||
NULL);
|
||||
priv);
|
||||
}
|
||||
|
||||
/**
|
||||
* netdev_upper_dev_unlink - Removes a link to upper device
|
||||
* @dev: device
|
||||
* @upper_dev: new upper device
|
||||
*
|
||||
* Removes a link to device which is upper to this one. The caller must hold
|
||||
* the RTNL lock.
|
||||
*/
|
||||
void netdev_upper_dev_unlink(struct net_device *dev,
|
||||
struct net_device *upper_dev)
|
||||
{
|
||||
struct netdev_nested_priv priv = {
|
||||
.flags = NESTED_SYNC_TODO,
|
||||
.data = NULL,
|
||||
};
|
||||
|
||||
__netdev_upper_dev_unlink(dev, upper_dev, &priv);
|
||||
}
|
||||
EXPORT_SYMBOL(netdev_upper_dev_unlink);
|
||||
|
||||
|
@ -7834,6 +7883,10 @@ int netdev_adjacent_change_prepare(struct net_device *old_dev,
|
|||
struct net_device *dev,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct netdev_nested_priv priv = {
|
||||
.flags = 0,
|
||||
.data = NULL,
|
||||
};
|
||||
int err;
|
||||
|
||||
if (!new_dev)
|
||||
|
@ -7841,8 +7894,8 @@ int netdev_adjacent_change_prepare(struct net_device *old_dev,
|
|||
|
||||
if (old_dev && new_dev != old_dev)
|
||||
netdev_adjacent_dev_disable(dev, old_dev);
|
||||
|
||||
err = netdev_upper_dev_link(new_dev, dev, extack);
|
||||
err = __netdev_upper_dev_link(new_dev, dev, false, NULL, NULL, &priv,
|
||||
extack);
|
||||
if (err) {
|
||||
if (old_dev && new_dev != old_dev)
|
||||
netdev_adjacent_dev_enable(dev, old_dev);
|
||||
|
@ -7857,6 +7910,11 @@ void netdev_adjacent_change_commit(struct net_device *old_dev,
|
|||
struct net_device *new_dev,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct netdev_nested_priv priv = {
|
||||
.flags = NESTED_SYNC_IMM | NESTED_SYNC_TODO,
|
||||
.data = NULL,
|
||||
};
|
||||
|
||||
if (!new_dev || !old_dev)
|
||||
return;
|
||||
|
||||
|
@ -7864,7 +7922,7 @@ void netdev_adjacent_change_commit(struct net_device *old_dev,
|
|||
return;
|
||||
|
||||
netdev_adjacent_dev_enable(dev, old_dev);
|
||||
netdev_upper_dev_unlink(old_dev, dev);
|
||||
__netdev_upper_dev_unlink(old_dev, dev, &priv);
|
||||
}
|
||||
EXPORT_SYMBOL(netdev_adjacent_change_commit);
|
||||
|
||||
|
@ -7872,13 +7930,18 @@ void netdev_adjacent_change_abort(struct net_device *old_dev,
|
|||
struct net_device *new_dev,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct netdev_nested_priv priv = {
|
||||
.flags = 0,
|
||||
.data = NULL,
|
||||
};
|
||||
|
||||
if (!new_dev)
|
||||
return;
|
||||
|
||||
if (old_dev && new_dev != old_dev)
|
||||
netdev_adjacent_dev_enable(dev, old_dev);
|
||||
|
||||
netdev_upper_dev_unlink(new_dev, dev);
|
||||
__netdev_upper_dev_unlink(new_dev, dev, &priv);
|
||||
}
|
||||
EXPORT_SYMBOL(netdev_adjacent_change_abort);
|
||||
|
||||
|
@ -10062,6 +10125,19 @@ static void netdev_wait_allrefs(struct net_device *dev)
|
|||
void netdev_run_todo(void)
|
||||
{
|
||||
struct list_head list;
|
||||
#ifdef CONFIG_LOCKDEP
|
||||
struct list_head unlink_list;
|
||||
|
||||
list_replace_init(&net_unlink_list, &unlink_list);
|
||||
|
||||
while (!list_empty(&unlink_list)) {
|
||||
struct net_device *dev = list_first_entry(&unlink_list,
|
||||
struct net_device,
|
||||
unlink_list);
|
||||
list_del(&dev->unlink_list);
|
||||
dev->nested_level = dev->lower_level - 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Snapshot list, allow later requests */
|
||||
list_replace_init(&net_todo_list, &list);
|
||||
|
@ -10274,6 +10350,10 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
|
|||
dev->gso_max_segs = GSO_MAX_SEGS;
|
||||
dev->upper_level = 1;
|
||||
dev->lower_level = 1;
|
||||
#ifdef CONFIG_LOCKDEP
|
||||
dev->nested_level = 0;
|
||||
INIT_LIST_HEAD(&dev->unlink_list);
|
||||
#endif
|
||||
|
||||
INIT_LIST_HEAD(&dev->napi_list);
|
||||
INIT_LIST_HEAD(&dev->unreg_list);
|
||||
|
|
|
@ -637,7 +637,7 @@ int dev_uc_sync(struct net_device *to, struct net_device *from)
|
|||
if (to->addr_len != from->addr_len)
|
||||
return -EINVAL;
|
||||
|
||||
netif_addr_lock_nested(to);
|
||||
netif_addr_lock(to);
|
||||
err = __hw_addr_sync(&to->uc, &from->uc, to->addr_len);
|
||||
if (!err)
|
||||
__dev_set_rx_mode(to);
|
||||
|
@ -667,7 +667,7 @@ int dev_uc_sync_multiple(struct net_device *to, struct net_device *from)
|
|||
if (to->addr_len != from->addr_len)
|
||||
return -EINVAL;
|
||||
|
||||
netif_addr_lock_nested(to);
|
||||
netif_addr_lock(to);
|
||||
err = __hw_addr_sync_multiple(&to->uc, &from->uc, to->addr_len);
|
||||
if (!err)
|
||||
__dev_set_rx_mode(to);
|
||||
|
@ -700,7 +700,7 @@ void dev_uc_unsync(struct net_device *to, struct net_device *from)
|
|||
* larger.
|
||||
*/
|
||||
netif_addr_lock_bh(from);
|
||||
netif_addr_lock_nested(to);
|
||||
netif_addr_lock(to);
|
||||
__hw_addr_unsync(&to->uc, &from->uc, to->addr_len);
|
||||
__dev_set_rx_mode(to);
|
||||
netif_addr_unlock(to);
|
||||
|
@ -867,7 +867,7 @@ int dev_mc_sync(struct net_device *to, struct net_device *from)
|
|||
if (to->addr_len != from->addr_len)
|
||||
return -EINVAL;
|
||||
|
||||
netif_addr_lock_nested(to);
|
||||
netif_addr_lock(to);
|
||||
err = __hw_addr_sync(&to->mc, &from->mc, to->addr_len);
|
||||
if (!err)
|
||||
__dev_set_rx_mode(to);
|
||||
|
@ -897,7 +897,7 @@ int dev_mc_sync_multiple(struct net_device *to, struct net_device *from)
|
|||
if (to->addr_len != from->addr_len)
|
||||
return -EINVAL;
|
||||
|
||||
netif_addr_lock_nested(to);
|
||||
netif_addr_lock(to);
|
||||
err = __hw_addr_sync_multiple(&to->mc, &from->mc, to->addr_len);
|
||||
if (!err)
|
||||
__dev_set_rx_mode(to);
|
||||
|
@ -922,7 +922,7 @@ void dev_mc_unsync(struct net_device *to, struct net_device *from)
|
|||
|
||||
/* See the above comments inside dev_uc_unsync(). */
|
||||
netif_addr_lock_bh(from);
|
||||
netif_addr_lock_nested(to);
|
||||
netif_addr_lock(to);
|
||||
__hw_addr_unsync(&to->mc, &from->mc, to->addr_len);
|
||||
__dev_set_rx_mode(to);
|
||||
netif_addr_unlock(to);
|
||||
|
|
Loading…
Reference in New Issue