Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <sebastian@breakpoint.cc>
Acked-by: Lennert Buytenhek <buytenh@marvell.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Sebastian Siewior and committed by
David S. Miller
57e8f26a 82a5bd6a

+3 -4
+3 -4
drivers/net/mv643xx_eth.c
··· 1175 { 1176 struct mib_counters *p = &mp->mib_counters; 1177 1178 - spin_lock(&mp->mib_counters_lock); 1179 p->good_octets_received += mib_read(mp, 0x00); 1180 p->good_octets_received += (u64)mib_read(mp, 0x04) << 32; 1181 p->bad_octets_received += mib_read(mp, 0x08); ··· 1208 p->bad_crc_event += mib_read(mp, 0x74); 1209 p->collision += mib_read(mp, 0x78); 1210 p->late_collision += mib_read(mp, 0x7c); 1211 - spin_unlock(&mp->mib_counters_lock); 1212 1213 mod_timer(&mp->mib_counters_timer, jiffies + 30 * HZ); 1214 } ··· 2216 wrlp(mp, INT_MASK, 0x00000000); 2217 rdlp(mp, INT_MASK); 2218 2219 - del_timer_sync(&mp->mib_counters_timer); 2220 - 2221 napi_disable(&mp->napi); 2222 2223 del_timer_sync(&mp->rx_oom); ··· 2227 port_reset(mp); 2228 mv643xx_eth_get_stats(dev); 2229 mib_counters_update(mp); 2230 2231 skb_queue_purge(&mp->rx_recycle); 2232
··· 1175 { 1176 struct mib_counters *p = &mp->mib_counters; 1177 1178 + spin_lock_bh(&mp->mib_counters_lock); 1179 p->good_octets_received += mib_read(mp, 0x00); 1180 p->good_octets_received += (u64)mib_read(mp, 0x04) << 32; 1181 p->bad_octets_received += mib_read(mp, 0x08); ··· 1208 p->bad_crc_event += mib_read(mp, 0x74); 1209 p->collision += mib_read(mp, 0x78); 1210 p->late_collision += mib_read(mp, 0x7c); 1211 + spin_unlock_bh(&mp->mib_counters_lock); 1212 1213 mod_timer(&mp->mib_counters_timer, jiffies + 30 * HZ); 1214 } ··· 2216 wrlp(mp, INT_MASK, 0x00000000); 2217 rdlp(mp, INT_MASK); 2218 2219 napi_disable(&mp->napi); 2220 2221 del_timer_sync(&mp->rx_oom); ··· 2229 port_reset(mp); 2230 mv643xx_eth_get_stats(dev); 2231 mib_counters_update(mp); 2232 + del_timer_sync(&mp->mib_counters_timer); 2233 2234 skb_queue_purge(&mp->rx_recycle); 2235