From: Chuck Lever chuck.lever@oracle.com
mainline inclusion from mainline-v6.10-rc1 commit ad191eb6d6942bb835a0b20b647f7c53c1d99ca4 bugzilla: https://gitee.com/src-openeuler/kernel/issues/IANSAC
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
--------------------------------
When renaming onto an existing directory entry, user space expects the replacement entry to have the same directory offset as the original one.
Link: https://gitlab.alpinelinux.org/alpine/aports/-/issues/15966 Fixes: a2e459555c5f ("shmem: stable directory offsets") Signed-off-by: Chuck Lever chuck.lever@oracle.com Link: https://lore.kernel.org/r/20240415152057.4605-4-cel@kernel.org Signed-off-by: Christian Brauner brauner@kernel.org Signed-off-by: Yifan Qiao qiaoyifan4@huawei.com --- fs/libfs.c | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/fs/libfs.c b/fs/libfs.c index 8dd6e0e37e9c..3dea681302a8 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -330,6 +330,9 @@ void simple_offset_remove(struct offset_ctx *octx, struct dentry *dentry) * * Caller provides appropriate serialization. * + * User space expects the directory offset value of the replaced + * (new) directory entry to be unchanged after a rename. + * * Returns zero on success, a negative errno value on failure. */ int simple_offset_rename(struct inode *old_dir, struct dentry *old_dentry, @@ -337,8 +340,14 @@ int simple_offset_rename(struct inode *old_dir, struct dentry *old_dentry, { struct offset_ctx *old_ctx = old_dir->i_op->get_offset_ctx(old_dir); struct offset_ctx *new_ctx = new_dir->i_op->get_offset_ctx(new_dir); + long new_offset = dentry2offset(new_dentry);
simple_offset_remove(old_ctx, old_dentry); + + if (new_offset) { + offset_set(new_dentry, 0); + return simple_offset_replace(new_ctx, old_dentry, new_offset); + } return simple_offset_add(new_ctx, old_dentry); }