diff options
author | David S. Miller <davem@davemloft.net> | 2009-06-25 05:45:42 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-06-25 05:45:42 -0400 |
commit | 11687a1099583273a8a98ec42af62b5bb5a69e45 (patch) | |
tree | 6af6c13ece4944985d0b0c94880ce68ac5035128 | |
parent | 6a9b6546164fb380a019f92ca4d76443202fdc4f (diff) |
Revert "veth: prevent oops caused by netdev destructor"
This reverts commit ae0e8e82205c903978a79ebf5e31c670b61fa5b4.
This change had two problems:
1) Since it frees the stats in the drivers' close method, we
can OOPS in the transmit routine.
2) stats are no longer remembered across ifdown/ifup which
disagrees with how every other device operates.
Thanks to analysis and test patch from Serge E. Hallyn
and initial OOPS report by Sachin Sant.
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/veth.c | 41 |
1 files changed, 25 insertions, 16 deletions
diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 87197dd9c788..1097c72e44d5 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c | |||
@@ -208,11 +208,14 @@ rx_drop: | |||
208 | 208 | ||
209 | static struct net_device_stats *veth_get_stats(struct net_device *dev) | 209 | static struct net_device_stats *veth_get_stats(struct net_device *dev) |
210 | { | 210 | { |
211 | struct veth_priv *priv = netdev_priv(dev); | 211 | struct veth_priv *priv; |
212 | struct net_device_stats *dev_stats = &dev->stats; | 212 | struct net_device_stats *dev_stats; |
213 | unsigned int cpu; | 213 | int cpu; |
214 | struct veth_net_stats *stats; | 214 | struct veth_net_stats *stats; |
215 | 215 | ||
216 | priv = netdev_priv(dev); | ||
217 | dev_stats = &dev->stats; | ||
218 | |||
216 | dev_stats->rx_packets = 0; | 219 | dev_stats->rx_packets = 0; |
217 | dev_stats->tx_packets = 0; | 220 | dev_stats->tx_packets = 0; |
218 | dev_stats->rx_bytes = 0; | 221 | dev_stats->rx_bytes = 0; |
@@ -220,17 +223,16 @@ static struct net_device_stats *veth_get_stats(struct net_device *dev) | |||
220 | dev_stats->tx_dropped = 0; | 223 | dev_stats->tx_dropped = 0; |
221 | dev_stats->rx_dropped = 0; | 224 | dev_stats->rx_dropped = 0; |
222 | 225 | ||
223 | if (priv->stats) | 226 | for_each_online_cpu(cpu) { |
224 | for_each_online_cpu(cpu) { | 227 | stats = per_cpu_ptr(priv->stats, cpu); |
225 | stats = per_cpu_ptr(priv->stats, cpu); | ||
226 | 228 | ||
227 | dev_stats->rx_packets += stats->rx_packets; | 229 | dev_stats->rx_packets += stats->rx_packets; |
228 | dev_stats->tx_packets += stats->tx_packets; | 230 | dev_stats->tx_packets += stats->tx_packets; |
229 | dev_stats->rx_bytes += stats->rx_bytes; | 231 | dev_stats->rx_bytes += stats->rx_bytes; |
230 | dev_stats->tx_bytes += stats->tx_bytes; | 232 | dev_stats->tx_bytes += stats->tx_bytes; |
231 | dev_stats->tx_dropped += stats->tx_dropped; | 233 | dev_stats->tx_dropped += stats->tx_dropped; |
232 | dev_stats->rx_dropped += stats->rx_dropped; | 234 | dev_stats->rx_dropped += stats->rx_dropped; |
233 | } | 235 | } |
234 | 236 | ||
235 | return dev_stats; | 237 | return dev_stats; |
236 | } | 238 | } |
@@ -257,8 +259,6 @@ static int veth_close(struct net_device *dev) | |||
257 | netif_carrier_off(dev); | 259 | netif_carrier_off(dev); |
258 | netif_carrier_off(priv->peer); | 260 | netif_carrier_off(priv->peer); |
259 | 261 | ||
260 | free_percpu(priv->stats); | ||
261 | priv->stats = NULL; | ||
262 | return 0; | 262 | return 0; |
263 | } | 263 | } |
264 | 264 | ||
@@ -289,6 +289,15 @@ static int veth_dev_init(struct net_device *dev) | |||
289 | return 0; | 289 | return 0; |
290 | } | 290 | } |
291 | 291 | ||
292 | static void veth_dev_free(struct net_device *dev) | ||
293 | { | ||
294 | struct veth_priv *priv; | ||
295 | |||
296 | priv = netdev_priv(dev); | ||
297 | free_percpu(priv->stats); | ||
298 | free_netdev(dev); | ||
299 | } | ||
300 | |||
292 | static const struct net_device_ops veth_netdev_ops = { | 301 | static const struct net_device_ops veth_netdev_ops = { |
293 | .ndo_init = veth_dev_init, | 302 | .ndo_init = veth_dev_init, |
294 | .ndo_open = veth_open, | 303 | .ndo_open = veth_open, |
@@ -306,7 +315,7 @@ static void veth_setup(struct net_device *dev) | |||
306 | dev->netdev_ops = &veth_netdev_ops; | 315 | dev->netdev_ops = &veth_netdev_ops; |
307 | dev->ethtool_ops = &veth_ethtool_ops; | 316 | dev->ethtool_ops = &veth_ethtool_ops; |
308 | dev->features |= NETIF_F_LLTX; | 317 | dev->features |= NETIF_F_LLTX; |
309 | dev->destructor = free_netdev; | 318 | dev->destructor = veth_dev_free; |
310 | } | 319 | } |
311 | 320 | ||
312 | /* | 321 | /* |