From nobody Fri Oct 2 10:08:53 2026 Received: from out162-62-57-87.mail.qq.com (out162-62-57-87.mail.qq.com [162.62.57.87]) (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 E5E4A392C29; Sun, 2 Aug 2026 15:46:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=162.62.57.87 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785685595; cv=none; b=Mlza6a8yeRxGrUnqua0h4EVlAL04f8hjbuC2LuxSOpcxB6Uj6pm2t6xl0mSVmP45/S2I/W7OcOHV5LGfp3lsfL2rZeNucT90KteyBJePEG1A6Ie0o+no9/Tl/wKNtCknQkaEIvLjq1XaTlPcdD6f7toDO+fKiVSN7UItAoFFYRA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785685595; c=relaxed/simple; bh=nQSJrDA/fmQdX1iZpaXtdzjlm5bLhXj9XQZqYVDT85Q=; h=Message-ID:From:To:Cc:Subject:Date:In-Reply-To:References: MIME-Version; b=VYf69gcVczbNXSUxv+jv0Ak+SHQskGnuJc8Doyp1tKaxAYnAwAKZytWiNiTgnoR0MRcMV9sFdTEHyDdO+BJqVU39TdCbyz9YCzpPAvOvJ2oL1+WMUwKGw/5SRti1vkdrAPCyKW/+CEYhE7XrQEAvUbAZ+zwMC5ExSAZmdBQ13/c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=cyyself.name; spf=pass smtp.mailfrom=cyyself.name; dkim=pass (1024-bit key) header.d=qq.com header.i=@qq.com header.b=wQ3SpEkk; arc=none smtp.client-ip=162.62.57.87 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=cyyself.name Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=cyyself.name Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=qq.com header.i=@qq.com header.b="wQ3SpEkk" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qq.com; s=s201512; t=1785685579; bh=WPlcpJoLTcSVOaV+8nxaAkEHLcTeJTsMz0suLveR/fA=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=wQ3SpEkk05/dk4AZ2JDNTlFvcoAaS5vNxOwi3MOp9LECcJrbkM3VZ/ZDOe0ERR5YC qPLGY1NI8y5v1TpqhPxjKebNKbbIc8Km1a8smxNOSW3k5Q+vCo3E9Rkjfp4q3iyw3/ 27kyI0w4Uy9zLo8LP8+8Bwxrw1HpiL4vlX3STlM0= Received: from halo.lan ([240e:379:2238:cc00:262b:8ebc:c000:80a0]) by newxmesmtplogicsvrszc56-0.qq.com (NewEsmtp) with SMTP id B839CE89; Sun, 02 Aug 2026 23:46:03 +0800 X-QQ-mid: xmsmtpt1785685563td6zh1djc Message-ID: X-QQ-XMAILINFO: MllZffuBkEb5a60sLct7sviH/uCQPly28gt+lxpw9k7QY4hZCCpkRSKQagg/gn kx8OmEyoVAAayqY5GsXo/jDI8Ittpmff+H38A/aBJ2004Un/B2kwUJViVa+uVBOICitpkpQcZ1ap HIMUQANo5o+Cj80FOaIZJmFZg4M2KsjzH+F//gqdiO54IAzOsREvuhw1Sp7YPMAkRUofpnxVxCYx 93YxA6ROMAbG/I8dngZDsyXCThVmP8eSv/Gc2CrvgOJ+sU1jUeT8OwhRCoyyy12rWvYC8GR1PJRq mq/I600Um5w5XV4GzPF9CtR4HGjT6hyL4tXiZLsuTHWfPpOsOYdoLbmUL0K+CGLfe9QGghUj41WZ sOazhbMTGuQ0KrJ73Oofckfa3KuR2bcdXZjwZUDxgzWHtst7ybLGdTVOmVe2UsrvbqcsOAfiTBFI H/xCI1eCLnhem3qN7wY+bRwnTsq8QCYJ53xHS0KnmvRa4LiUcflPqhNrNrOXlOPJfs3gL2A/J1Ly 1jI+wkddORAxt7wbUy/AwRo/nT2MwmXvnux36EPL6RXDnKlrGsam/kIo7+jfT769H5ALaN6bT1pf rTrzNorKqiWmoUcWcLI1b87hkAJ+z2nnKmj8by2eWxPqZ4W6dlbmLaHWvhHscCLI4+ipZK6jiv33 WT13+ZHnucahLOIlp/X0uUjUZ8O8EiDBGRO6aSNXfAEpggKDz6QzQpeIF1/Ss1kwsbtZIPVTKOGh uOF7w3v9QE7i1KL/NKg3jsorBYE5a8x7lTKQ16IJngHdTRhqess7nq7YQL85iH8G7lA+THfkN16H 19IJe7+iRYFSRMIfDchDH6F7C/xObT31BPwTUVGbA2g554HZ/R5B05tFeSBxnMLUnXoeuk5f68Ns ShBak8vn8VWeHrNLXzPOw1vc9ohfHKka3Hul7a/fVQxcSPAhJ+XvoK+Bl9S+OqanNYPbs4NTSWdm Knn0W9hcQ+kWwssekGDPIDEpoxZde41Vf1xw3vYFvAYqCI2t8UZKPuS4zimEWuKPA7niMiOarMVt n/xzNB5RdmP6Sh+Hjri1n1eaa2rJYhZXMqXdDjQvLDk8RoVKNZj5jv4AzeoHyvwgHYeCubLhlPwR 4gybf/icBXKQSnlowdXpFZg/QBAg== X-QQ-XMRINFO: NS+P29fieYNwqS3WCnRCOn9D1NpZuCnCRA== From: Yangyu Chen To: Sukhdeep Singh , Andrew Lunn , "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni Cc: Mina Almasry , Jesper Dangaard Brouer , Richard Cochran , Lino Sanfilippo , Igor Russkikh , Simon Horman , netdev@vger.kernel.org, bpf@vger.kernel.org, linux-kernel@vger.kernel.org, stable@vger.kernel.org, Yangyu Chen Subject: [PATCH net 1/2] net: atlantic: free stranded TX buffers on ring deinit Date: Sun, 2 Aug 2026 23:46:00 +0800 X-OQ-MSGID: <20260802154600.39228-1-cyy@cyyself.name> X-Mailer: git-send-email 2.47.3 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" aq_vec_deinit() drains the TX rings with a single aq_ring_tx_clean() call, which frees at most AQ_CFG_TX_CLEAN_BUDGET (256) descriptors and stops at hw_head, which no longer moves once aq_vec_stop() has stopped the hardware and NAPI. Completed descriptors beyond the budget and everything still posted in [hw_head, sw_tail) keep their skb or xdp_frame when the interface goes down: aq_vec_ring_free() then frees the buffer ring and the references are lost for good. Today this is a silent memory leak on every interface down under TX/XDP_TX load. With the conversion of the RX path to page_pool posted for net-next it becomes much more visible: XDP_TX frames carry fragment references on the RX ring's page_pool, so a single stranded frame keeps the pool's inflight count above zero forever. page_pool_destroy() then never completes, the pool is leaked together with its pages, and "page_pool_release_retry() stalled pool shutdown" is warned every 60 seconds from that point on, on every ifdown, XDP detach or ring resize under XDP_TX load. Bring back aq_ring_tx_deinit() as it was before the removal and use it for teardown again, with one extension: TX rings can hold xdp_frames nowadays, so release those too. They are returned with xdp_return_frame() since this runs in process context. Fixes: eb36bedf28be ("net: aquantia: remove function aq_ring_tx_deinit") Cc: stable@vger.kernel.org # v4.11+ Reviewed-by: Sukhdeep Singh Assisted-by: Claude:claude-fable-5 Signed-off-by: Yangyu Chen Acked-by: Mina Almasry Reviewed-by tags, and each carries a Fixes tag and a Cc: stable with --- Notes: Without this fix, converting the RX path to page_pool (posted separately for net-next) turns the stranded XDP_TX frames into leaked p= age_pool fragments, so page_pool_destroy() can never drain and the shutdown stalls forever. =20 Reproduced on an AQC100 with this patch dropped from the series (i.e. page_pool applied without the tx-deinit fix): =20 # reflect received frames back out through XDP_TX xdp-bench tx enp99s0 # or any trivial XDP_TX prog # from a peer on the same link, flood RX so frames are in flight, then ip link set enp99s0 down =20 The pool is destroyed with frames still stranded on the TX ring, and page_pool_release_retry() warns every 60s with the same id and inflight count and a growing age, indefinitely: =20 [161110.753385] page_pool_release_retry() stalled pool shutdown: id 3= 61, 12 inflight 60 sec [161171.170756] page_pool_release_retry() stalled pool shutdown: id 3= 61, 12 inflight 120 sec [161231.588685] page_pool_release_retry() stalled pool shutdown: id 3= 61, 12 inflight 181 sec [161292.005886] page_pool_release_retry() stalled pool shutdown: id 3= 61, 12 inflight 241 sec =20 With this patch the stranded buffers are freed at deinit, inflight drops to zero and the pool drains cleanly. .../net/ethernet/aquantia/atlantic/aq_ring.c | 29 +++++++++++++++++++ .../net/ethernet/aquantia/atlantic/aq_ring.h | 1 + .../net/ethernet/aquantia/atlantic/aq_vec.c | 2 +- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c b/drivers/net= /ethernet/aquantia/atlantic/aq_ring.c index 8ff07de2bd52..81685a4dc5a6 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c @@ -360,6 +360,35 @@ bool aq_ring_tx_clean(struct aq_ring_s *self) return !!budget; } =20 +void aq_ring_tx_deinit(struct aq_ring_s *self) +{ + if (!self) + return; + + for (; self->sw_head !=3D self->sw_tail; + self->sw_head =3D aq_ring_next_dx(self, self->sw_head)) { + struct aq_ring_buff_s *buff =3D &self->buff_ring[self->sw_head]; + struct device *ndev =3D aq_nic_get_dev(self->aq_nic); + + if (buff->is_mapped) { + if (buff->is_sop) { + dma_unmap_single(ndev, buff->pa, buff->len, + DMA_TO_DEVICE); + } else { + dma_unmap_page(ndev, buff->pa, buff->len, + DMA_TO_DEVICE); + } + } + + if (buff->is_eop) { + if (buff->skb) + dev_kfree_skb_any(buff->skb); + else if (buff->xdpf) + xdp_return_frame(buff->xdpf); + } + } +} + static void aq_rx_checksum(struct aq_ring_s *self, struct aq_ring_buff_s *buff, struct sk_buff *skb) diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.h b/drivers/net= /ethernet/aquantia/atlantic/aq_ring.h index a70b880ada67..6431cc62962f 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.h @@ -202,6 +202,7 @@ void aq_ring_update_queue_state(struct aq_ring_s *ring); void aq_ring_queue_wake(struct aq_ring_s *ring); void aq_ring_queue_stop(struct aq_ring_s *ring); bool aq_ring_tx_clean(struct aq_ring_s *self); +void aq_ring_tx_deinit(struct aq_ring_s *self); int aq_xdp_xmit(struct net_device *dev, int num_frames, struct xdp_frame **frames, u32 flags); int aq_ring_rx_clean(struct aq_ring_s *self, diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_vec.c b/drivers/net/= ethernet/aquantia/atlantic/aq_vec.c index 2f9033ceed8c..05814fea0f5f 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_vec.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_vec.c @@ -275,7 +275,7 @@ void aq_vec_deinit(struct aq_vec_s *self) =20 for (i =3D 0U; self->tx_rings > i; ++i) { ring =3D self->ring[i]; - aq_ring_tx_clean(&ring[AQ_VEC_TX_ID]); + aq_ring_tx_deinit(&ring[AQ_VEC_TX_ID]); aq_ring_rx_deinit(&ring[AQ_VEC_RX_ID]); } =20 base-commit: af39eb111ce6b5eba9c08513b62c4868eb7e7fd5 --=20 2.47.3 From nobody Fri Oct 2 10:08:53 2026 Received: from out162-62-57-137.mail.qq.com (out162-62-57-137.mail.qq.com [162.62.57.137]) (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 8114E237180; Sun, 2 Aug 2026 15:46:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=162.62.57.137 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785685612; cv=none; b=qUHq4Nlp+kqbCqbviax1tpNdNBlQHjvL5EASw098k+WDHor+vPGLqhlXD54WrUytGr+fxHEj5SbPdRjZRxoioSiIlrCVp2auMoPeeOIeFyr9rPB7LB94tNRCahrrVQWuqd5oL84c80T2e77G8eaNwIK/HlwzEtJLxLFyePEi2kA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785685612; c=relaxed/simple; bh=IfrwjOpzPnpV9Q+Tru6a26fgTY45Egp/KC1PG3FiSs0=; h=Message-ID:From:To:Cc:Subject:Date:In-Reply-To:References: MIME-Version; b=J7orzNbVci+x5Y+dHFm9bYT10KJ4OKUewgEUqTn4XTLeoRkA5TuMmwbsYb4suRSHo2p2M3d53MXZIVxHJz/YJ3PmHl98fabuImTTXyttIC9k2K/Gbpcs/cP5VAWSDdz8/8DPWQ+H6GAsBZ8TqWX1gQAurNEyFaEYw2Ej4t+TXtQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=cyyself.name; spf=pass smtp.mailfrom=cyyself.name; dkim=pass (1024-bit key) header.d=qq.com header.i=@qq.com header.b=tZ48CzR0; arc=none smtp.client-ip=162.62.57.137 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=cyyself.name Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=cyyself.name Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=qq.com header.i=@qq.com header.b="tZ48CzR0" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qq.com; s=s201512; t=1785685604; bh=J4VqWLfvWNBX30FARDgxlRiuvqFbIs6GXH5ot/8285s=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=tZ48CzR0S8U1Ex6XrH5R9lrA5dKl4bytBCDo4XMR2R04lPslSe41JZFs/cb+jZc/b DDMT8OsB77X+m3rL3ut12+jC71Cxa1PAxCusEgApvJJSesfKskDkRGJRmpkHNCy5ok +ggWZDt8rjj7a93OEmvqX27CI/KJJH/k86m0yYZs= Received: from halo.lan ([240e:379:2238:cc00:262b:8ebc:c000:80a0]) by newxmesmtplogicsvrsza53-0.qq.com (NewEsmtp) with SMTP id BA820436; Sun, 02 Aug 2026 23:46:40 +0800 X-QQ-mid: xmsmtpt1785685600t8z39glaz Message-ID: X-QQ-XMAILINFO: MIB/1UGyXKa7T8S0WAGwz5545nqgzT3DySR5JVCmudQCDCEhls3oawacPvze7B 1UD2Y0+5Gt/t3gUSK7PRsE2XkvL2JSIk7AuVmI0WjKYFhAZ4U7DVhhLa6OTSvS4bB+97kmOvzmGS oCItJTU5/m0/vuz4DRmuDvKD0YkNrRu9XGEs20w5eV64aZclAIQAGVln62rHk1G4wteZMW1aSlqL OoSsC84tO3SWltdhpfJsToUvKkLbxhgrAlf8K4jErE52MnRnMPWsYWt5MrH+okgvHOyLrKAHGCcf t22s8rtDxaGCaLcXK6s3mZ764U9REXO/9E/0mT/8H4jjDnilk8Oomm5D8pqJqMnPoPP2Z36dwknp ChVqiRO9hMxsX2Nt2v9SZ36iPr7yaU1unT9oX4EiRGN9+wkxmsSChd9xOH5s6Suj3zHaVwUuRful LwEk4haMuJTfz6kf4lqEAsAeG89gKlm/iDT0mfj2rz0E9i1PKGt5cPN2ENNGCKGrmODWpoBNL2Lx 8fNys0wx3heCoOvWVToORWzcbwy/G/PZc3IAos/Z6qhYmC4ZRfZoz9lc4DF+l7Q/cHxbE3nLYDUJ QP3MI2GvkMOVvhvNjm8ziFIl35mJ/Ae5iQRMYRNjxGnKJp1wJLbqU/kXWz7T3d+wMaeh5VxxBMVk rw0Xm06nAWlnBL6snbxyjiUmNxDW3Xq7ConHyVLF1NsGTIXfL3tGcPE4niDDNv0irMiEDsTx2u/6 WE92GxSG+9j07d81uDyloPF4X5E9K7EjQvCt0Gyh7S4FFYbN0VM5JdTKXA09xGhN8pHer0qFFxqH Mh1OkMtM1bC004Op3sELeyR0IEGiKY0FjIfRsY6kJ08zGyvCvqwgL2f65gIdg+M4C/IWeYJSeJnG b56GYpIrrY3iDMMfRWcQ1Zo3Cofg3mTPljucXyjzr2RQpqx+/NY40+pJwFk3SilxKusRaSTCCcJP K3elLgB+D274qcoKu4fwxy6ZQnkLV0thDWl/jU7IhDx0ozJP9JPNVGbrupnKVlddxbRsrARbs23Q skmfgiOcWe/be+Pg98K7Od4WydbJq34u+UJUdU1ccO0Gxq8/b1KzdH3NsmCdxj2c1unitAgnORou BSkR9xp1gV0N/HVJ9g3WKa5Oj997QQCGxlzT77vNtU1mrqZwGtNqzJ3sKPuQ== X-QQ-XMRINFO: M/715EihBoGS47X28/vv4NpnfpeBLnr4Qg== From: Yangyu Chen To: Sukhdeep Singh , Andrew Lunn , "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni Cc: Mina Almasry , Jesper Dangaard Brouer , Richard Cochran , Lino Sanfilippo , Igor Russkikh , Simon Horman , netdev@vger.kernel.org, bpf@vger.kernel.org, linux-kernel@vger.kernel.org, stable@vger.kernel.org, Yangyu Chen Subject: [PATCH net 2/2] net: atlantic: free RX pages of consumed but not refilled buffers Date: Sun, 2 Aug 2026 23:46:38 +0800 X-OQ-MSGID: <20260802154638.40342-1-cyy@cyyself.name> X-Mailer: git-send-email 2.47.3 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" aq_ring_rx_deinit() only walks [sw_head, sw_tail), the region posted to hardware. Since the page reuse strategy was added, a cleaned RX buffer keeps its page (and its DMA mapping) in the ring for reuse, and refill is batched: aq_ring_rx_fill() returns early until AQ_CFG_RX_REFILL_THRES slots are free. Slots that were consumed but not yet reposted therefore sit in the complementary [sw_tail, sw_head) gap with a live page, and the deinit walk never visits them: up to a refill batch worth of pages and DMA mappings leak on every interface down. Walk the whole ring instead and release whatever is still there. Also bail out if the buffer ring is already gone: a partial aq_ptp_ring_alloc() failure frees the ring but leaves aq_nic set, so aq_ptp_ring_deinit() still gets here on the unwind path. Fixes: 46f4c29d9de6 ("net: aquantia: optimize rx performance by page reuse = strategy") Cc: stable@vger.kernel.org # v5.2+ Reviewed-by: Sukhdeep Singh Assisted-by: Claude:claude-fable-5 Signed-off-by: Yangyu Chen Acked-by: Mina Almasry Reviewed-by tags, and each carries a Fixes tag and a Cc: stable with --- Notes: Without this fix, the page_pool conversion posted for net-next turns th= e missed pages into fragments that page_pool_destroy() waits for forever. Reproduced on an AQC100 with the conversion applied and this fix reverted -- ordinary small received frames (<=3D 256 byte header-only packets, e.g. ping replies or pure TCP ACKs) are enough to populate the [sw_tail, sw_head) gap: =20 ping -c 200 -i 0.005 %enp99s0 ip link set enp99s0 down =20 One short ping flow left three of the eight RX rings' pools with stranded fragments, and page_pool_release_retry() warns for each of them every 60 seconds, indefinitely: =20 [278084.929092] page_pool_release_retry() stalled pool shutdown: id 1= 23, 1 inflight 60 sec [278084.961064] page_pool_release_retry() stalled pool shutdown: id 1= 26, 1 inflight 60 sec [278084.961087] page_pool_release_retry() stalled pool shutdown: id 1= 25, 6 inflight 60 sec [278145.346737] page_pool_release_retry() stalled pool shutdown: id 1= 23, 1 inflight 120 sec [278145.378745] page_pool_release_retry() stalled pool shutdown: id 1= 25, 6 inflight 120 sec [278145.378759] page_pool_release_retry() stalled pool shutdown: id 1= 26, 1 inflight 120 sec =20 With this patch the whole ring is walked at deinit, the pages are released, and the pools drain immediately. On the current code the same gap leaks the pages and their DMA mappings silently. =20 Applies and was build- and runtime-tested independently of the page_pool conversion, against the current page reuse scheme. .../net/ethernet/aquantia/atlantic/aq_ring.c | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c b/drivers/net= /ethernet/aquantia/atlantic/aq_ring.c index 81685a4dc5a6..e1193c6719d9 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c @@ -950,15 +950,29 @@ int aq_ring_rx_fill(struct aq_ring_s *self) =20 void aq_ring_rx_deinit(struct aq_ring_s *self) { - if (!self) + unsigned int i; + + if (!self || !self->buff_ring) return; =20 - for (; self->sw_head !=3D self->sw_tail; - self->sw_head =3D aq_ring_next_dx(self, self->sw_head)) { - struct aq_ring_buff_s *buff =3D &self->buff_ring[self->sw_head]; + /* Release every page still owned by the ring. + * + * Walking [sw_head, sw_tail) is not enough: refill is batched + * (aq_ring_rx_fill() waits for AQ_CFG_RX_REFILL_THRES free slots), + * so slots that were cleaned but not yet reposted accumulate in the + * [sw_tail, sw_head) gap, and they keep their page for reuse. Walk + * the whole ring and release whatever is left. + */ + for (i =3D 0; i < self->size; i++) { + struct aq_ring_buff_s *buff =3D &self->buff_ring[i]; + + if (!buff->rxdata.page) + continue; =20 aq_free_rxpage(&buff->rxdata, aq_nic_get_dev(self->aq_nic)); } + + self->sw_head =3D self->sw_tail; } =20 void aq_ring_free(struct aq_ring_s *self) --=20 2.47.3