From ff99a5f6cbcc9c4810a8dac46fe76473539513f9 Mon Sep 17 00:00:00 2001 From: Hans Holmberg Date: Wed, 26 Aug 2026 14:32:19 +0200 Subject: [PATCH] xfs: prevent race in zoned space reservations xfs_zoned_add_available() checks whether the reservation list is empty before adding blocks to the available-space counter. This check is not serialized against a task adding itself to the reservation list however. This allows the space provider to observe an empty list, after which a reserver can enqueue itself and retry the counter before the new space is added. The provider then adds the space and returns without waking the now-eligible reserver, leaving it asleep until GC or another event provides a wakeup, potentially adding seconds to max write latency. Take the reservation lock before updating the counter and checking the list. Use list_empty() because the list is now inspected under its lock. Taking a per-mount lock when handing back space is far from ideal, but benchmarking with null_blk showed no measurable performance regression. Fixes: 0bb2193056b5 ("xfs: add support for zoned space reservations") Reported-by: Sashiko Closes: https://sashiko.dev/#/patchset/20260609075655.1698743-1-hch@lst.de?part=2 Signed-off-by: Hans Holmberg Reviewed-by: Carlos Maiolino Reviewed-by: Christoph Hellwig Signed-off-by: Carlos Maiolino --- fs/xfs/xfs_zone_space_resv.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/xfs/xfs_zone_space_resv.c b/fs/xfs/xfs_zone_space_resv.c index 5c6e6ef627e4..7aa3c74fb2e0 100644 --- a/fs/xfs/xfs_zone_space_resv.c +++ b/fs/xfs/xfs_zone_space_resv.c @@ -85,13 +85,13 @@ xfs_zoned_add_available( struct xfs_zone_info *zi = mp->m_zone_info; struct xfs_zone_reservation *reservation; - if (list_empty_careful(&zi->zi_reclaim_reservations)) { - xfs_add_freecounter(mp, XC_FREE_RTAVAILABLE, count_fsb); + spin_lock(&zi->zi_reservation_lock); + xfs_add_freecounter(mp, XC_FREE_RTAVAILABLE, count_fsb); + if (list_empty(&zi->zi_reclaim_reservations)) { + spin_unlock(&zi->zi_reservation_lock); return; } - spin_lock(&zi->zi_reservation_lock); - xfs_add_freecounter(mp, XC_FREE_RTAVAILABLE, count_fsb); count_fsb = xfs_sum_freecounter(mp, XC_FREE_RTAVAILABLE); list_for_each_entry(reservation, &zi->zi_reclaim_reservations, entry) { if (reservation->count_fsb > count_fsb)