[PATCH] f2fs: sync pending discards before reserving device alias
From: Wenjie Qi
Date: Fri Aug 28 2026 - 07:51:33 EST
A released device-alias range can accumulate pending discard
commands. The reserve path then marks the same range valid again
through f2fs_reserve_device_alias() without first synchronizing
those discards.
If the discard thread later submits one of the stale commands,
__check_sit_bitmap() can still see valid blocks in that range and
trigger a BUG.
Synchronize pending discard commands in the alias range before
making it valid again.
Fixes: eae3faf210bd ("f2fs: support dynamic reserve/release for device aliasing")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Wenjie Qi <qiwenjie@xxxxxxxxxx>
---
kernel BUG at fs/f2fs/segment.c:1228!
Oops: invalid opcode: 0000 [#1] SMP DEBUG_PAGEALLOC KASAN PTI
CPU: 1 UID: 0 PID: 79 Comm: f2fs_discard-25
RIP: 0010:__check_sit_bitmap+0x2e1/0x4e0
Call Trace:
__submit_discard_cmd+0x921/0x1140
__issue_discard_cmd+0x524/0x12f0
issue_discard_thread+0x686/0xe20
fs/f2fs/f2fs.h | 2 ++
fs/f2fs/file.c | 1 +
fs/f2fs/segment.c | 9 +++++++++
3 files changed, 12 insertions(+)
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 16720f1f0a9..2b9c6bf310b 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -4067,6 +4067,8 @@ int f2fs_start_discard_thread(struct f2fs_sb_info *sbi);
void f2fs_drop_discard_cmd(struct f2fs_sb_info *sbi);
void f2fs_stop_discard_thread(struct f2fs_sb_info *sbi);
bool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi, bool need_check);
+void f2fs_wait_discard_bios(struct f2fs_sb_info *sbi,
+ block_t blkaddr, unsigned int len);
void f2fs_clear_prefree_segments(struct f2fs_sb_info *sbi,
struct cp_control *cpc);
void f2fs_dirty_to_prefree(struct f2fs_sb_info *sbi);
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index d440231b8cb..58cea2aa314 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -3847,6 +3847,7 @@ static int f2fs_ioc_reserve_dev_alias(struct file *filp)
write_unlock(&et->lock);
clear_inode_flag(inode, FI_NO_EXTENT);
+ f2fs_wait_discard_bios(sbi, ei.blk, ei.len);
f2fs_reserve_device_alias(sbi, ei.blk, ei.len);
i_size_write(inode, (loff_t)ei.len << sbi->log_blocksize);
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index 1e7e745be71..7f4fe8c34c2 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -1916,6 +1916,15 @@ static void f2fs_wait_discard_bio(struct f2fs_sb_info *sbi, block_t blkaddr)
__wait_one_discard_bio(sbi, dc);
}
+void f2fs_wait_discard_bios(struct f2fs_sb_info *sbi,
+ block_t blkaddr, unsigned int len)
+{
+ block_t end = blkaddr + len;
+
+ while (blkaddr < end)
+ f2fs_wait_discard_bio(sbi, blkaddr++);
+}
+
void f2fs_stop_discard_thread(struct f2fs_sb_info *sbi)
{
struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
--
2.43.0