Skip to content

Commit

Permalink
netdev: Add netdev->addr_list_lock protection.
Browse files Browse the repository at this point in the history
Add netif_addr_{lock,unlock}{,_bh}() helpers.

Use them to protect operations that operate on or read
the network device unicast and multicast address lists.

Also use them in cases where the code simply wants to
block calls into the driver's ->set_rx_mode() and
->set_multicast_list() methods.

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jul 15, 2008
1 parent f1f28aa commit e308a5d
Show file tree
Hide file tree
Showing 14 changed files with 94 additions and 0 deletions.
2 changes: 2 additions & 0 deletions drivers/infiniband/ulp/ipoib/ipoib_multicast.c
Original file line number Diff line number Diff line change
Expand Up @@ -775,6 +775,7 @@ void ipoib_mcast_restart_task(struct work_struct *work)

local_irq_save(flags);
netif_tx_lock(dev);
netif_addr_lock(dev);
spin_lock(&priv->lock);

/*
Expand Down Expand Up @@ -851,6 +852,7 @@ void ipoib_mcast_restart_task(struct work_struct *work)
}

spin_unlock(&priv->lock);
netif_addr_unlock(dev);
netif_tx_unlock(dev);
local_irq_restore(flags);

Expand Down
2 changes: 2 additions & 0 deletions drivers/media/dvb/dvb-core/dvb_net.c
Original file line number Diff line number Diff line change
Expand Up @@ -1134,6 +1134,7 @@ static void wq_set_multicast_list (struct work_struct *work)
dvb_net_feed_stop(dev);
priv->rx_mode = RX_MODE_UNI;
netif_tx_lock_bh(dev);
netif_addr_lock(dev);

if (dev->flags & IFF_PROMISC) {
dprintk("%s: promiscuous mode\n", dev->name);
Expand All @@ -1158,6 +1159,7 @@ static void wq_set_multicast_list (struct work_struct *work)
}
}

netif_addr_unlock(dev);
netif_tx_unlock_bh(dev);
dvb_net_feed_start(dev);
}
Expand Down
8 changes: 8 additions & 0 deletions drivers/net/bonding/bond_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1568,10 +1568,12 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
}

netif_tx_lock_bh(bond_dev);
netif_addr_lock(bond_dev);
/* upload master's mc_list to new slave */
for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next) {
dev_mc_add (slave_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
}
netif_addr_unlock(bond_dev);
netif_tx_unlock_bh(bond_dev);
}

Expand Down Expand Up @@ -1937,7 +1939,9 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)

/* flush master's mc_list from slave */
netif_tx_lock_bh(bond_dev);
netif_addr_lock(bond_dev);
bond_mc_list_flush(bond_dev, slave_dev);
netif_addr_unlock(bond_dev);
netif_tx_unlock_bh(bond_dev);
}

Expand Down Expand Up @@ -2060,7 +2064,9 @@ static int bond_release_all(struct net_device *bond_dev)

/* flush master's mc_list from slave */
netif_tx_lock_bh(bond_dev);
netif_addr_lock(bond_dev);
bond_mc_list_flush(bond_dev, slave_dev);
netif_addr_unlock(bond_dev);
netif_tx_unlock_bh(bond_dev);
}

Expand Down Expand Up @@ -4674,7 +4680,9 @@ static void bond_free_all(void)

bond_work_cancel_all(bond);
netif_tx_lock_bh(bond_dev);
netif_addr_lock(bond_dev);
bond_mc_list_destroy(bond);
netif_addr_unlock(bond_dev);
netif_tx_unlock_bh(bond_dev);
/* Release the bonded slaves */
bond_release_all(bond_dev);
Expand Down
16 changes: 16 additions & 0 deletions drivers/net/forcedeth.c
Original file line number Diff line number Diff line change
Expand Up @@ -2831,6 +2831,7 @@ static int nv_change_mtu(struct net_device *dev, int new_mtu)
*/
nv_disable_irq(dev);
netif_tx_lock_bh(dev);
netif_addr_lock(dev);
spin_lock(&np->lock);
/* stop engines */
nv_stop_rxtx(dev);
Expand All @@ -2855,6 +2856,7 @@ static int nv_change_mtu(struct net_device *dev, int new_mtu)
/* restart rx engine */
nv_start_rxtx(dev);
spin_unlock(&np->lock);
netif_addr_unlock(dev);
netif_tx_unlock_bh(dev);
nv_enable_irq(dev);
}
Expand Down Expand Up @@ -2891,6 +2893,7 @@ static int nv_set_mac_address(struct net_device *dev, void *addr)

