| From 42fff6051ab899de6b054e4638d8e275c745c223 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Tue, 9 Jun 2020 13:19:44 +0000 |
| Subject: i40e: protect ring accesses with READ- and WRITE_ONCE |
| |
| From: Ciara Loftus <ciara.loftus@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.loftus@intel.com> |
| Tested-by: Andrew Bowers <andrewx.bowers@intel.com> |
| Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com> |
| Signed-off-by: Sasha Levin <sashal@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 |
| |