diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index 8c4eafe9ffac..a628782dab8d 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -294,6 +294,17 @@ static bool sanity_check_inode(struct inode *inode, struct folio *node_folio) return false; } + if (unlikely(inode->i_nlink == 0)) { + f2fs_warn(F2FS_I_SB(inode), "%s: inode (ino=%lx) has zero i_nlink", + __func__, inode->i_ino); + return false; + } else if (S_ISDIR(inode->i_mode) && inode->i_nlink == 1) { + f2fs_warn(F2FS_I_SB(inode), "%s: directory inode (ino=%lx) has a single i_nlink", + __func__, inode->i_ino); + return false; + } + + if (f2fs_has_extra_attr(inode)) { if (!f2fs_sb_has_extra_attr(sbi)) { f2fs_warn(sbi, "%s: inode (ino=%lx) is with extra_attr, but extra_attr feature is off", diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index b882771e4699..d13077bad482 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -552,30 +552,31 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry) if (unlikely(f2fs_cp_error(sbi))) { err = -EIO; - goto fail; + goto out; } err = f2fs_dquot_initialize(dir); if (err) - goto fail; + goto out; err = f2fs_dquot_initialize(inode); if (err) - goto fail; + goto out; de = f2fs_find_entry(dir, &dentry->d_name, &folio); if (!de) { if (IS_ERR(folio)) err = PTR_ERR(folio); - goto fail; + goto out; } if (unlikely(inode->i_nlink == 0)) { f2fs_warn(F2FS_I_SB(inode), "%s: inode (ino=%lx) has zero i_nlink", __func__, inode->i_ino); - err = -EFSCORRUPTED; - set_sbi_flag(F2FS_I_SB(inode), SBI_NEED_FSCK); - f2fs_folio_put(folio, false); - goto fail; + goto corrupted; + } else if (S_ISDIR(inode->i_mode) && inode->i_nlink == 1) { + f2fs_warn(F2FS_I_SB(inode), "%s: directory inode (ino=%lx) has a single i_nlink", + __func__, inode->i_ino); + goto corrupted; } f2fs_balance_fs(sbi, true); @@ -585,7 +586,7 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry) if (err) { f2fs_unlock_op(sbi); f2fs_folio_put(folio, false); - goto fail; + goto out; } f2fs_delete_entry(de, folio, dir, inode); f2fs_unlock_op(sbi); @@ -601,7 +602,13 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry) if (IS_DIRSYNC(dir)) f2fs_sync_fs(sbi->sb, 1); -fail: + + goto out; +corrupted: + err = -EFSCORRUPTED; + set_sbi_flag(F2FS_I_SB(inode), SBI_NEED_FSCK); + f2fs_folio_put(folio, false); +out: trace_f2fs_unlink_exit(inode, err); return err; }