if (netif_running(dev)) {
netif_tx_lock_bh(dev);
netif_addr_lock(dev);
spin_lock_irq(&np->lock);

/* stop rx engine */
Expand All @@ -2902,6 +2905,7 @@ static int nv_set_mac_address(struct net_device *dev, void *addr)
/* restart rx engine */
nv_start_rx(dev);
spin_unlock_irq(&np->lock);
netif_addr_unlock(dev);
netif_tx_unlock_bh(dev);
} else {
nv_copy_mac_to_hw(dev);
Expand Down Expand Up @@ -3971,6 +3975,7 @@ static void nv_do_nic_poll(unsigned long data)
printk(KERN_INFO "forcedeth: MAC in recoverable error state\n");
if (netif_running(dev)) {
netif_tx_lock_bh(dev);
netif_addr_lock(dev);
spin_lock(&np->lock);
/* stop engines */
nv_stop_rxtx(dev);
Expand All @@ -3995,6 +4000,7 @@ static void nv_do_nic_poll(unsigned long data)
/* restart rx engine */
nv_start_rxtx(dev);
spin_unlock(&np->lock);
netif_addr_unlock(dev);
netif_tx_unlock_bh(dev);
}
}
Expand Down Expand Up @@ -4202,6 +4208,7 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)

nv_disable_irq(dev);
netif_tx_lock_bh(dev);
netif_addr_lock(dev);
/* with plain spinlock lockdep complains */
spin_lock_irqsave(&np->lock, flags);
/* stop engines */
Expand All @@ -4215,6 +4222,7 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
*/
nv_stop_rxtx(dev);
spin_unlock_irqrestore(&np->lock, flags);
netif_addr_unlock(dev);
netif_tx_unlock_bh(dev);
}

Expand Down Expand Up @@ -4360,10 +4368,12 @@ static int nv_nway_reset(struct net_device *dev)
if (netif_running(dev)) {
nv_disable_irq(dev);
netif_tx_lock_bh(dev);
netif_addr_lock(dev);
spin_lock(&np->lock);
/* stop engines */
nv_stop_rxtx(dev);
spin_unlock(&np->lock);
netif_addr_unlock(dev);
netif_tx_unlock_bh(dev);
printk(KERN_INFO "%s: link down.\n", dev->name);
}
Expand Down Expand Up @@ -4471,6 +4481,7 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri
if (netif_running(dev)) {
nv_disable_irq(dev);
netif_tx_lock_bh(dev);
netif_addr_lock(dev);
spin_lock(&np->lock);
/* stop engines */
nv_stop_rxtx(dev);
Expand Down Expand Up @@ -4519,6 +4530,7 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri
/* restart engines */
nv_start_rxtx(dev);
spin_unlock(&np->lock);
netif_addr_unlock(dev);
netif_tx_unlock_bh(dev);
nv_enable_irq(dev);
}
Expand Down Expand Up @@ -4556,10 +4568,12 @@ static int nv_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam*
if (netif_running(dev)) {
nv_disable_irq(dev);
netif_tx_lock_bh(dev);
netif_addr_lock(dev);
spin_lock(&np->lock);
/* stop engines */
nv_stop_rxtx(dev);
spin_unlock(&np->lock);
netif_addr_unlock(dev);
netif_tx_unlock_bh(dev);
}

