]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
bnxt_en: Fix race conditions in .ndo_get_stats64().
authorMichael Chan <michael.chan@broadcom.com>
Tue, 11 Jul 2017 17:05:34 +0000 (13:05 -0400)
committerBrian Maly <brian.maly@oracle.com>
Tue, 19 Mar 2019 16:48:46 +0000 (12:48 -0400)
.ndo_get_stats64() may not be protected by RTNL and can race with
.ndo_stop() or other ethtool operations that can free the statistics
memory.  Fix it by setting a new flag BNXT_STATE_READ_STATS and then
proceeding to read statistics memory only if the state is OPEN.  The
close path that frees the memory clears the OPEN state and then waits
for the BNXT_STATE_READ_STATS to clear before proceeding to free the
statistics memory.

Fixes: c0c050c58d84 ("bnxt_en: New Broadcom ethernet driver.")
Signed-off-by: Michael Chan <michael.chan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit f9b76ebd49f97458857568918c305a17fa7c6567)
Signed-off-by: aru kolappan <aru.kolappan@oracle.com>
Orabug: 29129625

Reviewed-by: Jack Vogel <jack.vogel@oracle.com>
Signed-off-by: aru kolappan <aru.kolappan@oracle.com>
Signed-off-by: Brian Maly <brian.maly@oracle.com>
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/broadcom/bnxt/bnxt.h

index f2944439517381d9459867ba50889de65f2bfb78..5a15d28d43531d9e0be02e3bb045d727f7839f0d 100644 (file)
@@ -6812,7 +6812,11 @@ static int bnxt_open(struct net_device *dev)
        return __bnxt_open_nic(bp, true, true);
 }
 
-
+static bool bnxt_drv_busy(struct bnxt *bp)
+{
+       return (test_bit(BNXT_STATE_IN_SP_TASK, &bp->state) ||
+               test_bit(BNXT_STATE_READ_STATS, &bp->state));
+}
 
 static void __bnxt_close_nic(struct bnxt *bp, bool irq_re_init,
                             bool link_re_init)
@@ -6822,7 +6826,7 @@ static void __bnxt_close_nic(struct bnxt *bp, bool irq_re_init,
 
        clear_bit(BNXT_STATE_OPEN, &bp->state);
        smp_mb__after_atomic();
-       while (test_bit(BNXT_STATE_IN_SP_TASK, &bp->state))
+       while (bnxt_drv_busy(bp))
                msleep(20);
 
        /* Flush rings and and disable interrupts */
@@ -6901,8 +6905,15 @@ bnxt_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
 
        memset(stats, 0, sizeof(struct rtnl_link_stats64));
 
-       if (!bp->bnapi)
+       set_bit(BNXT_STATE_READ_STATS, &bp->state);
+       /* Make sure bnxt_close_nic() sees that we are reading stats before
+        * we check the BNXT_STATE_OPEN flag.
+        */
+       smp_mb__after_atomic();
+       if (!test_bit(BNXT_STATE_OPEN, &bp->state)) {
+               clear_bit(BNXT_STATE_READ_STATS, &bp->state);
                return stats;
+       }
 
        /* TODO check if we need to synchronize with bnxt_close path */
        for (i = 0; i < bp->cp_nr_rings; i++) {
@@ -6949,7 +6960,7 @@ bnxt_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
                stats->tx_fifo_errors = le64_to_cpu(tx->tx_fifo_underruns);
                stats->tx_errors = le64_to_cpu(tx->tx_err);
        }
-
+       clear_bit(BNXT_STATE_READ_STATS, &bp->state);
        return stats;
 }
 
index 09a70ea409ae371583b6699d672f2335b3655b60..31deb72b295255f93019da33d1c19e807c0b9f05 100644 (file)
@@ -1167,6 +1167,7 @@ struct bnxt {
        unsigned long           state;
 #define BNXT_STATE_OPEN                0
 #define BNXT_STATE_IN_SP_TASK  1
+#define BNXT_STATE_READ_STATS  2
 
        struct bnxt_irq *irq_tbl;
        int                     total_irqs;