netdev: Add netdev->addr_list_lock protection.
authorDavid S. Miller <davem@davemloft.net>
Tue, 15 Jul 2008 07:13:44 +0000 (00:13 -0700)
committerDavid S. Miller <davem@davemloft.net>
Tue, 15 Jul 2008 07:13:44 +0000 (00:13 -0700)
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>
14 files changed:
drivers/infiniband/ulp/ipoib/ipoib_multicast.c
drivers/media/dvb/dvb-core/dvb_net.c
drivers/net/bonding/bond_main.c
drivers/net/forcedeth.c
drivers/net/hamradio/6pack.c
drivers/net/hamradio/mkiss.c
drivers/net/ibm_newemac/core.c
drivers/net/sfc/efx.c
drivers/net/wireless/libertas/main.c
include/linux/netdevice.h
net/core/dev.c
net/core/dev_mcast.c
net/mac80211/main.c
net/mac80211/mlme.c

index 3f663fb852c1c627462807fd4348649eeda451d1..261ab7150431dd2a8bdc417235bd5fa50394637b 100644 (file)
@@ -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);
 
        /*
@@ -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);
 
index c2334aef4143f318813681587f2638870daf35a7..809d18c663bcf677d5bb486896ec017ca1a18e75 100644 (file)
@@ -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);
@@ -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);
 }
index 8ae7ff313218e42725fa52bd2de712c75baf1a2d..ea71abd6f7286d5a9c66e9f333b9630f093d08c7 100644 (file)
@@ -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);
        }
 
@@ -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);
        }
 
@@ -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);
                }
 
@@ -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);
index 786d668c612e897781ef9e91b3445591a66d5527..4ed89fa9ae46fa05e765fcaaa04854b7c4051fe0 100644 (file)
@@ -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);
@@ -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);
        }
@@ -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 */
@@ -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);
@@ -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);
@@ -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);
                }
        }
@@ -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 */
@@ -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);
        }
 
@@ -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);
                }
@@ -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);
@@ -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);
        }
@@ -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);
        }
 
@@ -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)) {
@@ -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);
                }
 
index 06ad9f302b5a757fd8d9ddad2600807cca54c422..ffc937f5d15dd82361e3c6e4bd4997e271b8f0ef 100644 (file)
@@ -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;
index 65166035aca0c81b5bea15d608bb88cf945ef24c..b8740e6a5ceca57a809dd443a4fd2623e3ad1ebc 100644 (file)
@@ -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;
index babc79ad490b6ada422a3ce96f9fefd510050b65..9ca57d3655997a25f8bfbf671aa227131c7c0d2e 100644 (file)
@@ -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);
@@ -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);
index 74265d8553b8b58e76a50067fd17f50298cf5323..e1257e556e48e63b9eb2592d3182ab84aa03cb3a 100644 (file)
@@ -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);
        }
 }
index abd6d9ed8f4bff9bcc83f9dbdd30563cd572c399..42e9b2771eab02d9b71d0f86c5b8b0a61aa5f5f8 100644 (file)
@@ -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,
@@ -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;
index fd0365219181cfae78c7b61fbffd14fa1eb2a255..570cf7affa7267a8a813c9155e39dc3bc14e33e5 100644 (file)
@@ -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);
index d933d1bfa6fa0c6ca1d704fe15be934657294715..ef1502d71f25cb4c5e30bd769ced1dec760212c3 100644 (file)
@@ -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);
 }
 
@@ -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;
 }
@@ -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;
 }
@@ -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;
 }
@@ -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);
@@ -3208,6 +3220,7 @@ 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;
@@ -3215,6 +3228,7 @@ static void dev_addr_discard(struct net_device *dev)
        __dev_addr_discard(&dev->mc_list);
        dev->mc_count = 0;
 
+       netif_addr_unlock(dev);
        netif_tx_unlock_bh(dev);
 }
 
index f8a3455f4493f7276fe614af6dbd7c26f4f04cb8..b6b2a129971a05eeca2c894cf0f7975f8c426871 100644 (file)
@@ -73,6 +73,7 @@ int dev_mc_delete(struct net_device *dev, void *addr, int alen, int glbl)
        int err;
 
        netif_tx_lock_bh(dev);
