Skip to content

Commit

Permalink
ext4: find old entry again if failed to rename whiteout
Browse files Browse the repository at this point in the history
commit b7ff91f upstream.

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: stable@vger.kernel.org
Signed-off-by: zhangyi (F) <yi.zhang@huawei.com>
Link: https://lore.kernel.org/r/20210303131703.330415-1-yi.zhang@huawei.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
zhangyi (F) authored and Greg Kroah-Hartman committed Mar 24, 2021
1 parent c615940 commit 1b46d1d
Showing 1 changed file with 27 additions and 2 deletions.
29 changes: 27 additions & 2 deletions fs/ext4/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -3445,6 +3445,31 @@ static int ext4_setent(handle_t *handle, struct ext4_renament *ent,
return 0;
}

static void ext4_resetent(handle_t *handle, struct ext4_renament *ent,
unsigned ino, unsigned file_type)
{
struct ext4_renament old = *ent;
int retval = 0;

/*
* old->de could have moved from under us during make indexed dir,
* so the old->de may no longer valid and need to find it again
* before reset old inode info.
*/
old.bh = ext4_find_entry(old.dir, &old.dentry->d_name, &old.de, NULL);
if (IS_ERR(old.bh))
retval = PTR_ERR(old.bh);
if (!old.bh)
retval = -ENOENT;
if (retval) {
ext4_std_error(old.dir->i_sb, retval);
return;
}

ext4_setent(handle, &old, ino, file_type);
brelse(old.bh);
}

static int ext4_find_delete_entry(handle_t *handle, struct inode *dir,
const struct qstr *d_name)
{
Expand Down Expand Up @@ -3754,8 +3779,8 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
end_rename:
if (whiteout) {
if (retval) {
ext4_setent(handle, &old,
old.inode->i_ino, old_file_type);
ext4_resetent(handle, &old,
old.inode->i_ino, old_file_type);
drop_nlink(whiteout);
}
unlock_new_inode(whiteout);
Expand Down

0 comments on commit 1b46d1d

Please sign in to comment.