From 82a5bd6a7b1b60b5d357e2e4b93b914f57314016 Mon Sep 17 00:00:00 2001 From: Sebastian Siewior Date: Sat, 14 Feb 2009 23:26:18 +0000 Subject: net/mv643xx: use GFP_ATOMIC while atomic dev_set_rx_mode() grabs netif_addr_lock_bh(): |BUG: sleeping function called from invalid context at /home/bigeasy/git/cryptodev-2.6/mm/slub.c:1599 |in_atomic(): 1, irqs_disabled(): 0, pid: 859, name: ifconfig |2 locks held by ifconfig/859: | #0: (rtnl_mutex){--..}, at: [] rtnl_lock+0x18/0x20 | #1: (_xmit_ETHER){-...}, at: [] dev_set_rx_mode+0x1c/0x30 |[] (dump_stack+0x0/0x14) from [] (__might_sleep+0x11c/0x13c) |[] (__might_sleep+0x0/0x13c) from [] (kmem_cache_alloc+0x30/0xd4) | r5:c78093a0 r4:c034a47c |[] (kmem_cache_alloc+0x0/0xd4) from [] (mv643xx_eth_set_rx_mode+0x70/0x188) |[] (mv643xx_eth_set_rx_mode+0x0/0x188) from [] (__dev_set_rx_mode+0x40/0xac) |[] (__dev_set_rx_mode+0x0/0xac) from [] (dev_set_rx_mode+0x24/0x30) | r6:00001043 r5:c78090f8 r4:c7809000 |[] (dev_set_rx_mode+0x0/0x30) from [] (dev_open+0xe4/0x114) | r5:c7809350 r4:c7809000 |[] (dev_open+0x0/0x114) from [] (dev_change_flags+0xb0/0x190) | r5:00000041 r4:c7809000 |[] (dev_change_flags+0x0/0x190) from [] (devinet_ioctl+0x2f0/0x710) | r7:c7221e70 r6:c7aadb00 r5:00000000 r4:00000001 |[] (devinet_ioctl+0x0/0x710) from [] (inet_ioctl+0xd4/0x110) |[] (inet_ioctl+0x0/0x110) from [] (sock_ioctl+0x1f4/0x254) | r4:c7242b40 |[] (sock_ioctl+0x0/0x254) from [] (vfs_ioctl+0x38/0x98) | r6:beec9bb8 r5:00008914 r4:c7242b40 |[] (vfs_ioctl+0x0/0x98) from [] (do_vfs_ioctl+0x484/0x4d4) | r6:00008914 r5:c7242b40 r4:c74db1c0 |[] (do_vfs_ioctl+0x0/0x4d4) from [] (sys_ioctl+0x40/0x64) |[] (sys_ioctl+0x0/0x64) from [] (ret_fast_syscall+0x0/0x2c) |[42949399.520000] r7:00000036 r6:beec9c80 r5:00000041 r4:beec9bb8 Signed-off-by: Sebastian Andrzej Siewior Acked-by: Lennert Buytenhek Signed-off-by: David S. Miller --- drivers/net/mv643xx_eth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/mv643xx_eth.c') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 5f31bbb614a..b6ab46942b9 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -1575,7 +1575,7 @@ oom: return; } - mc_spec = kmalloc(0x200, GFP_KERNEL); + mc_spec = kmalloc(0x200, GFP_ATOMIC); if (mc_spec == NULL) goto oom; mc_other = mc_spec + (0x100 >> 2); -- cgit v1.2.3 From 57e8f26a10ac4af488292199bb0435555f6723f3 Mon Sep 17 00:00:00 2001 From: Sebastian Siewior Date: Mon, 16 Feb 2009 11:28:15 +0000 Subject: net/mv643xx: don't disable the mib timer too early and lock properly mib_counters_update() also restarts the timer. So the timer is dequeued, the stats are read and then the timer is enqueued again. This is "okay" unless someone unloads the module. The locking here is also broken: mib_counters_update() grabs just a simple spinlock. The only thing the lock is good for is to protect the timer func against other callers namely mv643xx_eth_stop() && mv643xx_eth_get_ethtool_stats(). That means if the spinlock is taken via the ethtool path and than the timer kicks in then the box will lock up. Signed-off-by: Sebastian Andrzej Siewior Acked-by: Lennert Buytenhek Signed-off-by: David S. Miller --- drivers/net/mv643xx_eth.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/net/mv643xx_eth.c') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index b6ab46942b9..13f11f402a9 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -1175,7 +1175,7 @@ static void mib_counters_update(struct mv643xx_eth_private *mp) { struct mib_counters *p = &mp->mib_counters; - spin_lock(&mp->mib_counters_lock); + spin_lock_bh(&mp->mib_counters_lock); p->good_octets_received += mib_read(mp, 0x00); p->good_octets_received += (u64)mib_read(mp, 0x04) << 32; p->bad_octets_received += mib_read(mp, 0x08); @@ -1208,7 +1208,7 @@ static void mib_counters_update(struct mv643xx_eth_private *mp) p->bad_crc_event += mib_read(mp, 0x74); p->collision += mib_read(mp, 0x78); p->late_collision += mib_read(mp, 0x7c); - spin_unlock(&mp->mib_counters_lock); + spin_unlock_bh(&mp->mib_counters_lock); mod_timer(&mp->mib_counters_timer, jiffies + 30 * HZ); } @@ -2216,8 +2216,6 @@ static int mv643xx_eth_stop(struct net_device *dev) wrlp(mp, INT_MASK, 0x00000000); rdlp(mp, INT_MASK); - del_timer_sync(&mp->mib_counters_timer); - napi_disable(&mp->napi); del_timer_sync(&mp->rx_oom); @@ -2229,6 +2227,7 @@ static int mv643xx_eth_stop(struct net_device *dev) port_reset(mp); mv643xx_eth_get_stats(dev); mib_counters_update(mp); + del_timer_sync(&mp->mib_counters_timer); skb_queue_purge(&mp->rx_recycle); -- cgit v1.2.3