From: netdev-bot+sashiko@kernel.org
To: hramamurthy@google.com
Cc: netdev@vger.kernel.org, joshwash@google.com,
andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com,
kuba@kernel.org, pabeni@redhat.com, ast@kernel.org,
daniel@iogearbox.net, hawk@kernel.org, john.fastabend@gmail.com,
sdf@fomichev.me, jordanrhee@google.com, willemb@google.com,
nktgrg@google.com, maolson@google.com, thostet@google.com,
jacob.e.keller@intel.com, debarghyak@google.com, kees@kernel.org,
bpf@vger.kernel.org, linux-kernel@vger.kernel.org,
przemyslaw.kitszel@intel.com
Subject: Re: [PATCH net-next v7 06/12] gve: simplify reset logic
Date: Fri, 18 Sep 2026 07:57:46 +0000 [thread overview]
Message-ID: <178971826647.22033.15667934166032456970@kernel.org> (raw)
In-Reply-To: <20260916165533.2187434-7-hramamurthy@google.com>
Thank you for your contribution! Sashiko AI review found 7 potential
issue(s) to consider:
Critical: 0 · High: 1 · Medium: 4 (2) · Low: 2
- [High] gve_recover()'s new failure path calls gve_teardown_device()
(e.g. when gve_open() fails on queue-memory allocation), freeing all…
- [Medium] The -ETIME (admin-queue timeout) reset trigger was removed
from the shared helper gve_adminq_configure_flow_rule() and re-added…
- [Medium] gve_mgmnt_intr() now silently discards the management
interrupt whenever DEVICE_RESOURCES_OK is clear.
- [Medium] gve_queues_start()'s `reset:` path returns gve_reset()'s
status instead of the original error, so a successful reset converts a…
- [Medium] Queue-creation failure during reset recovery frees device-
owned ring memory before the hardware reset.
- [Low] The patch removes a synchronous gve_reset() on admin-queue
timeout from the shared flow-rule helper, which fixes a genuine…
- [Low] The commit message uses a `deconfigure_device_resources` failure
as its example of a path that 'preempts its reset with another reset…
Pre-existing issues:
- [Medium] Failed queue setup during reset recovery omits
gve_unreg_xdp_info(), leaking the XDP memory-model reference on DQO…
- [Medium] A service task that already observed GVE_PRIV_FLAGS_DO_RESET
can block on RTNL while a concurrent direct gve_reset() (ethtool/flow-…
--
gve: simplify reset logic
This reworks the gve reset path: recursive resets and resets during
teardown are removed, allocation is split from device setup, and the
hardware reset is now performed before shared resources are freed.
> gve: simplify reset logic
>
> [ ... ]
>
> 2) Removing resets during teardown. This is partly covered by removing
> recursive resets, but the primary goal in this case is to ensure that
> the driver is capable of actually executing a hardware reset if
> something goes wrong with a control plane operation. As it stands, if
> `deconfigure_device_resources` fails, for example, GVE will preempt
> its reset with another reset without actually invoking a hardware
> reset, which could actually help with recovery.
[Severity: Low]
Is the deconfigure_device_resources example accurate? In the baseline that
branch calls gve_trigger_reset(), which is just a wrapper for
gve_adminq_release():
gve_teardown_device_resources()
err = gve_adminq_deconfigure_device_resources(priv);
if (err) {
dev_err(...);
gve_trigger_reset(priv);
}
and gve_adminq_release() does perform the hardware reset and waits for the
device to acknowledge it:
iowrite32be(GVE_DRIVER_STATUS_RESET_MASK, &priv->reg_bar0->driver_status);
while (!(ioread32be(&priv->reg_bar0->device_status)
& GVE_DEVICE_STATUS_DEVICE_IS_RESET))
The path that really recursed is the flow-rule -ETIME case, where
gve_adminq_configure_flow_rule() called gve_reset() from inside teardown.
Could the changelog name that case instead?
> diff --git a/drivers/net/ethernet/google/gve/gve_adminq.c b/drivers/net/ethernet/google/gve/gve_adminq.c
> index a62cb7a921d07..901673d2e2648 100644
> --- a/drivers/net/ethernet/google/gve/gve_adminq.c
> +++ b/drivers/net/ethernet/google/gve/gve_adminq.c
[ ... ]
> @@ -1377,12 +1376,8 @@ gve_adminq_configure_flow_rule(struct gve_priv *priv,
> sizeof(struct gve_adminq_configure_flow_rule),
> flow_rule_cmd);
>
> - if (err == -ETIME) {
> - dev_err(&priv->pdev->dev, "Timeout to configure the flow rule, trigger reset");
> - gve_reset(priv, true);
> - } else if (!err) {
> + if (!err)
> priv->flow_rules_cache.rules_cache_synced = false;
> - }
>
> return err;
> }
[Severity: Medium]
This helper has three callers, but the -ETIME handling is re-added below only
for the add and delete cases. Does the third caller lose reset on timeout?
gve_set_features() /* ethtool -K <dev> ntuple off */
gve_flow_rules_reset()
ops->reset_flow_rules() == gve_adminq_reset_flow_rules()
gve_adminq_configure_flow_rule()
gve_adminq_reset_flow_rules() just forwards the return value:
return gve_adminq_configure_flow_rule(priv, &flow_rule_cmd);
and gve_set_features() does:
err = gve_flow_rules_reset(priv);
if (err)
goto revert_features;
so an admin-queue timeout there no longer starts recovery, while before this
patch it called gve_reset(priv, true). The v3 changelog says "only reset when
failing to program flow rules as ethtool op", and gve_set_features() is such
an ethtool op, so was this call site simply missed?
[Severity: Low]
Removing this gve_reset() also fixes a real recursion: teardown calls
gve_flow_rules_reset(), so an adminq timeout during gve_reset(),
gve_remove() or gve_suspend() re-entered gve_reset() from inside teardown.
Should the patch carry a Fixes: tag for 6f3bc487565d ("gve: Add flow steering
ethtool support")? The trailers currently only have Reviewed-by and
Signed-off-by lines.
> diff --git a/drivers/net/ethernet/google/gve/gve_flow_rule.c b/drivers/net/ethernet/google/gve/gve_flow_rule.c
> index 2c80cda28ef30..fae552f4ad6fb 100644
> --- a/drivers/net/ethernet/google/gve/gve_flow_rule.c
> +++ b/drivers/net/ethernet/google/gve/gve_flow_rule.c
> @@ -278,6 +278,11 @@ int gve_add_flow_rule(struct gve_priv *priv, struct ethtool_rxnfc *cmd)
> goto out;
>
> err = gve_adminq_add_flow_rule(priv, rule, fsp->location);
> + if (err == -ETIME) {
> + dev_err(&priv->pdev->dev,
> + "Timeout to add flow rule, trigger reset.");
> + gve_reset(priv, false);
> + }
>
> out:
> kvfree(rule);
> @@ -290,9 +295,17 @@ int gve_add_flow_rule(struct gve_priv *priv, struct ethtool_rxnfc *cmd)
> int gve_del_flow_rule(struct gve_priv *priv, struct ethtool_rxnfc *cmd)
> {
> struct ethtool_rx_flow_spec *fsp = (struct ethtool_rx_flow_spec *)&cmd->fs;
> + int err;
>
> if (!priv->max_flow_rules)
> return -EOPNOTSUPP;
>
> - return gve_adminq_del_flow_rule(priv, fsp->location);
> + err = gve_adminq_del_flow_rule(priv, fsp->location);
> + if (err == -ETIME) {
> + dev_err(&priv->pdev->dev,
> + "Timeout to delete flow rule, trigger reset.");
> + gve_reset(priv, false);
> + }
> +
> + return err;
> }
> diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c
> index 2fe280cf7e680..82bf2c5fed3f2 100644
> --- a/drivers/net/ethernet/google/gve/gve_main.c
> +++ b/drivers/net/ethernet/google/gve/gve_main.c
[ ... ]
> @@ -270,6 +271,10 @@ static irqreturn_t gve_mgmnt_intr(int irq, void *arg)
> {
> struct gve_priv *priv = arg;
>
> + /* Device resources are not okay; consider the interrupt spurious. */
> + if (!gve_get_device_resources_ok(priv))
> + return IRQ_HANDLED;
> +
> queue_work(priv->gve_wq, &priv->service_task);
> return IRQ_HANDLED;
> }
[Severity: Medium]
Can this drop a device-requested reset?
The mgmt vector is requested in gve_alloc_notify_blocks() during the
allocation phase, while gve_set_device_resources_ok() only runs at the very
end of gve_setup_control_plane_resources(), after several blocking adminq
round trips. Any event arriving in that window, including
GVE_DEVICE_STATUS_RESET_MASK, is acked as handled and thrown away.
The only consumer of that bit is gve_service_task():
u32 status = ioread32be(&priv->reg_bar0->device_status);
gve_handle_status(priv, status);
and it only runs when the service task is queued. On the paths that call
gve_recover() with setup_queues == false (gve_reset(priv, true) from
gve_close(), and gve_resume() when up_before_suspend is false) there is no
queue_work() from gve_queues_start(), so nothing re-samples device_status
after the flag is set again.
Since disable_work()/enable_work() already stop the service task across
reset, and gve_reset() returns early on reset_in_progress, would simply
queueing the work (a no-op while disabled) or re-reading device_status after
gve_set_device_resources_ok() avoid the lost-event window?
[ ... ]
> @@ -1416,10 +1465,11 @@ static int gve_queues_start(struct gve_priv *priv,
> reset:
> if (gve_get_reset_in_progress(priv))
> goto stop_and_free_rings;
> - gve_reset_and_teardown(priv, true);
> - /* if this fails there is nothing we can do so just ignore the return */
> - gve_reset_recovery(priv, false);
> - /* return the original error */
> +
> + /* Attempt to reset. If reset is successful, gve_queues_start was
> + * successful.
> + */
> + err = gve_reset(priv, false);
> return err;
> stop_and_free_rings:
> gve_tx_stop_rings(priv, gve_num_tx_queues(priv));
[Severity: Medium]
Returning gve_reset()'s status here reports success for a queue start that
failed. Can that silently discard a requested configuration?
In gve_queues_start() these two assignments happen only after
gve_register_qpls() succeeds:
priv->header_split_enabled = rx_alloc_cfg->enable_header_split;
priv->rx_cfg.packet_buffer_size = rx_alloc_cfg->packet_buffer_size;
The earlier priv->rx_cfg = *rx_alloc_cfg->qcfg_rx does not carry them,
because gve_rx_get_curr_alloc_cfg() sets cfg->qcfg_rx = &priv->rx_cfg, so an
ethtool rx-buf-len or tcp-data-split change lives only in the temporary
alloc cfg.
If gve_init_rss_config() or gve_register_qpls() fails, we jump to reset, and
gve_reset() -> gve_recover() -> gve_open() -> gve_get_curr_alloc_cfgs()
rebuilds the rings from the stale priv values, while gve_open(),
gve_adjust_config() and gve_set_ringparam() all see 0. Would committing the
requested configuration before entering reset recovery, or propagating the
original error, be preferable?
[Severity: Medium]
The commit message says "shared resources between the device and driver are
not freed until after the hardware reset has completed". Does the
stop_and_free_rings path below meet that guarantee during reset recovery?
gve_create_rings() returns on partial success without cleaning up, for
example TX queues created and RX creation failing:
err = gve_adminq_create_rx_queues(priv, priv->rx_cfg.num_queues);
if (err) {
/* This failure will trigger a reset - no need to clean
* up
*/
return err;
}
With reset_in_progress set by the enclosing gve_reset(), we then take
stop_and_free_rings and call gve_queues_mem_remove(), which dma_free_coherent()s
the ring memory and releases the QPL pages while those queues are still
registered with the device. The hardware reset only happens afterwards in
gve_recover() -> gve_teardown_device() -> gve_reset_device(), whose teardown
adminq commands can block before the reset register write. Could the device
still write into that freed memory?
[Severity: Medium]
This isn't a bug introduced by this patch, but the same stop_and_free_rings
path never calls gve_unreg_xdp_info(), so the XDP memory-model reference on
DQO page pools looks leaked.
gve_reg_xdp_info() registers the pool:
xdp_rxq_info_reg_mem_model(&rx->xdp_rxq, MEM_TYPE_PAGE_POOL,
rx->dqo.page_pool);
and __xdp_reg_mem_model() takes an extra reference:
if (type == MEM_TYPE_PAGE_POOL)
page_pool_use_xdp_mem(allocator, mem_allocator_disconnect, mem);
while gve_rx_free_ring_dqo() only does one page_pool_destroy(). Since
xdp_rxq_info_unreg() is reached only from gve_unreg_xdp_info(), does the pool
and mem-model id stay around after a failed queue start with XDP enabled on
DQO?
[ ... ]
> @@ -2514,30 +2554,7 @@ static int gve_init_priv(struct gve_priv *priv)
> return 0;
> }
>
> -static void gve_teardown_priv_resources(struct gve_priv *priv)
> -{
> - gve_teardown_device_resources(priv);
> - gve_adminq_free(priv);
> - bitmap_free(priv->xsk_pools);
> - priv->xsk_pools = NULL;
> -}
> -
> -static void gve_trigger_reset(struct gve_priv *priv)
> -{
> - /* Reset the device by releasing the AQ */
> - gve_adminq_release(priv);
> -}
> -
> -static void gve_reset_and_teardown(struct gve_priv *priv, bool was_up)
> -{
> - gve_trigger_reset(priv);
> - /* With the reset having already happened, close cannot fail */
> - if (was_up)
> - gve_close(priv->dev);
> - gve_teardown_priv_resources(priv);
> -}
> -
> -static int gve_reset_recovery(struct gve_priv *priv, bool was_up)
> +static int gve_recover(struct gve_priv *priv, bool setup_queues)
> {
> int err;
>
> @@ -2545,62 +2562,67 @@ static int gve_reset_recovery(struct gve_priv *priv, bool was_up)
> if (err) {
> dev_err(&priv->pdev->dev,
> "Failed to alloc admin queue: err=%d\n", err);
> - goto err;
> + goto teardown_device;
> }
>
> err = gve_adminq_verify_driver_compatibility(priv);
> if (err) {
> dev_err(&priv->pdev->dev,
> "Could not verify driver compatibility: err=%d\n", err);
> - goto err_free_adminq;
> + goto teardown_device;
> }
>
> err = gve_setup_device(priv);
> if (err)
> - goto err_free_adminq;
> - if (was_up) {
> + goto teardown_device;
> +
> + if (setup_queues) {
> err = gve_open(priv->dev);
> if (err)
> - return err;
> + goto teardown_device;
> }
> +
> return 0;
>
> -err_free_adminq:
> - gve_adminq_free(priv);
> -err:
> - dev_err(&priv->pdev->dev, "Reset failed! !!! DISABLING ALL QUEUES !!!\n");
> - gve_turndown(priv);
> +teardown_device:
> + dev_err(&priv->pdev->dev, "Recover failed! !!! DISABLING ALL QUEUES !!!\n");
> + gve_teardown_device(priv);
> return err;
> }
[Severity: High]
Routing a gve_open() failure into gve_teardown_device() frees the whole
control plane while the netdev stays registered and administratively
running. Can that be dereferenced afterwards?
gve_teardown_device() -> gve_free_control_plane_resources() calls
gve_free_rss_config_cache():
kfree(rss_config->hash_key);
kfree(rss_config->hash_lut);
memset(rss_config, 0, sizeof(*rss_config));
and gve_free_notify_blocks(), which leaves priv->ntfy_blocks NULL, while
priv->cache_rss_config, priv->rss_key_size and priv->rss_lut_size (set in
gve_init_priv()) are untouched and nothing closes the interface.
Only gve_open() got the new resources_ok gate, so ETHTOOL_GRSSH still
reaches gve_get_rxfh() -> gve_get_rss_config_cache():
memcpy(rxfh->key, rss_config->hash_key, priv->rss_key_size);
with hash_key == NULL, and ETHTOOL_GRSSH is one of the commands that skips
the ns_capable(net->user_ns, CAP_NET_ADMIN) check in net/ethtool/ioctl.c.
An ethtool channel change is a second route: gve_adjust_queues() still sees
netif_running(priv->dev) true, so gve_adjust_config() -> gve_queues_start()
-> gve_tx_start_rings() -> gve_tx_add_to_block() runs:
struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
struct gve_tx_ring *tx = &priv->tx[queue_idx];
block->tx = tx;
on a NULL array. Should these entry points also be rejected (or the netdev
detached) while control-plane resources are gone?
>
> -int gve_reset(struct gve_priv *priv, bool attempt_teardown)
> +int gve_reset(struct gve_priv *priv, bool skip_queue_setup)
> {
> bool was_up = netif_running(priv->dev);
> int err;
>
> + if (gve_get_reset_in_progress(priv))
> + return 0;
> +
> dev_info(&priv->pdev->dev, "Performing reset\n");
> gve_clear_do_reset(priv);
> gve_set_reset_in_progress(priv);
[Severity: Medium]
This is a pre-existing issue, but the new early return only covers
overlapping resets, not a stale pending request. gve_handle_reset() samples
the bit before taking the locks and never rechecks it:
if (gve_get_do_reset(priv)) {
rtnl_lock();
netdev_lock(priv->dev);
gve_reset(priv, false);
If a direct gve_reset() from the ethtool or flow-rule path completes while
the worker is blocked on RTNL, it clears both do_reset and
reset_in_progress (and disable_work() does not wait for an already running
worker), so the worker performs a second full reset once it gets the locks.
Would rechecking do_reset after acquiring the locks be reasonable?
>
> - /* If we aren't attempting to teardown normally, just go turndown and
> - * reset right away.
> - */
> - if (!attempt_teardown) {
> + if (was_up) {
> gve_turndown(priv);
> - gve_reset_and_teardown(priv, was_up);
> - } else {
> - /* Otherwise attempt to close normally */
> - if (was_up) {
> - err = gve_close(priv->dev);
> - /* If that fails reset as we did above */
> - if (err)
> - gve_reset_and_teardown(priv, was_up);
> + if (gve_get_device_rings_ok(priv)) {
> + gve_clear_device_rings_ok(priv);
> + gve_destroy_rings(priv);
> + gve_unregister_qpls(priv);
> }
> - /* Clean up any remaining resources */
> - gve_teardown_priv_resources(priv);
> }
>
> - /* Set it all back up */
> - err = gve_reset_recovery(priv, was_up);
> + disable_work(&priv->service_task);
> + gve_reset_device(priv);
> + gve_queues_stop(priv);
> + gve_queues_mem_remove(priv);
> + gve_free_control_plane_resources(priv);
> +
> + enable_work(&priv->service_task);
> + err = gve_recover(priv, was_up && !skip_queue_setup);
> + if (err)
> + dev_info(&priv->pdev->dev,
> + "Failed to recover in reset: %d\n", err);
> +
> gve_clear_reset_in_progress(priv);
> priv->reset_cnt++;
> priv->interface_up_cnt = 0;
[ ... ]
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260916165533.2187434-1-hramamurthy%40google.com
next prev parent reply other threads:[~2026-09-18 7:57 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-16 16:55 [PATCH net-next v7 00/12] gve: AdminQ mode related refactors Harshitha Ramamurthy
2026-09-16 16:55 ` [PATCH net-next v7 01/12] gve: add struct gve_device_info to hold device properties Harshitha Ramamurthy
2026-09-18 7:57 ` netdev-bot+sashiko
2026-09-16 16:55 ` [PATCH net-next v7 02/12] gve: introduce control plane operations structure Harshitha Ramamurthy
2026-09-16 16:55 ` [PATCH net-next v7 03/12] gve: introduce ctrl ops to set vectors and Qs Harshitha Ramamurthy
2026-09-16 16:55 ` [PATCH net-next v7 04/12] gve: introduce gve_adminq_get_device_properties() Harshitha Ramamurthy
2026-09-16 16:55 ` [PATCH net-next v7 05/12] gve: refactor gve_init_priv for reset path Harshitha Ramamurthy
2026-09-18 7:57 ` netdev-bot+sashiko
2026-09-16 16:55 ` [PATCH net-next v7 06/12] gve: simplify reset logic Harshitha Ramamurthy
2026-09-18 7:57 ` netdev-bot+sashiko [this message]
2026-09-19 1:28 ` Joshua Washington
2026-09-16 16:55 ` [PATCH net-next v7 07/12] gve: add gve_ctrl_ops for gve initialization/teardown sequences Harshitha Ramamurthy
2026-09-16 16:55 ` [PATCH net-next v7 08/12] gve: split up notify block allocation and setup paths Harshitha Ramamurthy
2026-09-18 7:57 ` netdev-bot+sashiko
2026-09-19 1:49 ` Joshua Washington
2026-09-16 16:55 ` [PATCH net-next v7 09/12] gve: introduce new methods to handle IRQ doorbells Harshitha Ramamurthy
2026-09-18 7:57 ` netdev-bot+sashiko
2026-09-16 16:55 ` [PATCH net-next v7 10/12] gve: setup and teardown management interrupts Harshitha Ramamurthy
2026-09-16 16:55 ` [PATCH net-next v7 11/12] gve: add ctrl ops for queue operations Harshitha Ramamurthy
2026-09-18 7:57 ` netdev-bot+sashiko
2026-09-16 16:55 ` [PATCH net-next v7 12/12] gve: add link status/speed ctrl ops Harshitha Ramamurthy
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=178971826647.22033.15667934166032456970@kernel.org \
--to=netdev-bot+sashiko@kernel.org \
--cc=andrew+netdev@lunn.ch \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=davem@davemloft.net \
--cc=debarghyak@google.com \
--cc=edumazet@google.com \
--cc=hawk@kernel.org \
--cc=hramamurthy@google.com \
--cc=jacob.e.keller@intel.com \
--cc=john.fastabend@gmail.com \
--cc=jordanrhee@google.com \
--cc=joshwash@google.com \
--cc=kees@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=maolson@google.com \
--cc=netdev@vger.kernel.org \
--cc=nktgrg@google.com \
--cc=pabeni@redhat.com \
--cc=przemyslaw.kitszel@intel.com \
--cc=sdf@fomichev.me \
--cc=thostet@google.com \
--cc=willemb@google.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®