Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 21 additions & 9 deletions drivers/net/macvlan.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ struct macvlan_port {

struct macvlan_source_entry {
struct hlist_node hlist;
struct macvlan_dev *vlan;
struct macvlan_dev __rcu *vlan;
unsigned char addr[6+2] __aligned(sizeof(u16));
struct rcu_head rcu;
};
Expand Down Expand Up @@ -145,7 +145,7 @@ static struct macvlan_source_entry *macvlan_hash_lookup_source(

hlist_for_each_entry_rcu(entry, h, hlist, lockdep_rtnl_is_held()) {
if (ether_addr_equal_64bits(entry->addr, addr) &&
entry->vlan == vlan)
rcu_access_pointer(entry->vlan) == vlan)
return entry;
}
return NULL;
Expand All @@ -167,7 +167,7 @@ static int macvlan_hash_add_source(struct macvlan_dev *vlan,
return -ENOMEM;

ether_addr_copy(entry->addr, addr);
entry->vlan = vlan;
RCU_INIT_POINTER(entry->vlan, vlan);
h = &port->vlan_source_hash[macvlan_eth_hash(addr)];
hlist_add_head_rcu(&entry->hlist, h);
vlan->macaddr_count++;
Expand All @@ -186,6 +186,7 @@ static void macvlan_hash_add(struct macvlan_dev *vlan)

static void macvlan_hash_del_source(struct macvlan_source_entry *entry)
{
RCU_INIT_POINTER(entry->vlan, NULL);
hlist_del_rcu(&entry->hlist);
kfree_rcu(entry, rcu);
}
Expand Down Expand Up @@ -389,7 +390,7 @@ static void macvlan_flush_sources(struct macvlan_port *port,
int i;

hash_for_each_safe(port->vlan_source_hash, i, next, entry, hlist)
if (entry->vlan == vlan)
if (rcu_access_pointer(entry->vlan) == vlan)
macvlan_hash_del_source(entry);

vlan->macaddr_count = 0;
Expand Down Expand Up @@ -432,9 +433,14 @@ static bool macvlan_forward_source(struct sk_buff *skb,

hlist_for_each_entry_rcu(entry, h, hlist) {
if (ether_addr_equal_64bits(entry->addr, addr)) {
if (entry->vlan->flags & MACVLAN_FLAG_NODST)
struct macvlan_dev *vlan = rcu_dereference(entry->vlan);

if (!vlan)
continue;

if (vlan->flags & MACVLAN_FLAG_NODST)
consume = true;
macvlan_forward_source_one(skb, entry->vlan);
macvlan_forward_source_one(skb, vlan);
}
}

Expand Down Expand Up @@ -1572,10 +1578,16 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
/* the macvlan port may be freed by macvlan_uninit when fail to register.
* so we destroy the macvlan port only when it's valid.
*/
if (create && macvlan_port_get_rtnl(lowerdev)) {
if (macvlan_port_get_rtnl(lowerdev)) {
macvlan_flush_sources(port, vlan);
macvlan_port_destroy(port->dev);
if (create)
macvlan_port_destroy(port->dev);
}
/* @dev might have been made visible before an error was detected.
* Make sure to observe an RCU grace period before our caller
* (rtnl_newlink()) frees it.
*/
synchronize_net();
return err;
}
EXPORT_SYMBOL_GPL(macvlan_common_newlink);
Expand Down Expand Up @@ -1691,7 +1703,7 @@ static int macvlan_fill_info_macaddr(struct sk_buff *skb,
struct macvlan_source_entry *entry;

hlist_for_each_entry_rcu(entry, h, hlist, lockdep_rtnl_is_held()) {
if (entry->vlan != vlan)
if (rcu_access_pointer(entry->vlan) != vlan)
continue;
if (nla_put(skb, IFLA_MACVLAN_MACADDR, ETH_ALEN, entry->addr))
return 1;
Expand Down
12 changes: 10 additions & 2 deletions net/atm/lec.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ static unsigned char bus_mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };

/* Device structures */
static struct net_device *dev_lec[MAX_LEC_ITF];
static DEFINE_MUTEX(lec_mutex);

#if IS_ENABLED(CONFIG_BRIDGE)
static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
Expand Down Expand Up @@ -687,6 +688,7 @@ static int lec_vcc_attach(struct atm_vcc *vcc, void __user *arg)
int bytes_left;
struct atmlec_ioc ioc_data;

lockdep_assert_held(&lec_mutex);
/* Lecd must be up in this case */
bytes_left = copy_from_user(&ioc_data, arg, sizeof(struct atmlec_ioc));
if (bytes_left != 0)
Expand All @@ -712,6 +714,7 @@ static int lec_vcc_attach(struct atm_vcc *vcc, void __user *arg)

static int lec_mcast_attach(struct atm_vcc *vcc, int arg)
{
lockdep_assert_held(&lec_mutex);
if (arg < 0 || arg >= MAX_LEC_ITF)
return -EINVAL;
arg = array_index_nospec(arg, MAX_LEC_ITF);
Expand All @@ -727,6 +730,7 @@ static int lecd_attach(struct atm_vcc *vcc, int arg)
int i;
struct lec_priv *priv;

lockdep_assert_held(&lec_mutex);
if (arg < 0)
arg = 0;
if (arg >= MAX_LEC_ITF)
Expand All @@ -744,6 +748,7 @@ static int lecd_attach(struct atm_vcc *vcc, int arg)
snprintf(dev_lec[i]->name, IFNAMSIZ, "lec%d", i);
if (register_netdev(dev_lec[i])) {
free_netdev(dev_lec[i]);
dev_lec[i] = NULL;
return -EINVAL;
}

Expand Down Expand Up @@ -906,7 +911,6 @@ static void *lec_itf_walk(struct lec_state *state, loff_t *l)
v = (dev && netdev_priv(dev)) ?
lec_priv_walk(state, l, netdev_priv(dev)) : NULL;
if (!v && dev) {
dev_put(dev);
/* Partial state reset for the next time we get called */
dev = NULL;
}
Expand All @@ -930,6 +934,7 @@ static void *lec_seq_start(struct seq_file *seq, loff_t *pos)
{
struct lec_state *state = seq->private;

mutex_lock(&lec_mutex);
state->itf = 0;
state->dev = NULL;
state->locked = NULL;
Expand All @@ -947,8 +952,9 @@ static void lec_seq_stop(struct seq_file *seq, void *v)
if (state->dev) {
spin_unlock_irqrestore(&state->locked->lec_arp_lock,
state->flags);
dev_put(state->dev);
state->dev = NULL;
}
mutex_unlock(&lec_mutex);
}

static void *lec_seq_next(struct seq_file *seq, void *v, loff_t *pos)
Expand Down Expand Up @@ -1005,6 +1011,7 @@ static int lane_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
return -ENOIOCTLCMD;
}

mutex_lock(&lec_mutex);
switch (cmd) {
case ATMLEC_CTRL:
err = lecd_attach(vcc, (int)arg);
Expand All @@ -1019,6 +1026,7 @@ static int lane_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
break;
}

mutex_unlock(&lec_mutex);
return err;
}

Expand Down
Loading