Message ID | 20231122193652.419091-5-viro@zeniv.linux.org.uk (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [1/9] reiserfs: Avoid touching renamed directory if parent does not change | expand |
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@zeniv.linux.org.uk> Looks good to me. Feel free to add: Reviewed-by: Jan Kara <jack@suse.cz> 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 >
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; }
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@zeniv.linux.org.uk> --- fs/ext4/namei.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-)