+       netif_addr_lock(dev);
        err = __dev_addr_delete(&dev->mc_list, &dev->mc_count,
                                addr, alen, glbl);
        if (!err) {
@@ -83,6 +84,7 @@ int dev_mc_delete(struct net_device *dev, void *addr, int alen, int glbl)
 
                __dev_set_rx_mode(dev);
        }
+       netif_addr_unlock(dev);
        netif_tx_unlock_bh(dev);
        return err;
 }
@@ -96,9 +98,11 @@ int dev_mc_add(struct net_device *dev, void *addr, int alen, int glbl)
        int err;
 
        netif_tx_lock_bh(dev);
+       netif_addr_lock(dev);
        err = __dev_addr_add(&dev->mc_list, &dev->mc_count, addr, alen, glbl);
        if (!err)
                __dev_set_rx_mode(dev);
+       netif_addr_unlock(dev);
        netif_tx_unlock_bh(dev);
        return err;
 }
@@ -120,10 +124,12 @@ int dev_mc_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->mc_list, &to->mc_count,
                              &from->mc_list, &from->mc_count);
        if (!err)
                __dev_set_rx_mode(to);
+       netif_addr_unlock(to);
        netif_tx_unlock_bh(to);
 
        return err;
@@ -144,13 +150,17 @@ EXPORT_SYMBOL(dev_mc_sync);
 void dev_mc_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->mc_list, &to->mc_count,
                          &from->mc_list, &from->mc_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_mc_unsync);
@@ -165,6 +175,7 @@ static int dev_mc_seq_show(struct seq_file *seq, void *v)
                return 0;
 
        netif_tx_lock_bh(dev);
+       netif_addr_lock(dev);
        for (m = dev->mc_list; m; m = m->next) {
                int i;
 
@@ -176,6 +187,7 @@ static int dev_mc_seq_show(struct seq_file *seq, void *v)
 
                seq_putc(seq, '\n');
        }
+       netif_addr_unlock(dev);
        netif_tx_unlock_bh(dev);
        return 0;
 }
index 36859e7949289c0e01740a1b545204595050cc31..095b7d928d6416e8ec8aaca396b0b43b16f14e6c 100644 (file)
@@ -292,7 +292,9 @@ static int ieee80211_open(struct net_device *dev)
                        local->fif_other_bss++;
 
                netif_tx_lock_bh(local->mdev);
+               netif_addr_lock(local->mdev);
                ieee80211_configure_filter(local);
+               netif_addr_unlock(local->mdev);
                netif_tx_unlock_bh(local->mdev);
                break;
        case IEEE80211_IF_TYPE_STA:
@@ -491,7 +493,9 @@ static int ieee80211_stop(struct net_device *dev)
                        local->fif_other_bss--;
 
                netif_tx_lock_bh(local->mdev);
+               netif_addr_lock(local->mdev);
                ieee80211_configure_filter(local);
+               netif_addr_unlock(local->mdev);
                netif_tx_unlock_bh(local->mdev);
                break;
        case IEEE80211_IF_TYPE_MESH_POINT:
index 8f51375317dd5e94cdb776d047032dbb014d469f..1232ba25e1e90c127b95f847ff5de0bceafa65d8 100644 (file)
@@ -3869,6 +3869,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
 
 
        netif_tx_lock_bh(local->mdev);
+       netif_addr_lock(local->mdev);
        local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC;
        local->ops->configure_filter(local_to_hw(local),
                                     FIF_BCN_PRBRESP_PROMISC,
@@ -3876,6 +3877,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
                                     local->mdev->mc_count,
                                     local->mdev->mc_list);
 
+       netif_addr_unlock(local->mdev);
        netif_tx_unlock_bh(local->mdev);
 
        rcu_read_lock();
@@ -4063,12 +4065,14 @@ static int ieee80211_sta_start_scan(struct net_device *dev,
        local->scan_dev = dev;
 
        netif_tx_lock_bh(local->mdev);
+       netif_addr_lock(local->mdev);
        local->filter_flags |= FIF_BCN_PRBRESP_PROMISC;
        local->ops->configure_filter(local_to_hw(local),
                                     FIF_BCN_PRBRESP_PROMISC,
                                     &local->filter_flags,
                                     local->mdev->mc_count,
                                     local->mdev->mc_list);
+       netif_addr_unlock(local->mdev);
        netif_tx_unlock_bh(local->mdev);
 
        /* TODO: start scan as soon as all nullfunc frames are ACKed */