--- /dev/null
+From 898ad80d1207cbdb22b21bafb6de4adfd7627bd0 Mon Sep 17 00:00:00 2001
+From: Pavel Begunkov <asml.silence@gmail.com>
+Date: Mon, 23 Mar 2026 12:43:57 +0000
+Subject: io_uring/zcrx: use guards for locking
+
+From: Pavel Begunkov <asml.silence@gmail.com>
+
+commit 898ad80d1207cbdb22b21bafb6de4adfd7627bd0 upstream.
+
+Convert last several places using manual locking to guards to simplify
+the code.
+
+Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
+Link: https://patch.msgid.link/eb4667cfaf88c559700f6399da9e434889f5b04a.1774261953.git.asml.silence@gmail.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ io_uring/zcrx.c | 15 +++++++--------
+ 1 file changed, 7 insertions(+), 8 deletions(-)
+
+--- a/io_uring/zcrx.c
++++ b/io_uring/zcrx.c
+@@ -696,9 +696,8 @@ static void io_zcrx_return_niov_freelist
+ {
+ struct io_zcrx_area *area = io_zcrx_iov_to_area(niov);
+
+- spin_lock_bh(&area->freelist_lock);
++ guard(spinlock_bh)(&area->freelist_lock);
+ area->freelist[area->free_count++] = net_iov_idx(niov);
+- spin_unlock_bh(&area->freelist_lock);
+ }
+
+ static void io_zcrx_return_niov(struct net_iov *niov)
+@@ -829,7 +828,8 @@ static void io_zcrx_refill_slow(struct p
+ {
+ struct io_zcrx_area *area = ifq->area;
+
+- spin_lock_bh(&area->freelist_lock);
++ guard(spinlock_bh)(&area->freelist_lock);
++
+ while (area->free_count && pp->alloc.count < PP_ALLOC_CACHE_REFILL) {
+ struct net_iov *niov = __io_zcrx_get_free_niov(area);
+ netmem_ref netmem = net_iov_to_netmem(niov);
+@@ -838,7 +838,6 @@ static void io_zcrx_refill_slow(struct p
+ io_zcrx_sync_for_device(pp, niov);
+ net_mp_netmem_place_in_cache(pp, netmem);
+ }
+- spin_unlock_bh(&area->freelist_lock);
+ }
+
+ static netmem_ref io_pp_zc_alloc_netmems(struct page_pool *pp, gfp_t gfp)
+@@ -975,10 +974,10 @@ static struct net_iov *io_alloc_fallback
+ if (area->mem.is_dmabuf)
+ return NULL;
+
+- spin_lock_bh(&area->freelist_lock);
+- if (area->free_count)
+- niov = __io_zcrx_get_free_niov(area);
+- spin_unlock_bh(&area->freelist_lock);
++ scoped_guard(spinlock_bh, &area->freelist_lock) {
++ if (area->free_count)
++ niov = __io_zcrx_get_free_niov(area);
++ }
+
+ if (niov)
+ page_pool_fragment_netmem(net_iov_to_netmem(niov), 1);
--- /dev/null
+From 770594e78c3964cf23cf5287f849437cdde9b7d0 Mon Sep 17 00:00:00 2001
+From: Pavel Begunkov <asml.silence@gmail.com>
+Date: Tue, 21 Apr 2026 09:45:29 +0100
+Subject: io_uring/zcrx: warn on freelist violations
+
+From: Pavel Begunkov <asml.silence@gmail.com>
+
+commit 770594e78c3964cf23cf5287f849437cdde9b7d0 upstream.
+
+The freelist is appropriately sized to always be able to take a free
+niov, but let's be more defensive and check the invariant with a
+warning. That should help to catch any double-free issues.
+
+Suggested-by: Kai Aizen <kai@snailsploit.com>
+Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
+Link: https://patch.msgid.link/2f3cea363b04649755e3b6bb9ab66485a95936d5.1776760901.git.asml.silence@gmail.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ io_uring/zcrx.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/io_uring/zcrx.c
++++ b/io_uring/zcrx.c
+@@ -697,6 +697,8 @@ static void io_zcrx_return_niov_freelist
+ struct io_zcrx_area *area = io_zcrx_iov_to_area(niov);
+
+ guard(spinlock_bh)(&area->freelist_lock);
++ if (WARN_ON_ONCE(area->free_count >= area->nia.num_niovs))
++ return;
+ area->freelist[area->free_count++] = net_iov_idx(niov);
+ }
+