[PATCH 2/2] f2fs: keep released alias devices out of pinned allocation

From: Wenjie Qi

Date: Wed Aug 26 2026 - 09:44:55 EST


Release makes a device alias range free, but a custom alias name prevents
the basename lookup from setting has_alias again after remount. Pinned
allocation can then place immovable blocks on the released device and
prevent a later reserve.

Set has_alias after the persistent inode mapping is committed and before
release frees the range. At mount, restore it from the recorded mapping
and validate the alias inode and any live reserved extent. Keep devices
with suspect mappings blocked from pinned allocation.

Fixes: eae3faf210bd ("f2fs: support dynamic reserve/release for device aliasing")
Signed-off-by: Wenjie Qi <qiwenjie@xxxxxxxxxx>
---
fs/f2fs/file.c | 4 ++++
fs/f2fs/super.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 52 insertions(+)

diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 7f1dc00031ba..10dadde70a13 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -3988,6 +3988,10 @@ static int f2fs_ioc_release_dev_alias(struct file *filp)
if (err)
goto out_inode_unlock;

+ spin_lock(&FREE_I(sbi)->segmap_lock);
+ FDEV(devi).has_alias = true;
+ spin_unlock(&FREE_I(sbi)->segmap_lock);
+
f2fs_down_write_trace(&sbi->gc_lock, &glc);
f2fs_lock_op(sbi, &lc);

diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index c1e315282ec6..3a07d91b41ce 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -5035,6 +5035,21 @@ static void f2fs_tuning_parameters(struct f2fs_sb_info *sbi)
sbi->readdir_ra = true;
}

+static bool f2fs_valid_dev_alias_mapping(struct f2fs_sb_info *sbi,
+ struct inode *inode, int devi)
+{
+ struct extent_info ei;
+
+ if (!IS_DEVICE_ALIASING(inode))
+ return false;
+ if (!F2FS_HAS_BLOCKS(inode))
+ return true;
+ if (!f2fs_lookup_read_extent_cache(inode, 0, &ei))
+ return false;
+ return !ei.fofs && ei.blk == FDEV(devi).start_blk &&
+ ei.len == FDEV(devi).total_segments << sbi->log_blocks_per_seg;
+}
+
static void f2fs_restore_device_alias(struct f2fs_sb_info *sbi)
{
struct inode *root = d_inode(sbi->sb->s_root);
@@ -5045,6 +5060,39 @@ static void f2fs_restore_device_alias(struct f2fs_sb_info *sbi)
if (!f2fs_sb_has_device_alias(sbi))
return;

+ for (i = 1; i < sbi->s_ndevs; i++) {
+ nid_t ino = le32_to_cpu(sbi->raw_super->dev_alias_ino[i]);
+ struct inode *inode;
+ int j;
+
+ if (!ino)
+ continue;
+ FDEV(i).has_alias = true;
+
+ for (j = 0; j < MAX_DEVICES; j++)
+ if (j != i &&
+ le32_to_cpu(sbi->raw_super->dev_alias_ino[j]) == ino)
+ break;
+ if (j < MAX_DEVICES)
+ goto invalid_mapping;
+
+ inode = f2fs_iget(sbi->sb, ino);
+ if (IS_ERR(inode))
+ goto invalid_mapping;
+ if (!f2fs_valid_dev_alias_mapping(sbi, inode, i)) {
+ iput(inode);
+ goto invalid_mapping;
+ }
+ iput(inode);
+ continue;
+
+invalid_mapping:
+ f2fs_warn(sbi,
+ "invalid device alias inode mapping: device=%d, ino=%u",
+ i, ino);
+ set_sbi_flag(sbi, SBI_NEED_FSCK);
+ }
+
for (i = 1; i < sbi->s_ndevs; i++) {
char *name = strrchr(FDEV(i).path, '/');
struct inode *inode;
--
2.43.0