From 0fa2298ed083c9e05fcff2c683c08c910320eb6d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 16 Nov 2010 19:26:42 -0800 Subject: [PATCH] --- yaml --- r: 224355 b: refs/heads/master c: 1a51502bddca7ac1e921d918b741ffd2bec149ed h: refs/heads/master i: 224353: b42d98969f0fa4b16a502517a18e545b7ba59e4f 224351: 2d7464d94b8e605a99ce0798c40e7d758b371566 v: v3 --- [refs] | 2 +- trunk/drivers/net/fec_mpc52xx.c | 19 +++++++++------- trunk/drivers/net/ixgbe/ixgbe.h | 1 + trunk/drivers/net/ixgbe/ixgbe_main.c | 34 ++++++++++++++++++++-------- 4 files changed, 37 insertions(+), 19 deletions(-) diff --git a/[refs] b/[refs] index aa86a93ffcd2..248b9d58e98d 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 9d1e5e40d6cac4bf7008e04c202d71918455ca11 +refs/heads/master: 1a51502bddca7ac1e921d918b741ffd2bec149ed diff --git a/trunk/drivers/net/fec_mpc52xx.c b/trunk/drivers/net/fec_mpc52xx.c index 50c1213f61fe..e9f5d030bc26 100644 --- a/trunk/drivers/net/fec_mpc52xx.c +++ b/trunk/drivers/net/fec_mpc52xx.c @@ -366,8 +366,9 @@ static irqreturn_t mpc52xx_fec_tx_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct mpc52xx_fec_priv *priv = netdev_priv(dev); + unsigned long flags; - spin_lock(&priv->lock); + spin_lock_irqsave(&priv->lock, flags); while (bcom_buffer_done(priv->tx_dmatsk)) { struct sk_buff *skb; struct bcom_fec_bd *bd; @@ -378,7 +379,7 @@ static irqreturn_t mpc52xx_fec_tx_interrupt(int irq, void *dev_id) dev_kfree_skb_irq(skb); } - spin_unlock(&priv->lock); + spin_unlock_irqrestore(&priv->lock, flags); netif_wake_queue(dev); @@ -394,8 +395,9 @@ static irqreturn_t mpc52xx_fec_rx_interrupt(int irq, void *dev_id) struct bcom_fec_bd *bd; u32 status, physaddr; int length; + unsigned long flags; - spin_lock(&priv->lock); + spin_lock_irqsave(&priv->lock, flags); while (bcom_buffer_done(priv->rx_dmatsk)) { @@ -427,7 +429,7 @@ static irqreturn_t mpc52xx_fec_rx_interrupt(int irq, void *dev_id) /* Process the received skb - Drop the spin lock while * calling into the network stack */ - spin_unlock(&priv->lock); + spin_unlock_irqrestore(&priv->lock, flags); dma_unmap_single(dev->dev.parent, physaddr, rskb->len, DMA_FROM_DEVICE); @@ -436,10 +438,10 @@ static irqreturn_t mpc52xx_fec_rx_interrupt(int irq, void *dev_id) rskb->protocol = eth_type_trans(rskb, dev); netif_rx(rskb); - spin_lock(&priv->lock); + spin_lock_irqsave(&priv->lock, flags); } - spin_unlock(&priv->lock); + spin_unlock_irqrestore(&priv->lock, flags); return IRQ_HANDLED; } @@ -450,6 +452,7 @@ static irqreturn_t mpc52xx_fec_interrupt(int irq, void *dev_id) struct mpc52xx_fec_priv *priv = netdev_priv(dev); struct mpc52xx_fec __iomem *fec = priv->fec; u32 ievent; + unsigned long flags; ievent = in_be32(&fec->ievent); @@ -467,9 +470,9 @@ static irqreturn_t mpc52xx_fec_interrupt(int irq, void *dev_id) if (net_ratelimit() && (ievent & FEC_IEVENT_XFIFO_ERROR)) dev_warn(&dev->dev, "FEC_IEVENT_XFIFO_ERROR\n"); - spin_lock(&priv->lock); + spin_lock_irqsave(&priv->lock, flags); mpc52xx_fec_reset(dev); - spin_unlock(&priv->lock); + spin_unlock_irqrestore(&priv->lock, flags); return IRQ_HANDLED; } diff --git a/trunk/drivers/net/ixgbe/ixgbe.h b/trunk/drivers/net/ixgbe/ixgbe.h index ed8703cfffb7..018e143612b2 100644 --- a/trunk/drivers/net/ixgbe/ixgbe.h +++ b/trunk/drivers/net/ixgbe/ixgbe.h @@ -192,6 +192,7 @@ struct ixgbe_ring { unsigned int size; /* length in bytes */ dma_addr_t dma; /* phys. address of descriptor ring */ + struct rcu_head rcu; } ____cacheline_internodealigned_in_smp; enum ixgbe_ring_f_enum { diff --git a/trunk/drivers/net/ixgbe/ixgbe_main.c b/trunk/drivers/net/ixgbe/ixgbe_main.c index fbad4d819608..a137f9dbaacd 100644 --- a/trunk/drivers/net/ixgbe/ixgbe_main.c +++ b/trunk/drivers/net/ixgbe/ixgbe_main.c @@ -4751,6 +4751,11 @@ int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter) return err; } +static void ring_free_rcu(struct rcu_head *head) +{ + kfree(container_of(head, struct ixgbe_ring, rcu)); +} + /** * ixgbe_clear_interrupt_scheme - Clear the current interrupt scheme settings * @adapter: board private structure to clear interrupt scheme on @@ -4767,7 +4772,12 @@ void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter) adapter->tx_ring[i] = NULL; } for (i = 0; i < adapter->num_rx_queues; i++) { - kfree(adapter->rx_ring[i]); + struct ixgbe_ring *ring = adapter->rx_ring[i]; + + /* ixgbe_get_stats64() might access this ring, we must wait + * a grace period before freeing it. + */ + call_rcu(&ring->rcu, ring_free_rcu); adapter->rx_ring[i] = NULL; } @@ -6563,20 +6573,23 @@ static struct rtnl_link_stats64 *ixgbe_get_stats64(struct net_device *netdev, /* accurate rx/tx bytes/packets stats */ dev_txq_stats_fold(netdev, stats); + rcu_read_lock(); for (i = 0; i < adapter->num_rx_queues; i++) { - struct ixgbe_ring *ring = adapter->rx_ring[i]; + struct ixgbe_ring *ring = ACCESS_ONCE(adapter->rx_ring[i]); u64 bytes, packets; unsigned int start; - do { - start = u64_stats_fetch_begin_bh(&ring->syncp); - packets = ring->stats.packets; - bytes = ring->stats.bytes; - } while (u64_stats_fetch_retry_bh(&ring->syncp, start)); - stats->rx_packets += packets; - stats->rx_bytes += bytes; + if (ring) { + do { + start = u64_stats_fetch_begin_bh(&ring->syncp); + packets = ring->stats.packets; + bytes = ring->stats.bytes; + } while (u64_stats_fetch_retry_bh(&ring->syncp, start)); + stats->rx_packets += packets; + stats->rx_bytes += bytes; + } } - + rcu_read_unlock(); /* following stats updated by ixgbe_watchdog_task() */ stats->multicast = netdev->stats.multicast; stats->rx_errors = netdev->stats.rx_errors; @@ -7282,6 +7295,7 @@ static void __exit ixgbe_exit_module(void) dca_unregister_notify(&dca_notifier); #endif pci_unregister_driver(&ixgbe_driver); + rcu_barrier(); /* Wait for completion of call_rcu()'s */ } #ifdef CONFIG_IXGBE_DCA