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