Skip to content

Commit b7ff91f

Browse files
zhangyi089tytso
authored andcommitted
ext4: find old entry again if failed to rename whiteout
If we failed to add new entry on rename whiteout, we cannot reset the old->de entry directly, because the old->de could have moved from under us during make indexed dir. So find the old entry again before reset is needed, otherwise it may corrupt the filesystem as below. /dev/sda: Entry '00000001' in ??? (12) has deleted/unused inode 15. CLEARED. /dev/sda: Unattached inode 75 /dev/sda: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY. Fixes: 6b4b8e6 ("ext4: fix bug for rename with RENAME_WHITEOUT") Cc: [email protected] Signed-off-by: zhangyi (F) <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Theodore Ts'o <[email protected]>
1 parent f053cf7 commit b7ff91f

File tree

1 file changed

+27
-2
lines changed

1 file changed

+27
-2
lines changed

fs/ext4/namei.c

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3613,6 +3613,31 @@ static int ext4_setent(handle_t *handle, struct ext4_renament *ent,
36133613
return retval;
36143614
}
36153615

3616+
static void ext4_resetent(handle_t *handle, struct ext4_renament *ent,
3617+
unsigned ino, unsigned file_type)
3618+
{
3619+
struct ext4_renament old = *ent;
3620+
int retval = 0;
3621+
3622+
/*
3623+
* old->de could have moved from under us during make indexed dir,
3624+
* so the old->de may no longer valid and need to find it again
3625+
* before reset old inode info.
3626+
*/
3627+
old.bh = ext4_find_entry(old.dir, &old.dentry->d_name, &old.de, NULL);
3628+
if (IS_ERR(old.bh))
3629+
retval = PTR_ERR(old.bh);
3630+
if (!old.bh)
3631+
retval = -ENOENT;
3632+
if (retval) {
3633+
ext4_std_error(old.dir->i_sb, retval);
3634+
return;
3635+
}
3636+
3637+
ext4_setent(handle, &old, ino, file_type);
3638+
brelse(old.bh);
3639+
}
3640+
36163641
static int ext4_find_delete_entry(handle_t *handle, struct inode *dir,
36173642
const struct qstr *d_name)
36183643
{
@@ -3937,8 +3962,8 @@ static int ext4_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
39373962
end_rename:
39383963
if (whiteout) {
39393964
if (retval) {
3940-
ext4_setent(handle, &old,
3941-
old.inode->i_ino, old_file_type);
3965+
ext4_resetent(handle, &old,
3966+
old.inode->i_ino, old_file_type);
39423967
drop_nlink(whiteout);
39433968
}
39443969
unlock_new_inode(whiteout);

0 commit comments

Comments
 (0)