mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
gve: Fix race condition on tx->dropped_pkt update
The tx->dropped_pkt counter is a 64-bit integer that is incremented directly. On 32-bit architectures, this operation is not atomic and can lead to read/write tearing if a reader accesses the counter during the update. This can result in incorrect values being reported for dropped packets. To prevent this potential data corruption, wrap the increment operation with u64_stats_update_begin() and u64_stats_update_end(). This ensures that updates to the 64-bit counter are atomic, even on 32-bit systems, by using a sequence lock. The u64_stats_sync API requires the writer to have exclusive access, which is already provided in this context by the network stack's serialization of the transmit path (net_device_ops::ndo_start_xmit [1]) for a given queue. [1]: https://www.kernel.org/doc/Documentation/networking/netdevices.txt Signed-off-by: Max Yuan <maxyuan@google.com> Reviewed-by: Jordan Rhee <jordanrhee@google.com> Signed-off-by: Harshitha Ramamurthy <hramamurthy@google.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
@@ -730,7 +730,9 @@ unmap_drop:
|
||||
gve_tx_unmap_buf(tx->dev, &tx->info[idx & tx->mask]);
|
||||
}
|
||||
drop:
|
||||
u64_stats_update_begin(&tx->statss);
|
||||
tx->dropped_pkt++;
|
||||
u64_stats_update_end(&tx->statss);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1002,7 +1002,9 @@ static int gve_try_tx_skb(struct gve_priv *priv, struct gve_tx_ring *tx,
|
||||
return 0;
|
||||
|
||||
drop:
|
||||
u64_stats_update_begin(&tx->statss);
|
||||
tx->dropped_pkt++;
|
||||
u64_stats_update_end(&tx->statss);
|
||||
dev_kfree_skb_any(skb);
|
||||
return 0;
|
||||
}
|
||||
@@ -1324,7 +1326,11 @@ static void remove_miss_completions(struct gve_priv *priv,
|
||||
/* This indicates the packet was dropped. */
|
||||
dev_kfree_skb_any(pending_packet->skb);
|
||||
pending_packet->skb = NULL;
|
||||
|
||||
u64_stats_update_begin(&tx->statss);
|
||||
tx->dropped_pkt++;
|
||||
u64_stats_update_end(&tx->statss);
|
||||
|
||||
net_err_ratelimited("%s: No reinjection completion was received for: %d.\n",
|
||||
priv->dev->name,
|
||||
(int)(pending_packet - tx->dqo.pending_packets));
|
||||
|
||||
Reference in New Issue
Block a user