From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 130354C6C for ; Sat, 7 Feb 2026 17:43:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770486222; cv=none; b=ilnrf0ZXnut3EQ5zV27iLGWWvYJ4wkVt8OHik8MOpbo56g+KnkGV5UvgPf6TH6evtnQvXhWzMmOKbDCHLszUwu2IaBdspf1PLZpvewhC50/d+MROT4LJEfLkqTHy2iuMhN3hq549Pgu9AQowykN3G1ZDOIZvQ+7yW0SsZ/aJunQ= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770486222; c=relaxed/simple; bh=R1USufZvyi9WYSOngvgp/ZOrKBafboTHm0kmHbkiE0o=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=C4HpG4L/5E4piUXDSRSwjOfyDyTXeVECK1077T51jQMt3/zvB33r8isvo8XgYvoblzonS8Nfmvfoo1JNaeJj0sHyE9vAJihJ1eWtCUPmpul8m8Py4Fl18LEqY5HkWh91R+dTZNy+TsZSv4Pm7LA9XBQ3u4b8aYDUo73WtUQkpEg= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=L+Qba+E5; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="L+Qba+E5" Received: by smtp.kernel.org (Postfix) with ESMTPSA id CDDE4C116D0; Sat, 7 Feb 2026 17:43:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1770486221; bh=R1USufZvyi9WYSOngvgp/ZOrKBafboTHm0kmHbkiE0o=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=L+Qba+E52yrm1Xf60R0n1+uCDtklvJwjr/QVe6v1P1YdlY2zU5AWcj1iOv/LsF7Yv 96WSEXb5gPO/Y2qiY5PjbP0wSy1CBlsaKJ8GGNDReRpltS7NyaII69qwPNY2GtD0sX OnQvNESvNLK1lCb4qrYULHWlAcFWk+Y8VZhEObsJKac6EsbzKfCfXnjFXekdr2FVCy dQosdZmSO5+KueCctQTZ0BOhl7H+feVaYqP+CXnpMy3/ObeOU9jYNAD/8MxNQ4hbqE dgmyzL4HC5aZhc7fWzjcfKEi3bNJu0SceZMKvJaOH4IDnSqbPn61IOqsYRAqcxoRYg eiOGhLIdph4Aw== From: Sasha Levin To: stable@vger.kernel.org Cc: Debarghya Kundu , Joshua Washington , Harshitha Ramamurthy , Jacob Keller , Jakub Kicinski , Sasha Levin Subject: [PATCH 6.1.y] gve: Fix stats report corruption on queue count change Date: Sat, 7 Feb 2026 12:43:39 -0500 Message-ID: <20260207174339.471643-1-sashal@kernel.org> X-Mailer: git-send-email 2.51.0 In-Reply-To: <2026020743-case-starter-eeef@gregkh> References: <2026020743-case-starter-eeef@gregkh> Precedence: bulk X-Mailing-List: stable@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: Debarghya Kundu [ Upstream commit 7b9ebcce0296e104a0d82a6b09d68564806158ff ] The driver and the NIC share a region in memory for stats reporting. The NIC calculates its offset into this region based on the total size of the stats region and the size of the NIC's stats. When the number of queues is changed, the driver's stats region is resized. If the queue count is increased, the NIC can write past the end of the allocated stats region, causing memory corruption. If the queue count is decreased, there is a gap between the driver and NIC stats, leading to incorrect stats reporting. This change fixes the issue by allocating stats region with maximum size, and the offset calculation for NIC stats is changed to match with the calculation of the NIC. Cc: stable@vger.kernel.org Fixes: 24aeb56f2d38 ("gve: Add Gvnic stats AQ command and ethtool show/set-priv-flags.") Signed-off-by: Debarghya Kundu Reviewed-by: Joshua Washington Signed-off-by: Harshitha Ramamurthy Reviewed-by: Jacob Keller Link: https://patch.msgid.link/20260202193925.3106272-2-hramamurthy@google.com Signed-off-by: Jakub Kicinski [ gve_num_tx_queues() => priv->tx_cfg.num_queues and no stopped queues ] Signed-off-by: Sasha Levin --- drivers/net/ethernet/google/gve/gve_ethtool.c | 42 +++++++++++++------ drivers/net/ethernet/google/gve/gve_main.c | 4 +- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/google/gve/gve_ethtool.c b/drivers/net/ethernet/google/gve/gve_ethtool.c index 7e60139f8ac57..86b26fc919434 100644 --- a/drivers/net/ethernet/google/gve/gve_ethtool.c +++ b/drivers/net/ethernet/google/gve/gve_ethtool.c @@ -145,7 +145,8 @@ gve_get_ethtool_stats(struct net_device *netdev, tmp_tx_pkts, tmp_tx_bytes; u64 rx_buf_alloc_fail, rx_desc_err_dropped_pkt, rx_pkts, rx_skb_alloc_fail, rx_bytes, tx_pkts, tx_bytes, tx_dropped; - int stats_idx, base_stats_idx, max_stats_idx; + int rx_base_stats_idx, max_rx_stats_idx, max_tx_stats_idx; + int stats_idx, stats_region_len, nic_stats_len; struct stats *report_stats; int *rx_qid_to_stats_idx; int *tx_qid_to_stats_idx; @@ -230,14 +231,33 @@ gve_get_ethtool_stats(struct net_device *netdev, data[i++] = priv->stats_report_trigger_cnt; i = GVE_MAIN_STATS_LEN; - /* For rx cross-reporting stats, start from nic rx stats in report */ - base_stats_idx = GVE_TX_STATS_REPORT_NUM * priv->tx_cfg.num_queues + - GVE_RX_STATS_REPORT_NUM * priv->rx_cfg.num_queues; - max_stats_idx = NIC_RX_STATS_REPORT_NUM * priv->rx_cfg.num_queues + - base_stats_idx; + rx_base_stats_idx = 0; + max_rx_stats_idx = 0; + max_tx_stats_idx = 0; + stats_region_len = priv->stats_report_len - + sizeof(struct gve_stats_report); + nic_stats_len = (NIC_RX_STATS_REPORT_NUM * priv->rx_cfg.num_queues + + NIC_TX_STATS_REPORT_NUM * priv->tx_cfg.num_queues) * + sizeof(struct stats); + if (unlikely((stats_region_len - + nic_stats_len) % sizeof(struct stats))) { + net_err_ratelimited("Starting index of NIC stats should be multiple of stats size"); + } else { + /* For rx cross-reporting stats, + * start from nic rx stats in report + */ + rx_base_stats_idx = (stats_region_len - nic_stats_len) / + sizeof(struct stats); + max_rx_stats_idx = NIC_RX_STATS_REPORT_NUM * + priv->rx_cfg.num_queues + + rx_base_stats_idx; + max_tx_stats_idx = NIC_TX_STATS_REPORT_NUM * + priv->tx_cfg.num_queues + + max_rx_stats_idx; + } /* Preprocess the stats report for rx, map queue id to start index */ skip_nic_stats = false; - for (stats_idx = base_stats_idx; stats_idx < max_stats_idx; + for (stats_idx = rx_base_stats_idx; stats_idx < max_rx_stats_idx; stats_idx += NIC_RX_STATS_REPORT_NUM) { u32 stat_name = be32_to_cpu(report_stats[stats_idx].stat_name); u32 queue_id = be32_to_cpu(report_stats[stats_idx].queue_id); @@ -294,13 +314,9 @@ gve_get_ethtool_stats(struct net_device *netdev, i += priv->rx_cfg.num_queues * NUM_GVE_RX_CNTS; } - /* For tx cross-reporting stats, start from nic tx stats in report */ - base_stats_idx = max_stats_idx; - max_stats_idx = NIC_TX_STATS_REPORT_NUM * priv->tx_cfg.num_queues + - max_stats_idx; - /* Preprocess the stats report for tx, map queue id to start index */ skip_nic_stats = false; - for (stats_idx = base_stats_idx; stats_idx < max_stats_idx; + /* NIC TX stats start right after NIC RX stats */ + for (stats_idx = max_rx_stats_idx; stats_idx < max_tx_stats_idx; stats_idx += NIC_TX_STATS_REPORT_NUM) { u32 stat_name = be32_to_cpu(report_stats[stats_idx].stat_name); u32 queue_id = be32_to_cpu(report_stats[stats_idx].queue_id); diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c index 2e8b01b3ee444..963c76e4aa5d0 100644 --- a/drivers/net/ethernet/google/gve/gve_main.c +++ b/drivers/net/ethernet/google/gve/gve_main.c @@ -135,9 +135,9 @@ static int gve_alloc_stats_report(struct gve_priv *priv) int tx_stats_num, rx_stats_num; tx_stats_num = (GVE_TX_STATS_REPORT_NUM + NIC_TX_STATS_REPORT_NUM) * - priv->tx_cfg.num_queues; + priv->tx_cfg.max_queues; rx_stats_num = (GVE_RX_STATS_REPORT_NUM + NIC_RX_STATS_REPORT_NUM) * - priv->rx_cfg.num_queues; + priv->rx_cfg.max_queues; priv->stats_report_len = struct_size(priv->stats_report, stats, size_add(tx_stats_num, rx_stats_num)); priv->stats_report = -- 2.51.0