From: Harshitha Ramamurthy <hramamurthy@google.com>
To: netdev@vger.kernel.org
Cc: joshwash@google.com, hramamurthy@google.com,
andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@kernel.org,
kuba@kernel.org, pabeni@redhat.com, jordanrhee@google.com,
willemb@google.com, przemyslaw.kitszel@intel.com,
nktgrg@google.com, maolson@google.com, jacob.e.keller@intel.com,
pkaligineedi@google.com, yangchun@google.com,
patricion@google.com, awogbemila@google.com,
stable@vger.kernel.org, linux-kernel@vger.kernel.org,
Debarghya Kundu <debarghyak@google.com>,
Pin-yen Lin <treapking@google.com>
Subject: [PATCH net v3 2/4] gve: Fix backward stats when interface goes down or configuration is adjusted
Date: Fri, 23 Oct 2026 20:47:04 +0000 [thread overview]
Message-ID: <20261023204706.3112215-3-hramamurthy@google.com> (raw)
In-Reply-To: <20261023204706.3112215-1-hramamurthy@google.com>
From: Debarghya Kundu <debarghyak@google.com>
gve_get_base_stats() sets all the stats to 0, so the stats go backwards
when interface goes down or configuration is adjusted.
This issue was discovered and actually triggered by the
drivers/net/stats.py selftest (check_down test case). Bringing down the
interface caused statistics counters to reset to 0, triggering selftest
assertion failures because netdevice stats must not go backwards.
Fix this by persisting baseline stats across queue teardown in
gve_queues_mem_remove() and single-queue stop in gve_rx_queue_stop().
This change was tested using the DQO RDA queue format.
Cc: stable@vger.kernel.org
Fixes: 2e5e0932dff5 ("gve: add support for basic queue stats")
Signed-off-by: Debarghya Kundu <debarghyak@google.com>
Co-developed-by: Pin-yen Lin <treapking@google.com>
Signed-off-by: Pin-yen Lin <treapking@google.com>
Signed-off-by: Harshitha Ramamurthy <hramamurthy@google.com>
---
Changes in v3:
- Drop u64_stats_sync for the base stats and use spinlock to protect
them instead
- Save base stats in gve_queues_mem_remove() instead of gve_close()
- Save base stats in gve_rx_queue_stop() for single-queue restarts
- Drop unused rx_dropped and tx_dropped accumulation in gve_add_base_stats()
- Refined the commit message
Changes in v2:
- Add a NULL pointer check in gve_get_ring_err_stats() (Sashiko)
- Use local variable to prevent inflates from u64_stats_fetch_retry()
(Sashiko)
- Add u64_stats_fetch/begin to protect base stats (Sashiko)
drivers/net/ethernet/google/gve/gve.h | 6 ++
drivers/net/ethernet/google/gve/gve_main.c | 83 +++++++++++++++++++---
2 files changed, 81 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/google/gve/gve.h b/drivers/net/ethernet/google/gve/gve.h
index 104468c2c07f..37070bc14c87 100644
--- a/drivers/net/ethernet/google/gve/gve.h
+++ b/drivers/net/ethernet/google/gve/gve.h
@@ -871,6 +871,10 @@ struct gve_ctrl_ops {
int (*report_link_speed)(struct gve_priv *priv);
};
+struct gve_ring_err_stats {
+ u64 rx_alloc_fails;
+};
+
struct gve_priv {
struct net_device *dev;
struct gve_tx_ring *tx; /* array of tx_cfg.num_queues */
@@ -962,6 +966,8 @@ struct gve_priv {
unsigned long service_task_flags;
unsigned long state_flags;
+ struct gve_ring_err_stats base_ring_err_stats;
+ struct rtnl_link_stats64 base_net_stats;
struct gve_stats_report *stats_report;
u64 stats_report_len;
dma_addr_t stats_report_bus; /* dma address for the stats report */
diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c
index 26fdd22644f4..52c152a986eb 100644
--- a/drivers/net/ethernet/google/gve/gve_main.c
+++ b/drivers/net/ethernet/google/gve/gve_main.c
@@ -61,15 +61,25 @@ static netdev_tx_t gve_start_xmit(struct sk_buff *skb, struct net_device *dev)
return gve_tx_dqo(skb, dev);
}
-static void gve_get_stats(struct net_device *dev, struct rtnl_link_stats64 *s)
+static void gve_add_base_stats(struct gve_priv *priv,
+ struct rtnl_link_stats64 *s)
+{
+ struct rtnl_link_stats64 *base_stats = &priv->base_net_stats;
+
+ s->rx_packets += base_stats->rx_packets;
+ s->rx_bytes += base_stats->rx_bytes;
+ s->tx_packets += base_stats->tx_packets;
+ s->tx_bytes += base_stats->tx_bytes;
+}
+
+static void gve_get_ring_stats(struct gve_priv *priv,
+ struct rtnl_link_stats64 *s)
{
- struct gve_priv *priv = netdev_priv(dev);
unsigned int start;
u64 packets, bytes;
int num_tx_queues;
int ring;
- spin_lock_bh(&priv->stats_lock);
num_tx_queues = gve_num_tx_queues(priv);
if (priv->rx) {
for (ring = 0; ring < priv->rx_cfg.num_queues; ring++) {
@@ -97,6 +107,38 @@ static void gve_get_stats(struct net_device *dev, struct rtnl_link_stats64 *s)
s->tx_bytes += bytes;
}
}
+}
+
+static void gve_get_ring_err_stats(struct gve_priv *priv,
+ struct gve_ring_err_stats *err_stats)
+{
+ int ring;
+
+ if (!priv->rx)
+ return;
+
+ for (ring = 0; ring < priv->rx_cfg.num_queues; ring++) {
+ struct gve_rx_ring *rx = &priv->rx[ring];
+ unsigned int start;
+ u64 rx_alloc_fails;
+
+ do {
+ start = u64_stats_fetch_begin(&rx->statss);
+ rx_alloc_fails = rx->rx_skb_alloc_fail +
+ rx->rx_buf_alloc_fail;
+ } while (u64_stats_fetch_retry(&rx->statss, start));
+
+ err_stats->rx_alloc_fails += rx_alloc_fails;
+ }
+}
+
+static void gve_get_stats(struct net_device *dev, struct rtnl_link_stats64 *s)
+{
+ struct gve_priv *priv = netdev_priv(dev);
+
+ spin_lock_bh(&priv->stats_lock);
+ gve_get_ring_stats(priv, s);
+ gve_add_base_stats(priv, s);
spin_unlock_bh(&priv->stats_lock);
}
@@ -646,6 +688,9 @@ static void gve_queues_mem_remove(struct gve_priv *priv)
gve_get_curr_alloc_cfgs(priv, &tx_alloc_cfg, &rx_alloc_cfg);
spin_lock_bh(&priv->stats_lock);
+ gve_get_ring_stats(priv, &priv->base_net_stats);
+ gve_get_ring_err_stats(priv, &priv->base_ring_err_stats);
+
priv->tx = NULL;
priv->rx = NULL;
spin_unlock_bh(&priv->stats_lock);
@@ -2689,8 +2734,20 @@ static int gve_rx_queue_stop(struct net_device *dev, void *per_q_mem, int idx)
gve_turnup_and_check_status(priv);
gve_per_q_mem = (struct gve_rx_ring *)per_q_mem;
+ spin_lock_bh(&priv->stats_lock);
+ priv->base_net_stats.rx_packets += priv->rx[idx].rpackets;
+ priv->base_net_stats.rx_bytes += priv->rx[idx].rbytes;
+ priv->base_ring_err_stats.rx_alloc_fails +=
+ priv->rx[idx].rx_skb_alloc_fail +
+ priv->rx[idx].rx_buf_alloc_fail;
*gve_per_q_mem = priv->rx[idx];
memset(&priv->rx[idx], 0, sizeof(priv->rx[idx]));
+ spin_unlock_bh(&priv->stats_lock);
+
+ gve_per_q_mem->rpackets = 0;
+ gve_per_q_mem->rbytes = 0;
+ gve_per_q_mem->rx_skb_alloc_fail = 0;
+ gve_per_q_mem->rx_buf_alloc_fail = 0;
return 0;
}
@@ -2844,12 +2901,22 @@ static void gve_get_base_stats(struct net_device *dev,
struct netdev_queue_stats_rx *rx,
struct netdev_queue_stats_tx *tx)
{
- rx->packets = 0;
- rx->bytes = 0;
- rx->alloc_fail = 0;
+ const struct gve_ring_err_stats *base_err_stats;
+ const struct rtnl_link_stats64 *base_stats;
+ struct gve_priv *priv;
+
+ priv = netdev_priv(dev);
+ base_stats = &priv->base_net_stats;
+ base_err_stats = &priv->base_ring_err_stats;
+
+ spin_lock_bh(&priv->stats_lock);
+ rx->packets = base_stats->rx_packets;
+ rx->bytes = base_stats->rx_bytes;
+ rx->alloc_fail = base_err_stats->rx_alloc_fails;
- tx->packets = 0;
- tx->bytes = 0;
+ tx->packets = base_stats->tx_packets;
+ tx->bytes = base_stats->tx_bytes;
+ spin_unlock_bh(&priv->stats_lock);
}
static const struct netdev_stat_ops gve_stat_ops = {
--
2.56.0.257.gf7497c7d27-goog
next prev parent reply other threads:[~2026-10-23 20:47 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-23 20:47 [PATCH net v3 0/4] gve: Fixes for issues discovered via net selftests and Sashiko Harshitha Ramamurthy
2026-10-23 20:47 ` [PATCH net v3 1/4] gve: Fix race between stats query and queue reconfig Harshitha Ramamurthy
2026-10-23 20:47 ` Harshitha Ramamurthy [this message]
2026-10-23 20:47 ` [PATCH net v3 3/4] gve: Block invalid ring sizes when device options are 0 Harshitha Ramamurthy
2026-10-23 20:47 ` [PATCH net v3 4/4] gve: Fix link flap after ethtool 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=20261023204706.3112215-3-hramamurthy@google.com \
--to=hramamurthy@google.com \
--cc=andrew+netdev@lunn.ch \
--cc=awogbemila@google.com \
--cc=davem@davemloft.net \
--cc=debarghyak@google.com \
--cc=edumazet@kernel.org \
--cc=jacob.e.keller@intel.com \
--cc=jordanrhee@google.com \
--cc=joshwash@google.com \
--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=patricion@google.com \
--cc=pkaligineedi@google.com \
--cc=przemyslaw.kitszel@intel.com \
--cc=stable@vger.kernel.org \
--cc=treapking@google.com \
--cc=willemb@google.com \
--cc=yangchun@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®