Re: [PATCH] ext4: fix RENAME_WHITEOUT handling for inline directories

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri 10-02-23 12:32:44, Eric Whitney wrote:
> A significant number of xfstests can cause ext4 to log one or more
> warning messages when they are run on a test file system where the
> inline_data feature has been enabled.  An example:
> 
> "EXT4-fs warning (device vdc): ext4_dirblock_csum_set:425: inode
>  #16385: comm fsstress: No space for directory leaf checksum. Please
> run e2fsck -D."
> 
> The xfstests include: ext4/057, 058, and 307; generic/013, 051, 068,
> 070, 076, 078, 083, 232, 269, 270, 390, 461, 475, 476, 482, 579, 585,
> 589, 626, 631, and 650.
> 
> In this situation, the warning message indicates a bug in the code that
> performs the RENAME_WHITEOUT operation on a directory entry that has
> been stored inline.  It doesn't detect that the directory is stored
> inline, and incorrectly attempts to compute a dirent block checksum on
> the whiteout inode when creating it.  This attempt fails as a result
> of the integrity checking in get_dirent_tail (usually due to a failure
> to match the EXT4_FT_DIR_CSUM magic cookie), and the warning message
> is then emitted.
> 
> Fix this by simply collecting the inlined data state at the time the
> search for the source directory entry is performed.  Existing code
> handles the rest, and this is sufficient to eliminate all spurious
> warning messages produced by the tests above.  Go one step further
> and do the same in the code that resets the source directory entry in
> the event of failure.  The inlined state should be present in the
> "old" struct, but given the possibility of a race there's no harm
> in taking a conservative approach and getting that information again
> since the directory entry is being reread anyway.
> 
> Fixes: b7ff91fd030d ("ext4: find old entry again if failed to rename whiteout")
> 
> Signed-off-by: Eric Whitney <enwlinux@xxxxxxxxx>

Looks good to me. Feel free to add:

Reviewed-by: Jan Kara <jack@xxxxxxx>

								Honza

> ---
>  fs/ext4/namei.c | 13 +++++++------
>  1 file changed, 7 insertions(+), 6 deletions(-)
> 
> diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
> index dd28453d6ea3..924e16b239e0 100644
> --- a/fs/ext4/namei.c
> +++ b/fs/ext4/namei.c
> @@ -1595,11 +1595,10 @@ static struct buffer_head *__ext4_find_entry(struct inode *dir,
>  		int has_inline_data = 1;
>  		ret = ext4_find_inline_entry(dir, fname, res_dir,
>  					     &has_inline_data);
> -		if (has_inline_data) {
> -			if (inlined)
> -				*inlined = 1;
> +		if (inlined)
> +			*inlined = has_inline_data;
> +		if (has_inline_data)
>  			goto cleanup_and_exit;
> -		}
>  	}
>  
>  	if ((namelen <= 2) && (name[0] == '.') &&
> @@ -3646,7 +3645,8 @@ static void ext4_resetent(handle_t *handle, struct ext4_renament *ent,
>  	 * 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);
> +	old.bh = ext4_find_entry(old.dir, &old.dentry->d_name, &old.de,
> +				 &old.inlined);
>  	if (IS_ERR(old.bh))
>  		retval = PTR_ERR(old.bh);
>  	if (!old.bh)
> @@ -3813,7 +3813,8 @@ static int ext4_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
>  			return retval;
>  	}
>  
> -	old.bh = ext4_find_entry(old.dir, &old.dentry->d_name, &old.de, NULL);
> +	old.bh = ext4_find_entry(old.dir, &old.dentry->d_name, &old.de,
> +				 &old.inlined);
>  	if (IS_ERR(old.bh))
>  		return PTR_ERR(old.bh);
>  	/*
> -- 
> 2.30.2
> 
-- 
Jan Kara <jack@xxxxxxxx>
SUSE Labs, CR



[Index of Archives]     [Reiser Filesystem Development]     [Ceph FS]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux FS]     [Yosemite National Park]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Device Mapper]     [Linux Media]

  Powered by Linux