mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-03 18:20:25 +02:00 
			
		
		
		
	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: 6b4b8e6b4a ("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>
			
			
This commit is contained in:
		
							parent
							
								
									f053cf7aa6
								
							
						
					
					
						commit
						b7ff91fd03
					
				
					 1 changed files with 27 additions and 2 deletions
				
			
		| 
						 | 
				
			
			@ -3613,6 +3613,31 @@ static int ext4_setent(handle_t *handle, struct ext4_renament *ent,
 | 
			
		|||
	return retval;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -3937,8 +3962,8 @@ static int ext4_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
 | 
			
		|||
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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue