From: Ciara Loftus <ciara.lof...@intel.com>

[ Upstream commit d59e267912cd90b0adf33b4659050d831e746317 ]

READ_ONCE should be used when reading rings prior to accessing the
statistics pointer. Introduce this as well as the corresponding WRITE_ONCE
usage when allocating and freeing the rings, to ensure protected access.

Signed-off-by: Ciara Loftus <ciara.lof...@intel.com>
Tested-by: Andrew Bowers <andrewx.bow...@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirs...@intel.com>
Signed-off-by: Sasha Levin <sas...@kernel.org>
---
 drivers/net/ethernet/intel/i40e/i40e_main.c | 29 ++++++++++++++-------
 1 file changed, 19 insertions(+), 10 deletions(-)

diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c 
b/drivers/net/ethernet/intel/i40e/i40e_main.c
index a8dd0228b6787..095ed81cc0ba4 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -458,11 +458,15 @@ static void i40e_get_netdev_stats_struct(struct 
net_device *netdev,
                i40e_get_netdev_stats_struct_tx(ring, stats);
 
                if (i40e_enabled_xdp_vsi(vsi)) {
-                       ring++;
+                       ring = READ_ONCE(vsi->xdp_rings[i]);
+                       if (!ring)
+                               continue;
                        i40e_get_netdev_stats_struct_tx(ring, stats);
                }
 
-               ring++;
+               ring = READ_ONCE(vsi->rx_rings[i]);
+               if (!ring)
+                       continue;
                do {
                        start   = u64_stats_fetch_begin_irq(&ring->syncp);
                        packets = ring->stats.packets;
@@ -806,6 +810,8 @@ static void i40e_update_vsi_stats(struct i40e_vsi *vsi)
        for (q = 0; q < vsi->num_queue_pairs; q++) {
                /* locate Tx ring */
                p = READ_ONCE(vsi->tx_rings[q]);
+               if (!p)
+                       continue;
 
                do {
                        start = u64_stats_fetch_begin_irq(&p->syncp);
@@ -819,8 +825,11 @@ static void i40e_update_vsi_stats(struct i40e_vsi *vsi)
                tx_linearize += p->tx_stats.tx_linearize;
                tx_force_wb += p->tx_stats.tx_force_wb;
 
-               /* Rx queue is part of the same block as Tx queue */
-               p = &p[1];
+               /* locate Rx ring */
+               p = READ_ONCE(vsi->rx_rings[q]);
+               if (!p)
+                       continue;
+
                do {
                        start = u64_stats_fetch_begin_irq(&p->syncp);
                        packets = p->stats.packets;
@@ -10816,10 +10825,10 @@ static void i40e_vsi_clear_rings(struct i40e_vsi *vsi)
        if (vsi->tx_rings && vsi->tx_rings[0]) {
                for (i = 0; i < vsi->alloc_queue_pairs; i++) {
                        kfree_rcu(vsi->tx_rings[i], rcu);
-                       vsi->tx_rings[i] = NULL;
-                       vsi->rx_rings[i] = NULL;
+                       WRITE_ONCE(vsi->tx_rings[i], NULL);
+                       WRITE_ONCE(vsi->rx_rings[i], NULL);
                        if (vsi->xdp_rings)
-                               vsi->xdp_rings[i] = NULL;
+                               WRITE_ONCE(vsi->xdp_rings[i], NULL);
                }
        }
 }
@@ -10853,7 +10862,7 @@ static int i40e_alloc_rings(struct i40e_vsi *vsi)
                if (vsi->back->hw_features & I40E_HW_WB_ON_ITR_CAPABLE)
                        ring->flags = I40E_TXR_FLAGS_WB_ON_ITR;
                ring->itr_setting = pf->tx_itr_default;
-               vsi->tx_rings[i] = ring++;
+               WRITE_ONCE(vsi->tx_rings[i], ring++);
 
                if (!i40e_enabled_xdp_vsi(vsi))
                        goto setup_rx;
@@ -10871,7 +10880,7 @@ static int i40e_alloc_rings(struct i40e_vsi *vsi)
                        ring->flags = I40E_TXR_FLAGS_WB_ON_ITR;
                set_ring_xdp(ring);
                ring->itr_setting = pf->tx_itr_default;
-               vsi->xdp_rings[i] = ring++;
+               WRITE_ONCE(vsi->xdp_rings[i], ring++);
 
 setup_rx:
                ring->queue_index = i;
@@ -10884,7 +10893,7 @@ setup_rx:
                ring->size = 0;
                ring->dcb_tc = 0;
                ring->itr_setting = pf->rx_itr_default;
-               vsi->rx_rings[i] = ring;
+               WRITE_ONCE(vsi->rx_rings[i], ring);
        }
 
        return 0;
-- 
2.25.1



Reply via email to