Skip to content

Commit c7df4a1

Browse files
committed
ext4: work around deleting a file with i_nlink == 0 safely
If the file system is corrupted such that a file's i_links_count is too small, then it's possible that when unlinking that file, i_nlink will already be zero. Previously we were working around this kind of corruption by forcing i_nlink to one; but we were doing this before trying to delete the directory entry --- and if the file system is corrupted enough that ext4_delete_entry() fails, then we exit with i_nlink elevated, and this causes the orphan inode list handling to be FUBAR'ed, such that when we unmount the file system, the orphan inode list can get corrupted. A better way to fix this is to simply skip trying to call drop_nlink() if i_nlink is already zero, thus moving the check to the place where it makes the most sense. https://bugzilla.kernel.org/show_bug.cgi?id=205433 Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Theodore Ts'o <[email protected]> Cc: [email protected] Reviewed-by: Andreas Dilger <[email protected]>
1 parent 4ea9993 commit c7df4a1

File tree

1 file changed

+5
-6
lines changed

1 file changed

+5
-6
lines changed

fs/ext4/namei.c

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3196,18 +3196,17 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
31963196
if (IS_DIRSYNC(dir))
31973197
ext4_handle_sync(handle);
31983198

3199-
if (inode->i_nlink == 0) {
3200-
ext4_warning_inode(inode, "Deleting file '%.*s' with no links",
3201-
dentry->d_name.len, dentry->d_name.name);
3202-
set_nlink(inode, 1);
3203-
}
32043199
retval = ext4_delete_entry(handle, dir, de, bh);
32053200
if (retval)
32063201
goto end_unlink;
32073202
dir->i_ctime = dir->i_mtime = current_time(dir);
32083203
ext4_update_dx_flag(dir);
32093204
ext4_mark_inode_dirty(handle, dir);
3210-
drop_nlink(inode);
3205+
if (inode->i_nlink == 0)
3206+
ext4_warning_inode(inode, "Deleting file '%.*s' with no links",
3207+
dentry->d_name.len, dentry->d_name.name);
3208+
else
3209+
drop_nlink(inode);
32113210
if (!inode->i_nlink)
32123211
ext4_orphan_add(handle, inode);
32133212
inode->i_ctime = current_time(inode);

0 commit comments

Comments
 (0)