Expand Down Expand Up @@ -4946,6 +4960,7 @@ static void nv_self_test(struct net_device *dev, struct ethtool_test *test, u64
napi_disable(&np->napi);
#endif
netif_tx_lock_bh(dev);
netif_addr_lock(dev);
spin_lock_irq(&np->lock);
nv_disable_hw_interrupts(dev, np->irqmask);
if (!(np->msi_flags & NV_MSI_X_ENABLED)) {
Expand All @@ -4959,6 +4974,7 @@ static void nv_self_test(struct net_device *dev, struct ethtool_test *test, u64
/* drain rx queue */
nv_drain_rxtx(dev);
spin_unlock_irq(&np->lock);
netif_addr_unlock(dev);
netif_tx_unlock_bh(dev);
}

Expand Down
2 changes: 2 additions & 0 deletions drivers/net/hamradio/6pack.c
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,9 @@ static int sp_set_mac_address(struct net_device *dev, void *addr)
struct sockaddr_ax25 *sa = addr;

netif_tx_lock_bh(dev);
netif_addr_lock(dev);
memcpy(dev->dev_addr, &sa->sax25_call, AX25_ADDR_LEN);
netif_addr_unlock(dev);
netif_tx_unlock_bh(dev);

return 0;
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/hamradio/mkiss.c
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,9 @@ static int ax_set_mac_address(struct net_device *dev, void *addr)
struct sockaddr_ax25 *sa = addr;

netif_tx_lock_bh(dev);
netif_addr_lock(dev);
memcpy(dev->dev_addr, &sa->sax25_call, AX25_ADDR_LEN);
netif_addr_unlock(dev);
netif_tx_unlock_bh(dev);

return 0;
Expand Down
4 changes: 4 additions & 0 deletions drivers/net/ibm_newemac/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,9 @@ static void emac_rx_disable(struct emac_instance *dev)
static inline void emac_netif_stop(struct emac_instance *dev)
{
netif_tx_lock_bh(dev->ndev);
netif_addr_lock(dev->ndev);
dev->no_mcast = 1;
netif_addr_unlock(dev->ndev);
netif_tx_unlock_bh(dev->ndev);
dev->ndev->trans_start = jiffies; /* prevent tx timeout */
mal_poll_disable(dev->mal, &dev->commac);
Expand All @@ -305,9 +307,11 @@ static inline void emac_netif_stop(struct emac_instance *dev)
static inline void emac_netif_start(struct emac_instance *dev)
{
netif_tx_lock_bh(dev->ndev);
netif_addr_lock(dev->ndev);
dev->no_mcast = 0;
if (dev->mcast_pending && netif_running(dev->ndev))
__emac_set_multicast_list(dev);
netif_addr_unlock(dev->ndev);
netif_tx_unlock_bh(dev->ndev);

netif_wake_queue(dev->ndev);
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/sfc/efx.c
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,8 @@ static void efx_stop_port(struct efx_nic *efx)
/* Serialise against efx_set_multicast_list() */
if (efx_dev_registered(efx)) {
netif_tx_lock_bh(efx->net_dev);
netif_addr_lock(efx->net_dev);
netif_addr_unlock(efx->net_dev);
netif_tx_unlock_bh(efx->net_dev);
}
}
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/wireless/libertas/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,7 @@ static int lbs_add_mcast_addrs(struct cmd_ds_mac_multicast_adr *cmd,
return nr_addrs;

netif_tx_lock_bh(dev);
netif_addr_lock(dev);
for (mc_list = dev->mc_list; mc_list; mc_list = mc_list->next) {
if (mac_in_list(cmd->maclist, nr_addrs, mc_list->dmi_addr)) {
lbs_deb_net("mcast address %s:%s skipped\n", dev->name,
Expand All @@ -608,6 +609,7 @@ static int lbs_add_mcast_addrs(struct cmd_ds_mac_multicast_adr *cmd,
print_mac(mac, mc_list->dmi_addr));
i++;
}
netif_addr_unlock(dev);
netif_tx_unlock_bh(dev);
if (mc_list)
return -EOVERFLOW;
Expand Down
20 changes: 20 additions & 0 deletions include/linux/netdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -1498,6 +1498,26 @@ static inline void netif_tx_disable(struct net_device *dev)
netif_tx_unlock_bh(dev);
}

static inline void netif_addr_lock(struct net_device *dev)
{
spin_lock(&dev->addr_list_lock);
}

static inline void netif_addr_lock_bh(struct net_device *dev)
{
spin_lock_bh(&dev->addr_list_lock);
}

static inline void netif_addr_unlock(struct net_device *dev)
{
spin_unlock(&dev->addr_list_lock);
}

static inline void netif_addr_unlock_bh(struct net_device *dev)
{
spin_unlock_bh(&dev->addr_list_lock);
}

/* These functions live elsewhere (drivers/net/net_init.c, but related) */

extern void ether_setup(struct net_device *dev);
Expand Down
14 changes: 14 additions & 0 deletions net/core/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -2982,7 +2982,9 @@ void __dev_set_rx_mode(struct net_device *dev)
void dev_set_rx_mode(struct net_device *dev)
{
netif_tx_lock_bh(dev);
netif_addr_lock(dev);
__dev_set_rx_mode(dev);
netif_addr_unlock(dev);
netif_tx_unlock_bh(dev);
}

Expand Down Expand Up @@ -3062,9 +3064,11 @@ int dev_unicast_delete(struct net_device *dev, void *addr, int alen)
ASSERT_RTNL();

netif_tx_lock_bh(dev);
netif_addr_lock(dev);
err = __dev_addr_delete(&dev->uc_list, &dev->uc_count, addr, alen, 0);
if (!err)
__dev_set_rx_mode(dev);
netif_addr_unlock(dev);
netif_tx_unlock_bh(dev);
return err;
}
Expand All @@ -3088,9 +3092,11 @@ int dev_unicast_add(struct net_device *dev, void *addr, int alen)
ASSERT_RTNL();

netif_tx_lock_bh(dev);
netif_addr_lock(dev);
err = __dev_addr_add(&dev->uc_list, &dev->uc_count, addr, alen, 0);
if (!err)
__dev_set_rx_mode(dev);
netif_addr_unlock(dev);
netif_tx_unlock_bh(dev);
return err;
}
Expand Down Expand Up @@ -3159,10 +3165,12 @@ int dev_unicast_sync(struct net_device *to, struct net_device *from)
int err = 0;

netif_tx_lock_bh(to);
netif_addr_lock(to);
err = __dev_addr_sync(&to->uc_list, &to->uc_count,
&from->uc_list, &from->uc_count);
if (!err)
__dev_set_rx_mode(to);
netif_addr_unlock(to);
netif_tx_unlock_bh(to);
return err;
}
Expand All @@ -3180,13 +3188,17 @@ EXPORT_SYMBOL(dev_unicast_sync);
void dev_unicast_unsync(struct net_device *to, struct net_device *from)
{
netif_tx_lock_bh(from);
netif_addr_lock(from);
netif_tx_lock_bh(to);
netif_addr_lock(to);

__dev_addr_unsync(&to->uc_list, &to->uc_count,
&from->uc_list, &from->uc_count);
__dev_set_rx_mode(to);

netif_addr_unlock(to);
netif_tx_unlock_bh(to);
netif_addr_unlock(from);
netif_tx_unlock_bh(from);
}
EXPORT_SYMBOL(dev_unicast_unsync);
Expand All @@ -3208,13 +3220,15 @@ static void __dev_addr_discard(struct dev_addr_list **list)
static void dev_addr_discard(struct net_device *dev)
{
netif_tx_lock_bh(dev);
netif_addr_lock(dev);

__dev_addr_discard(&dev->uc_list);
dev->uc_count = 0;

__dev_addr_discard(&dev->mc_list);
dev->mc_count = 0;

netif_addr_unlock(dev);
netif_tx_unlock_bh(dev);
}

Expand Down
Loading

0 comments on commit e308a5d

Please sign in to comment.