Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Max Yuan and committed by
Jakub Kicinski
858b1d07 4c035926

+8
+2
drivers/net/ethernet/google/gve/gve_tx.c
··· 730 730 gve_tx_unmap_buf(tx->dev, &tx->info[idx & tx->mask]); 731 731 } 732 732 drop: 733 + u64_stats_update_begin(&tx->statss); 733 734 tx->dropped_pkt++; 735 + u64_stats_update_end(&tx->statss); 734 736 return 0; 735 737 } 736 738
+6
drivers/net/ethernet/google/gve/gve_tx_dqo.c
··· 1002 1002 return 0; 1003 1003 1004 1004 drop: 1005 + u64_stats_update_begin(&tx->statss); 1005 1006 tx->dropped_pkt++; 1007 + u64_stats_update_end(&tx->statss); 1006 1008 dev_kfree_skb_any(skb); 1007 1009 return 0; 1008 1010 } ··· 1326 1324 /* This indicates the packet was dropped. */ 1327 1325 dev_kfree_skb_any(pending_packet->skb); 1328 1326 pending_packet->skb = NULL; 1327 + 1328 + u64_stats_update_begin(&tx->statss); 1329 1329 tx->dropped_pkt++; 1330 + u64_stats_update_end(&tx->statss); 1331 + 1330 1332 net_err_ratelimited("%s: No reinjection completion was received for: %d.\n", 1331 1333 priv->dev->name, 1332 1334 (int)(pending_packet - tx->dqo.pending_packets));