| From c4d847aa8e2f156faa5057e8cd892efd06306f3e Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Tue, 9 Jun 2020 13:19:43 +0000 |
| Subject: ixgbe: protect ring accesses with READ- and WRITE_ONCE |
| |
| From: Ciara Loftus <ciara.loftus@intel.com> |
| |
| [ Upstream commit f140ad9fe2ae16f385f8fe4dc9cf67bb4c51d794 ] |
| |
| 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/ixgbe/ixgbe_lib.c | 12 ++++++------ |
| drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 14 +++++++++++--- |
| 2 files changed, 17 insertions(+), 9 deletions(-) |
| |
| diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c |
| index cc3196ae5aea8..636e6e840afa2 100644 |
| --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c |
| +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c |
| @@ -923,7 +923,7 @@ static int ixgbe_alloc_q_vector(struct ixgbe_adapter *adapter, |
| ring->queue_index = txr_idx; |
| |
| /* assign ring to adapter */ |
| - adapter->tx_ring[txr_idx] = ring; |
| + WRITE_ONCE(adapter->tx_ring[txr_idx], ring); |
| |
| /* update count and index */ |
| txr_count--; |
| @@ -950,7 +950,7 @@ static int ixgbe_alloc_q_vector(struct ixgbe_adapter *adapter, |
| set_ring_xdp(ring); |
| |
| /* assign ring to adapter */ |
| - adapter->xdp_ring[xdp_idx] = ring; |
| + WRITE_ONCE(adapter->xdp_ring[xdp_idx], ring); |
| |
| /* update count and index */ |
| xdp_count--; |
| @@ -993,7 +993,7 @@ static int ixgbe_alloc_q_vector(struct ixgbe_adapter *adapter, |
| ring->queue_index = rxr_idx; |
| |
| /* assign ring to adapter */ |
| - adapter->rx_ring[rxr_idx] = ring; |
| + WRITE_ONCE(adapter->rx_ring[rxr_idx], ring); |
| |
| /* update count and index */ |
| rxr_count--; |
| @@ -1022,13 +1022,13 @@ static void ixgbe_free_q_vector(struct ixgbe_adapter *adapter, int v_idx) |
| |
| ixgbe_for_each_ring(ring, q_vector->tx) { |
| if (ring_is_xdp(ring)) |
| - adapter->xdp_ring[ring->queue_index] = NULL; |
| + WRITE_ONCE(adapter->xdp_ring[ring->queue_index], NULL); |
| else |
| - adapter->tx_ring[ring->queue_index] = NULL; |
| + WRITE_ONCE(adapter->tx_ring[ring->queue_index], NULL); |
| } |
| |
| ixgbe_for_each_ring(ring, q_vector->rx) |
| - adapter->rx_ring[ring->queue_index] = NULL; |
| + WRITE_ONCE(adapter->rx_ring[ring->queue_index], NULL); |
| |
| adapter->q_vector[v_idx] = NULL; |
| napi_hash_del(&q_vector->napi); |
| diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c |
| index edaa0bffa5c35..5336bfcd2d701 100644 |
| --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c |
| +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c |
| @@ -7064,7 +7064,10 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter) |
| } |
| |
| for (i = 0; i < adapter->num_rx_queues; i++) { |
| - struct ixgbe_ring *rx_ring = adapter->rx_ring[i]; |
| + struct ixgbe_ring *rx_ring = READ_ONCE(adapter->rx_ring[i]); |
| + |
| + if (!rx_ring) |
| + continue; |
| non_eop_descs += rx_ring->rx_stats.non_eop_descs; |
| alloc_rx_page += rx_ring->rx_stats.alloc_rx_page; |
| alloc_rx_page_failed += rx_ring->rx_stats.alloc_rx_page_failed; |
| @@ -7085,15 +7088,20 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter) |
| packets = 0; |
| /* gather some stats to the adapter struct that are per queue */ |
| for (i = 0; i < adapter->num_tx_queues; i++) { |
| - struct ixgbe_ring *tx_ring = adapter->tx_ring[i]; |
| + struct ixgbe_ring *tx_ring = READ_ONCE(adapter->tx_ring[i]); |
| + |
| + if (!tx_ring) |
| + continue; |
| restart_queue += tx_ring->tx_stats.restart_queue; |
| tx_busy += tx_ring->tx_stats.tx_busy; |
| bytes += tx_ring->stats.bytes; |
| packets += tx_ring->stats.packets; |
| } |
| for (i = 0; i < adapter->num_xdp_queues; i++) { |
| - struct ixgbe_ring *xdp_ring = adapter->xdp_ring[i]; |
| + struct ixgbe_ring *xdp_ring = READ_ONCE(adapter->xdp_ring[i]); |
| |
| + if (!xdp_ring) |
| + continue; |
| restart_queue += xdp_ring->tx_stats.restart_queue; |
| tx_busy += xdp_ring->tx_stats.tx_busy; |
| bytes += xdp_ring->stats.bytes; |
| -- |
| 2.25.1 |
| |