Re: [PATCH v2 2/2] f2fs: refresh pinned allocation boundary after resize

From: Daeho Jeong

Date: Wed Oct 14 2026 - 00:58:32 EST


On Tue, Sep 1, 2026 at 8:58 AM Daeho Jeong <daeho43@xxxxxxxxx> wrote:
>
> On Mon, Aug 31, 2026 at 7:53 PM Wenjie Qi <qwjhust@xxxxxxxxx> wrote:
> >
> > Hi Daeho,
> >
> > The second check is intentional. The first check is only an early
> > validation before mnt_want_write_file(), but mnt_want_write_file() does
> > not hold sb->s_umount. A concurrent remount can therefore change
> > resizable_tail_secno before freeze_super() obtains the exclusive
> > superblock lock.
> >
> > A test-only hook pauses resize after the early check and before
> > mnt_want_write_file(), allowing a concurrent remount to change
> > resizable_tail_secno before resize continues. Starting with 506 sections
> > and tail=1, the single-check version let a remount change the tail to
> > 128 and incorrectly returned success. With the second check, resize
> > returned -EINVAL and preserved 506 sections with
> > pinned_area_max_secno=378.
> >
> > The first check is the fast path for invalid requests, while the second
> > check validates the final geometry after freezing the filesystem and
> > taking the resize locks. Both checks are needed.
> >
> > Thanks,
> > Wenjie
>
> Reviewed-by: Daeho Jeong <daehojeong@xxxxxxxxxx>
>
> Thanks,

Hi Wenjie,

Thinking about the actual use case of resizable_tail_secno a bit more,
I realized there is a semantic issue with keeping resizable_tail_secno
unchanged after shrinking the filesystem.

The purpose of resizable_tail_secno=N is to reserve N sections at the
tail of the filesystem ([MAIN_SECS - N, MAIN_SECS)) as an unpinned area
so that those tail sections can be shrunk later via F2FS_IOC_RESIZE_FS,
while keeping the pinned area boundary fixed at (MAIN_SECS - N).

For example, suppose a 30 GiB filesystem (15,360 sections) is mounted
with resizable_tail_secno=10240 (20 GiB reserved at the tail for
shrinking), so pinned_area_max_secno is 5,120 (the first 10 GiB).

With the current patch, F2FS_OPTION(sbi).resizable_tail_secno is kept at
10,240 after resize, which causes two problems:

1. Shrinking the tail eats into the pinned area instead of consuming the
reserved tail:
If we shrink the filesystem by 64 sections (128 MiB), MAIN_SECS
becomes 15,296, and f2fs_adjust_pinned_area_boundary() recalculates:
pinned_area_max_secno = 15,296 - 10,240 = 5,056
Even though we only shrunk 64 sections from the unpinned tail, the
pinned area boundary shrinks from 5,120 to 5,056.

2. We can never shrink the full reserved tail (or even part of it if
secs + resizable_tail_secno >= MAIN_SECS):
In the example above, if we try to shrink all 20 GiB (10,240 sections)
or even 10 GiB (5,120 sections) of the reserved tail,
f2fs_resize_tail_invalid() rejects the resize with -EINVAL because
secs + resizable_tail_secno >= MAIN_SECS (10,240 + 10,240 >= 15,360).

When the filesystem is shrunk by `secs` sections from the tail, the
reserved tail itself is what is being consumed. So instead of keeping
resizable_tail_secno fixed, we should deduct the shrunk sections from
F2FS_OPTION(sbi).resizable_tail_secno (or clamp it to 0 if secs >=
resizable_tail_secno, and restore the old value on checkpoint failure
rollback) before calling f2fs_adjust_pinned_area_boundary(sbi).

That way:
- While shrinking within the reserved tail (secs <= resizable_tail_secno),
resizable_tail_secno decreases by `secs` and pinned_area_max_secno
(MAIN_SECS - resizable_tail_secno) remains unchanged at 5,120.
- Once the entire reserved tail is shrunk (secs == resizable_tail_secno),
resizable_tail_secno becomes 0 and pinned_area_max_secno equals the
new MAIN_SECS (5,120).
- If someone shrinks beyond resizable_tail_secno (or when
resizable_tail_secno is 0), resizable_tail_secno becomes 0 and
pinned_area_max_secno is clamped to the new MAIN_SECS without
underflowing.

Could you update the patch to adjust resizable_tail_secno accordingly?

Thanks,