From 0d1ddfe42c55a691340f2d8979b5f0a031dfcf62 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 6 Oct 2025 13:06:06 +0100 Subject: [PATCH] [gve] Cancel pending transmissions when closing device We cancel any pending transmissions when (re)starting the device since any transmissions that were initiated before the admin queue reset will not complete. The network device core will also cancel any pending transmissions after the device is closed. If the device is closed with some transmissions still pending and is then reopened, this will therefore result in a stale I/O buffer being passed to netdev_tx_complete_err() when the device is restarted. This error has not been observed in practice since transmissions generally complete almost immediately and it is therefore unlikely that the device will ever be closed with transmissions still pending. With out-of-order queues, the device seems to delay transmit completions (with no upper time limit) until a complete batch is available to be written out as a block of 128 bytes. It is therefore very likely that the device will be closed with transmissions still pending. Fix by ensuring that we have dropped all references to transmit I/O buffers before returning from gve_close(). Signed-off-by: Michael Brown --- src/drivers/net/gve.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/drivers/net/gve.c b/src/drivers/net/gve.c index cf796a8b5..fa8a15407 100644 --- a/src/drivers/net/gve.c +++ b/src/drivers/net/gve.c @@ -1073,18 +1073,14 @@ static void gve_free_queue ( struct gve_nic *gve, struct gve_queue *queue ) { } /** - * Start up device + * Cancel any pending transmissions * * @v gve GVE device - * @ret rc Return status code */ -static int gve_start ( struct gve_nic *gve ) { +static void gve_cancel_tx ( struct gve_nic *gve ) { struct net_device *netdev = gve->netdev; - struct gve_queue *tx = &gve->tx; - struct gve_queue *rx = &gve->rx; struct io_buffer *iobuf; unsigned int i; - int rc; /* Cancel any pending transmissions */ for ( i = 0 ; i < ( sizeof ( gve->tx_iobuf ) / @@ -1094,6 +1090,21 @@ static int gve_start ( struct gve_nic *gve ) { if ( iobuf ) netdev_tx_complete_err ( netdev, iobuf, -ECANCELED ); } +} + +/** + * Start up device + * + * @v gve GVE device + * @ret rc Return status code + */ +static int gve_start ( struct gve_nic *gve ) { + struct gve_queue *tx = &gve->tx; + struct gve_queue *rx = &gve->rx; + int rc; + + /* Cancel any pending transmissions */ + gve_cancel_tx ( gve ); /* Reset receive sequence */ gve->seq = gve_next ( 0 ); @@ -1307,6 +1318,9 @@ static void gve_close ( struct net_device *netdev ) { gve_stop ( gve ); gve_reset ( gve ); + /* Cancel any pending transmissions */ + gve_cancel_tx ( gve ); + /* Free queues */ gve_free_queue ( gve, rx ); gve_free_queue ( gve, tx ); -- 2.47.3