* [f2fs-dev] [PATCH v3 0/2] f2fs: fix online resize state
@ 2026-10-15 8:35 Wenjie Qi
2026-10-15 8:35 ` [f2fs-dev] [PATCH v3 1/2] f2fs: flush SIT journal during filesystem resize Wenjie Qi
2026-10-15 8:35 ` [f2fs-dev] [PATCH v3 2/2] f2fs: refresh pinned allocation boundary after resize Wenjie Qi
0 siblings, 2 replies; 4+ messages in thread
From: Wenjie Qi @ 2026-10-15 8:35 UTC (permalink / raw)
To: Jaegeuk Kim, Chao Yu
Cc: Daeho Jeong, qwjhust, linux-kernel, linux-f2fs-devel, qiwenjie,
Qiuyang Sun
Online shrink changes both persistent SIT state and the geometry used
by pinned allocation. This series prevents old state from surviving
those changes.
Patch 1 drains the SIT journal during resize even when there are no
new dirty sentries. Its code is unchanged, with Daeho's Reviewed-by
added.
Patch 2 now consumes the reserved tail as sections are removed. This
keeps the pinned boundary fixed while shrinking within the reservation
and limits it to the new main area when the reservation is exhausted.
It restores the old tail and boundary on final checkpoint rollback.
Changes since v2:
- Rebase onto current f2fs/dev.
- Reduce resizable_tail_secno by the removed sections, down to zero.
- Save the current tail after freeze and restore it on rollback.
- Document that online shrink consumes the reservation.
- Retain Daeho's review for patch 1; request a new review for patch 2.
Wenjie Qi (2):
f2fs: flush SIT journal during filesystem resize
f2fs: refresh pinned allocation boundary after resize
Documentation/filesystems/f2fs.rst | 3 ++-
fs/f2fs/gc.c | 6 +++++-
fs/f2fs/segment.c | 2 +-
fs/f2fs/segment.h | 11 +++++++++++
fs/f2fs/super.c | 15 ++-------------
5 files changed, 21 insertions(+), 16 deletions(-)
base-commit: e455328a66a5f4827d4ba96acfe50dbbb0e13b8d
--
2.43.0
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
^ permalink raw reply [flat|nested] 4+ messages in thread
* [f2fs-dev] [PATCH v3 1/2] f2fs: flush SIT journal during filesystem resize
2026-10-15 8:35 [f2fs-dev] [PATCH v3 0/2] f2fs: fix online resize state Wenjie Qi
@ 2026-10-15 8:35 ` Wenjie Qi
2026-10-15 8:35 ` [f2fs-dev] [PATCH v3 2/2] f2fs: refresh pinned allocation boundary after resize Wenjie Qi
1 sibling, 0 replies; 4+ messages in thread
From: Wenjie Qi @ 2026-10-15 8:35 UTC (permalink / raw)
To: Jaegeuk Kim, Chao Yu
Cc: Daeho Jeong, qwjhust, linux-kernel, linux-f2fs-devel, qiwenjie,
Qiuyang Sun
During a filesystem resize, SBI_IS_RESIZEFS prevents new SIT entries
from being added to the journal and forces existing entries to the SIT
area. However, f2fs_flush_sit_entries() returns early when there are no
new dirty sentries, leaving existing journal entries behind.
After the main area shrinks, a later checkpoint can access a journal
entry whose segment number is outside the new geometry and trigger
f2fs_bug_on().
Only take the zero-dirty fast path when entries may be written back to
the journal. This lets resize drain existing entries through
remove_sits_in_journal() even when there are no new dirty sentries.
Fixes: 04f0b2eaa3b3 ("f2fs: ioctl for removing a range from F2FS")
Reviewed-by: Daeho Jeong <daehojeong@google.com>
Signed-off-by: Wenjie Qi <qiwenjie@xiaomi.com>
---
fs/f2fs/segment.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index 25785b7626bb9..bf8d07fcce331 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -4893,7 +4893,7 @@ void f2fs_flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
down_write(&sit_i->sentry_lock);
- if (!sit_i->dirty_sentries)
+ if (!sit_i->dirty_sentries && to_journal)
goto out;
/*
--
2.43.0
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [f2fs-dev] [PATCH v3 2/2] f2fs: refresh pinned allocation boundary after resize
2026-10-15 8:35 [f2fs-dev] [PATCH v3 0/2] f2fs: fix online resize state Wenjie Qi
2026-10-15 8:35 ` [f2fs-dev] [PATCH v3 1/2] f2fs: flush SIT journal during filesystem resize Wenjie Qi
@ 2026-10-15 8:35 ` Wenjie Qi
2026-10-15 15:49 ` Daeho Jeong
1 sibling, 1 reply; 4+ messages in thread
From: Wenjie Qi @ 2026-10-15 8:35 UTC (permalink / raw)
To: Jaegeuk Kim, Chao Yu
Cc: Daeho Jeong, qwjhust, linux-kernel, linux-f2fs-devel, qiwenjie,
Qiuyang Sun
Online shrink updates MAIN_SECS() but leaves resizable_tail_secno and
pinned_area_max_secno unchanged. The pinned allocation limit can exceed
the new main area when shrinking beyond the reserved tail.
Consume the reserved tail by the number of removed sections, clamping
it to zero, before refreshing the shared pinned allocation boundary.
This preserves the boundary while shrinking within the reservation and
limits it to the new main area otherwise, retaining the zoned limit.
Save the old tail count and restore it before rolling back the geometry
if the final checkpoint fails.
Fixes: c966d29e01bb ("f2fs: support resizable tail section and unify pinned allocation")
Suggested-by: Daeho Jeong <daehojeong@google.com>
Signed-off-by: Wenjie Qi <qiwenjie@xiaomi.com>
---
Changes since v2:
- Consume the tail reservation instead of keeping its old size.
- Restore the saved tail before geometry and boundary rollback.
- Document the remaining-reservation semantics.
Documentation/filesystems/f2fs.rst | 3 ++-
fs/f2fs/gc.c | 6 +++++-
fs/f2fs/segment.h | 11 +++++++++++
fs/f2fs/super.c | 15 ++-------------
4 files changed, 20 insertions(+), 15 deletions(-)
diff --git a/Documentation/filesystems/f2fs.rst b/Documentation/filesystems/f2fs.rst
index 771216f45207a..55798421f2c45 100644
--- a/Documentation/filesystems/f2fs.rst
+++ b/Documentation/filesystems/f2fs.rst
@@ -421,7 +421,8 @@ resizable_tail_secno=%u Control the number of sections at the tail of the
(MAIN_SECS - resizable_tail_secno) - 1. If set to 0
(default), there is no tail restriction unless running
on a zoned block device where conventional zones are
- used.
+ used. Online shrink consumes this reservation, reducing
+ the value by the number of removed sections, down to zero.
======================== ============================================================
Debugfs Entries
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
index 926e6976bc22a..540769ad58acc 100644
--- a/fs/f2fs/gc.c
+++ b/fs/f2fs/gc.c
@@ -2342,6 +2342,7 @@ static void update_fs_metadata(struct f2fs_sb_info *sbi, int secs)
SM_I(sbi)->segment_count = (int)SM_I(sbi)->segment_count + segs;
MAIN_SEGS(sbi) = (int)MAIN_SEGS(sbi) + segs;
MAIN_SECS(sbi) += secs;
+ f2fs_adjust_pinned_area_boundary(sbi);
if (sbi->allocate_section_hint > MAIN_SECS(sbi))
sbi->allocate_section_hint = MAIN_SECS(sbi);
FREE_I(sbi)->free_sections = (int)FREE_I(sbi)->free_sections + secs;
@@ -2373,7 +2374,7 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
struct f2fs_lock_context lc;
struct f2fs_lock_context glc;
struct f2fs_lock_context clc;
- unsigned int secs;
+ unsigned int secs, old_tail;
int err = 0;
__u32 rem;
@@ -2482,6 +2483,8 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
goto recover_out;
}
+ old_tail = F2FS_OPTION(sbi).resizable_tail_secno;
+ F2FS_OPTION(sbi).resizable_tail_secno -= min(old_tail, secs);
update_fs_metadata(sbi, -secs);
clear_sbi_flag(sbi, SBI_IS_RESIZEFS);
set_sbi_flag(sbi, SBI_IS_DIRTY);
@@ -2489,6 +2492,7 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
stat_inc_cp_call_count(sbi, TOTAL_CALL);
err = f2fs_write_checkpoint(sbi, &cpc);
if (err) {
+ F2FS_OPTION(sbi).resizable_tail_secno = old_tail;
update_fs_metadata(sbi, secs);
update_sb_metadata(sbi, secs);
f2fs_commit_super(sbi, false);
diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
index 526764ba31ae5..918bc4452ad09 100644
--- a/fs/f2fs/segment.h
+++ b/fs/f2fs/segment.h
@@ -91,6 +91,17 @@ static inline void sanity_check_seg_type(struct f2fs_sb_info *sbi,
#define GET_ZONE_FROM_SEG(sbi, segno) \
GET_ZONE_FROM_SEC(sbi, GET_SEC_FROM_SEG(sbi, segno))
+static inline void f2fs_adjust_pinned_area_boundary(struct f2fs_sb_info *sbi)
+{
+ sbi->pinned_area_max_secno = MAIN_SECS(sbi);
+ if (f2fs_sb_has_blkzoned(sbi) && sbi->first_seq_zone_segno != NULL_SEGNO)
+ sbi->pinned_area_max_secno = min(sbi->pinned_area_max_secno,
+ GET_SEC_FROM_SEG(sbi, sbi->first_seq_zone_segno));
+ if (F2FS_OPTION(sbi).resizable_tail_secno)
+ sbi->pinned_area_max_secno = min(sbi->pinned_area_max_secno,
+ MAIN_SECS(sbi) - F2FS_OPTION(sbi).resizable_tail_secno);
+}
+
#define GET_SUM_BLOCK(sbi, segno) \
(SM_I(sbi)->ssa_blkaddr + (segno / (sbi)->sums_per_block))
#define GET_SUM_BLKOFF(sbi, segno) (segno % (sbi)->sums_per_block)
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 773b12ea29c0c..f323d9705aebe 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -554,17 +554,6 @@ static inline void adjust_unusable_cap_perc(struct f2fs_sb_info *sbi)
F2FS_OPTION(sbi).unusable_cap_perc);
}
-static inline void adjust_pinned_area_boundary(struct f2fs_sb_info *sbi)
-{
- sbi->pinned_area_max_secno = MAIN_SECS(sbi);
- if (f2fs_sb_has_blkzoned(sbi) && sbi->first_seq_zone_segno != NULL_SEGNO)
- sbi->pinned_area_max_secno = min(sbi->pinned_area_max_secno,
- GET_SEC_FROM_SEG(sbi, sbi->first_seq_zone_segno));
- if (F2FS_OPTION(sbi).resizable_tail_secno)
- sbi->pinned_area_max_secno = min(sbi->pinned_area_max_secno,
- MAIN_SECS(sbi) - F2FS_OPTION(sbi).resizable_tail_secno);
-}
-
static void init_once(void *foo)
{
struct f2fs_inode_info *fi = (struct f2fs_inode_info *) foo;
@@ -3103,7 +3092,7 @@ static int __f2fs_remount(struct fs_context *fc, struct super_block *sb)
sb->s_flags = (sb->s_flags & ~SB_POSIXACL) |
(test_opt(sbi, POSIX_ACL) ? SB_POSIXACL : 0);
- adjust_pinned_area_boundary(sbi);
+ f2fs_adjust_pinned_area_boundary(sbi);
limit_reserve_root(sbi);
fc->sb_flags = (flags & ~SB_LAZYTIME) | (sb->s_flags & SB_LAZYTIME);
@@ -5440,7 +5429,7 @@ static int f2fs_fill_super(struct super_block *sb, struct fs_context *fc)
/* get segno of first zoned block device */
sbi->first_seq_zone_segno = get_first_seq_zone_segno(sbi);
- adjust_pinned_area_boundary(sbi);
+ f2fs_adjust_pinned_area_boundary(sbi);
sbi->reserved_pin_section = f2fs_sb_has_blkzoned(sbi) ?
ZONED_PIN_SEC_REQUIRED_COUNT :
--
2.43.0
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [f2fs-dev] [PATCH v3 2/2] f2fs: refresh pinned allocation boundary after resize
2026-10-15 8:35 ` [f2fs-dev] [PATCH v3 2/2] f2fs: refresh pinned allocation boundary after resize Wenjie Qi
@ 2026-10-15 15:49 ` Daeho Jeong
0 siblings, 0 replies; 4+ messages in thread
From: Daeho Jeong @ 2026-10-15 15:49 UTC (permalink / raw)
To: Wenjie Qi
Cc: Daeho Jeong, linux-kernel, linux-f2fs-devel, qiwenjie,
Jaegeuk Kim, Qiuyang Sun
On Thu, Oct 15, 2026 at 1:35 AM Wenjie Qi <qwjhust@gmail.com> wrote:
>
> Online shrink updates MAIN_SECS() but leaves resizable_tail_secno and
> pinned_area_max_secno unchanged. The pinned allocation limit can exceed
> the new main area when shrinking beyond the reserved tail.
>
> Consume the reserved tail by the number of removed sections, clamping
> it to zero, before refreshing the shared pinned allocation boundary.
> This preserves the boundary while shrinking within the reservation and
> limits it to the new main area otherwise, retaining the zoned limit.
>
> Save the old tail count and restore it before rolling back the geometry
> if the final checkpoint fails.
>
> Fixes: c966d29e01bb ("f2fs: support resizable tail section and unify pinned allocation")
> Suggested-by: Daeho Jeong <daehojeong@google.com>
> Signed-off-by: Wenjie Qi <qiwenjie@xiaomi.com>
> ---
> Changes since v2:
> - Consume the tail reservation instead of keeping its old size.
> - Restore the saved tail before geometry and boundary rollback.
> - Document the remaining-reservation semantics.
>
> Documentation/filesystems/f2fs.rst | 3 ++-
> fs/f2fs/gc.c | 6 +++++-
> fs/f2fs/segment.h | 11 +++++++++++
> fs/f2fs/super.c | 15 ++-------------
> 4 files changed, 20 insertions(+), 15 deletions(-)
>
> diff --git a/Documentation/filesystems/f2fs.rst b/Documentation/filesystems/f2fs.rst
> index 771216f45207a..55798421f2c45 100644
> --- a/Documentation/filesystems/f2fs.rst
> +++ b/Documentation/filesystems/f2fs.rst
> @@ -421,7 +421,8 @@ resizable_tail_secno=%u Control the number of sections at the tail of the
> (MAIN_SECS - resizable_tail_secno) - 1. If set to 0
> (default), there is no tail restriction unless running
> on a zoned block device where conventional zones are
> - used.
> + used. Online shrink consumes this reservation, reducing
> + the value by the number of removed sections, down to zero.
> ======================== ============================================================
>
> Debugfs Entries
> diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
> index 926e6976bc22a..540769ad58acc 100644
> --- a/fs/f2fs/gc.c
> +++ b/fs/f2fs/gc.c
> @@ -2342,6 +2342,7 @@ static void update_fs_metadata(struct f2fs_sb_info *sbi, int secs)
> SM_I(sbi)->segment_count = (int)SM_I(sbi)->segment_count + segs;
> MAIN_SEGS(sbi) = (int)MAIN_SEGS(sbi) + segs;
> MAIN_SECS(sbi) += secs;
> + f2fs_adjust_pinned_area_boundary(sbi);
> if (sbi->allocate_section_hint > MAIN_SECS(sbi))
> sbi->allocate_section_hint = MAIN_SECS(sbi);
> FREE_I(sbi)->free_sections = (int)FREE_I(sbi)->free_sections + secs;
> @@ -2373,7 +2374,7 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
> struct f2fs_lock_context lc;
> struct f2fs_lock_context glc;
> struct f2fs_lock_context clc;
> - unsigned int secs;
> + unsigned int secs, old_tail;
> int err = 0;
> __u32 rem;
>
> @@ -2482,6 +2483,8 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
> goto recover_out;
> }
>
> + old_tail = F2FS_OPTION(sbi).resizable_tail_secno;
> + F2FS_OPTION(sbi).resizable_tail_secno -= min(old_tail, secs);
> update_fs_metadata(sbi, -secs);
> clear_sbi_flag(sbi, SBI_IS_RESIZEFS);
> set_sbi_flag(sbi, SBI_IS_DIRTY);
> @@ -2489,6 +2492,7 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
> stat_inc_cp_call_count(sbi, TOTAL_CALL);
> err = f2fs_write_checkpoint(sbi, &cpc);
> if (err) {
> + F2FS_OPTION(sbi).resizable_tail_secno = old_tail;
> update_fs_metadata(sbi, secs);
> update_sb_metadata(sbi, secs);
> f2fs_commit_super(sbi, false);
> diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
> index 526764ba31ae5..918bc4452ad09 100644
> --- a/fs/f2fs/segment.h
> +++ b/fs/f2fs/segment.h
> @@ -91,6 +91,17 @@ static inline void sanity_check_seg_type(struct f2fs_sb_info *sbi,
> #define GET_ZONE_FROM_SEG(sbi, segno) \
> GET_ZONE_FROM_SEC(sbi, GET_SEC_FROM_SEG(sbi, segno))
>
> +static inline void f2fs_adjust_pinned_area_boundary(struct f2fs_sb_info *sbi)
> +{
> + sbi->pinned_area_max_secno = MAIN_SECS(sbi);
> + if (f2fs_sb_has_blkzoned(sbi) && sbi->first_seq_zone_segno != NULL_SEGNO)
> + sbi->pinned_area_max_secno = min(sbi->pinned_area_max_secno,
> + GET_SEC_FROM_SEG(sbi, sbi->first_seq_zone_segno));
> + if (F2FS_OPTION(sbi).resizable_tail_secno)
> + sbi->pinned_area_max_secno = min(sbi->pinned_area_max_secno,
> + MAIN_SECS(sbi) - F2FS_OPTION(sbi).resizable_tail_secno);
> +}
> +
> #define GET_SUM_BLOCK(sbi, segno) \
> (SM_I(sbi)->ssa_blkaddr + (segno / (sbi)->sums_per_block))
> #define GET_SUM_BLKOFF(sbi, segno) (segno % (sbi)->sums_per_block)
> diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
> index 773b12ea29c0c..f323d9705aebe 100644
> --- a/fs/f2fs/super.c
> +++ b/fs/f2fs/super.c
> @@ -554,17 +554,6 @@ static inline void adjust_unusable_cap_perc(struct f2fs_sb_info *sbi)
> F2FS_OPTION(sbi).unusable_cap_perc);
> }
>
> -static inline void adjust_pinned_area_boundary(struct f2fs_sb_info *sbi)
> -{
> - sbi->pinned_area_max_secno = MAIN_SECS(sbi);
> - if (f2fs_sb_has_blkzoned(sbi) && sbi->first_seq_zone_segno != NULL_SEGNO)
> - sbi->pinned_area_max_secno = min(sbi->pinned_area_max_secno,
> - GET_SEC_FROM_SEG(sbi, sbi->first_seq_zone_segno));
> - if (F2FS_OPTION(sbi).resizable_tail_secno)
> - sbi->pinned_area_max_secno = min(sbi->pinned_area_max_secno,
> - MAIN_SECS(sbi) - F2FS_OPTION(sbi).resizable_tail_secno);
> -}
> -
> static void init_once(void *foo)
> {
> struct f2fs_inode_info *fi = (struct f2fs_inode_info *) foo;
> @@ -3103,7 +3092,7 @@ static int __f2fs_remount(struct fs_context *fc, struct super_block *sb)
> sb->s_flags = (sb->s_flags & ~SB_POSIXACL) |
> (test_opt(sbi, POSIX_ACL) ? SB_POSIXACL : 0);
>
> - adjust_pinned_area_boundary(sbi);
> + f2fs_adjust_pinned_area_boundary(sbi);
> limit_reserve_root(sbi);
> fc->sb_flags = (flags & ~SB_LAZYTIME) | (sb->s_flags & SB_LAZYTIME);
>
> @@ -5440,7 +5429,7 @@ static int f2fs_fill_super(struct super_block *sb, struct fs_context *fc)
> /* get segno of first zoned block device */
> sbi->first_seq_zone_segno = get_first_seq_zone_segno(sbi);
>
> - adjust_pinned_area_boundary(sbi);
> + f2fs_adjust_pinned_area_boundary(sbi);
>
> sbi->reserved_pin_section = f2fs_sb_has_blkzoned(sbi) ?
> ZONED_PIN_SEC_REQUIRED_COUNT :
> --
> 2.43.0
>
One minor thing, not introduced by this patch:
free_segment_range() temporarily reduces MAIN_SECS() and relocates
cursegs including CURSEG_COLD_DATA_PINNED, but get_new_segment() still
uses the old pinned_area_max_secno as the upper bound for pinning. So,
when shrinking beyond the reserved tail (or with no tail), the pinned
curseg can be re-allocated inside the range being removed.
e.g. MAIN_SECS = 1000, resizable_tail_secno = 0, shrinking by 100:
MAIN_SECS is temporarily 900, but pinned_area_max_secno is still 1000.
Before c966d29e01bb, MAIN_SECS() was used as the bound, so it was safe.
Could you bound it by MAIN_SECS() in get_new_segment()?
if (pinning) {
- max_secno = sbi->pinned_area_max_secno;
+ max_secno = min(sbi->pinned_area_max_secno, MAIN_SECS(sbi));
hint = 0;
Fixes: c966d29e01bb ("f2fs: support resizable tail section and unify
pinned allocation")
Thanks,
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-10-15 15:49 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-15 8:35 [f2fs-dev] [PATCH v3 0/2] f2fs: fix online resize state Wenjie Qi
2026-10-15 8:35 ` [f2fs-dev] [PATCH v3 1/2] f2fs: flush SIT journal during filesystem resize Wenjie Qi
2026-10-15 8:35 ` [f2fs-dev] [PATCH v3 2/2] f2fs: refresh pinned allocation boundary after resize Wenjie Qi
2026-10-15 15:49 ` Daeho Jeong
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.