From: Chris Mason <clm@meta.com>
To: Christoph Hellwig <hch@lst.de>
Cc: Chris Mason <clm@meta.com>, Jens Axboe <axboe@kernel.dk>,
Carlos Maiolino <cem@kernel.org>,
Damien Le Moal <dlemoal@kernel.org>,
Hans Holmberg <hans.holmberg@wdc.com>,
Keith Busch <kbusch@kernel.org>, <linux-block@vger.kernel.org>,
<linux-xfs@vger.kernel.org>,
Carlos Maiolino <cmaiolino@redhat.com>
Subject: Re: [PATCH 3/3] xfs: rework zone GC buffer management
Date: Sat, 24 Jan 2026 16:03:04 -0800 [thread overview]
Message-ID: <20260125000314.561545-1-clm@meta.com> (raw)
In-Reply-To: <20260114130651.3439765-4-hch@lst.de>
On Wed, 14 Jan 2026 14:06:43 +0100 Christoph Hellwig <hch@lst.de> wrote:
> The double buffering where just one scratch area is used at a time does
> not efficiently use the available memory. It was originally implemented
> when GC I/O could happen out of order, but that was removed before
> upstream submission to avoid fragmentation. Now that all GC I/Os are
> processed in order, just use a number of buffers as a simple ring buffer.
>
> For a synthetic benchmark that fills 256MiB HDD zones and punches out
> holes to free half the space this leads to a decrease of GC time by
> a little more than 25%.
Hi everyone,
I'm pretty low confidence on this, but it was flagged when I ran a bunch of
linux-next commits through the AI review prompts. I'm curious if the AI is
on to something or if I need to adjust things:
> diff --git a/fs/xfs/xfs_zone_gc.c b/fs/xfs/xfs_zone_gc.c
> --- a/fs/xfs/xfs_zone_gc.c
> +++ b/fs/xfs/xfs_zone_gc.c
[ ... ]
> @@ -590,7 +578,12 @@ xfs_zone_gc_ensure_target(
> xfs_zone_gc_scratch_available(
> struct xfs_zone_gc_data *data)
> {
> - return XFS_GC_CHUNK_SIZE - data->scratch[data->scratch_idx].offset;
> + if (!data->scratch_tail)
> + return data->scratch_size - data->scratch_head;
> +
> + if (!data->scratch_head)
> + return data->scratch_tail;
> + return (data->scratch_size - data->scratch_head) + data->scratch_tail;
> }
Can this function correctly distinguish between an empty and full ring
buffer?
When scratch_head wraps back to 0 and scratch_tail is also 0 (because no
I/O has completed yet), the first condition returns scratch_size (2MB),
indicating the buffer is empty. But if the buffer just filled completely
and head wrapped to 0, the buffer is actually full, and the available
space should be 0.
Consider this sequence in xfs_zone_gc_handle_work():
- Initial: head=0, tail=0, available=2MB (correct, empty)
- After 1MB chunk: head=1MB, tail=0, available=1MB (correct)
- After another 1MB chunk: head=0 (wrapped), tail=0, available=2MB (wrong)
The buffer is full but the function reports it as empty. The while loop
in xfs_zone_gc_handle_work() calling xfs_zone_gc_start_chunk() would then
continue adding more data, overwriting the buffer contents from the first
chunk before its I/O completes.
[ ... ]
> @@ -710,13 +728,9 @@ xfs_zone_gc_start_chunk(
>
> bio->bi_iter.bi_sector = xfs_rtb_to_daddr(mp, chunk->old_startblock);
> bio->bi_end_io = xfs_zone_gc_end_io;
> - bio_add_folio_nofail(bio, chunk->scratch->folio, chunk->len,
> - chunk->scratch->offset);
> - chunk->scratch->offset += chunk->len;
> - if (chunk->scratch->offset == XFS_GC_CHUNK_SIZE) {
> - data->scratch_idx =
> - (data->scratch_idx + 1) % XFS_ZONE_GC_NR_SCRATCH;
> - }
> + xfs_zone_gc_add_data(chunk);
> + data->scratch_head = (data->scratch_head + len) % data->scratch_size;
This advances scratch_head with modulo arithmetic, which is correct for
wrap-around. However, if head catches up to tail (buffer full), the code
does not detect this condition.
[ ... ]
> @@ -845,11 +860,8 @@ xfs_zone_gc_finish_chunk(
> return;
> }
>
> - chunk->scratch->freed += chunk->len;
> - if (chunk->scratch->freed == chunk->scratch->offset) {
> - chunk->scratch->offset = 0;
> - chunk->scratch->freed = 0;
> - }
> + data->scratch_tail =
> + (data->scratch_tail + chunk->len) % data->scratch_size;
And scratch_tail advances here when I/O completes. The classic ring
buffer empty/full ambiguity applies: when head == tail, is the buffer
empty or full? The xfs_zone_gc_scratch_available() function assumes
head=0 and tail=0 always means empty, but after wrapping it could mean
full.
A common solution is to track a separate count, or to sacrifice one slot
so head == tail always means empty, and head == tail-1 means full.
next prev parent reply other threads:[~2026-01-25 0:03 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-01-14 13:06 improve zoned XFS GC buffer management v4 Christoph Hellwig
2026-01-14 13:06 ` [PATCH 1/3] block: add a bio_reuse helper Christoph Hellwig
2026-01-14 13:06 ` [PATCH 2/3] xfs: use bio_reuse in the zone GC code Christoph Hellwig
2026-01-14 19:50 ` Darrick J. Wong
2026-01-14 13:06 ` [PATCH 3/3] xfs: rework zone GC buffer management Christoph Hellwig
2026-01-14 19:59 ` Darrick J. Wong
2026-01-15 6:12 ` Christoph Hellwig
2026-01-25 0:03 ` Chris Mason [this message]
2026-01-26 20:30 ` Keith Busch
2026-01-27 6:53 ` Christoph Hellwig
2026-01-21 12:21 ` improve zoned XFS GC buffer management v4 Carlos Maiolino
-- strict thread matches above, loose matches on Subject: below --
2026-01-13 7:19 improve zoned XFS GC buffer management v3 Christoph Hellwig
2026-01-13 7:19 ` [PATCH 3/3] xfs: rework zone GC buffer management Christoph Hellwig
2026-01-06 7:58 improve zoned XFS GC buffer management v2 Christoph Hellwig
2026-01-06 7:58 ` [PATCH 3/3] xfs: rework zone GC buffer management Christoph Hellwig
2026-01-09 12:24 ` Carlos Maiolino
2025-12-18 6:31 improve zoned XFS " Christoph Hellwig
2025-12-18 6:31 ` [PATCH 3/3] xfs: rework zone " Christoph Hellwig
2025-12-18 7:12 ` Damien Le Moal
2025-12-19 8:06 ` Hans Holmberg
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=20260125000314.561545-1-clm@meta.com \
--to=clm@meta.com \
--cc=axboe@kernel.dk \
--cc=cem@kernel.org \
--cc=cmaiolino@redhat.com \
--cc=dlemoal@kernel.org \
--cc=hans.holmberg@wdc.com \
--cc=hch@lst.de \
--cc=kbusch@kernel.org \
--cc=linux-block@vger.kernel.org \
--cc=linux-xfs@vger.kernel.org \
/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