Re: [PATCH 5/9] ext4: don't access the source subdirectory content on same-directory rename

From: Jan Kara
Date: Thu Nov 23 2023 - 23:19:27 EST


On Wed 22-11-23 19:36:48, Al Viro wrote:
> We can't really afford locking the source on same-directory rename;
> currently vfs_rename() tries to do that, but it will have to be changed.
> The logics in ext4 is lazy and goes looking for ".." in source even in
> same-directory case. It's not hard to get rid of that, leaving that
> behaviour only for cross-directory case; that VFS can get locks safely
> (and will keep doing that after the coming changes).
>
> Signed-off-by: Al Viro <viro@xxxxxxxxxxxxxxxxxx>

Looks good to me. Feel free to add:

Reviewed-by: Jan Kara <jack@xxxxxxx>

Honza

> ---
> fs/ext4/namei.c | 21 +++++++++++++--------
> 1 file changed, 13 insertions(+), 8 deletions(-)
>
> diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
> index d252935f9c8a..467ba47a691c 100644
> --- a/fs/ext4/namei.c
> +++ b/fs/ext4/namei.c
> @@ -3591,10 +3591,14 @@ struct ext4_renament {
> int dir_inlined;
> };
>
> -static int ext4_rename_dir_prepare(handle_t *handle, struct ext4_renament *ent)
> +static int ext4_rename_dir_prepare(handle_t *handle, struct ext4_renament *ent, bool is_cross)
> {
> int retval;
>
> + ent->is_dir = true;
> + if (!is_cross)
> + return 0;
> +
> ent->dir_bh = ext4_get_first_dir_block(handle, ent->inode,
> &retval, &ent->parent_de,
> &ent->dir_inlined);
> @@ -3612,6 +3616,9 @@ static int ext4_rename_dir_finish(handle_t *handle, struct ext4_renament *ent,
> {
> int retval;
>
> + if (!ent->dir_bh)
> + return 0;
> +
> ent->parent_de->inode = cpu_to_le32(dir_ino);
> BUFFER_TRACE(ent->dir_bh, "call ext4_handle_dirty_metadata");
> if (!ent->dir_inlined) {
> @@ -3900,7 +3907,7 @@ static int ext4_rename(struct mnt_idmap *idmap, struct inode *old_dir,
> if (new.dir != old.dir && EXT4_DIR_LINK_MAX(new.dir))
> goto end_rename;
> }
> - retval = ext4_rename_dir_prepare(handle, &old);
> + retval = ext4_rename_dir_prepare(handle, &old, new.dir != old.dir);
> if (retval)
> goto end_rename;
> }
> @@ -3964,7 +3971,7 @@ static int ext4_rename(struct mnt_idmap *idmap, struct inode *old_dir,
> }
> inode_set_mtime_to_ts(old.dir, inode_set_ctime_current(old.dir));
> ext4_update_dx_flag(old.dir);
> - if (old.dir_bh) {
> + if (old.is_dir) {
> retval = ext4_rename_dir_finish(handle, &old, new.dir->i_ino);
> if (retval)
> goto end_rename;
> @@ -3987,7 +3994,7 @@ static int ext4_rename(struct mnt_idmap *idmap, struct inode *old_dir,
> if (unlikely(retval))
> goto end_rename;
>
> - if (S_ISDIR(old.inode->i_mode)) {
> + if (old.is_dir) {
> /*
> * We disable fast commits here that's because the
> * replay code is not yet capable of changing dot dot
> @@ -4114,14 +4121,12 @@ static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
> ext4_handle_sync(handle);
>
> if (S_ISDIR(old.inode->i_mode)) {
> - old.is_dir = true;
> - retval = ext4_rename_dir_prepare(handle, &old);
> + retval = ext4_rename_dir_prepare(handle, &old, new.dir != old.dir);
> if (retval)
> goto end_rename;
> }
> if (S_ISDIR(new.inode->i_mode)) {
> - new.is_dir = true;
> - retval = ext4_rename_dir_prepare(handle, &new);
> + retval = ext4_rename_dir_prepare(handle, &new, new.dir != old.dir);
> if (retval)
> goto end_rename;
> }
> --
> 2.39.2
>
--
Jan Kara <jack@xxxxxxxx>
SUSE Labs, CR