From: Chuck Lever chuck.lever@oracle.com
mainline inclusion from mainline-v6.10-rc1 commit 23cdd0eed3f1fff3af323092b0b88945a7950d8e bugzilla: https://gitee.com/src-openeuler/kernel/issues/IANSAC
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
--------------------------------
User space expects the replacement (old) directory entry to have the same directory offset after the rename.
Suggested-by: Christian Brauner brauner@kernel.org Fixes: a2e459555c5f ("shmem: stable directory offsets") Signed-off-by: Chuck Lever chuck.lever@oracle.com Link: https://lore.kernel.org/r/20240415152057.4605-2-cel@kernel.org Signed-off-by: Christian Brauner brauner@kernel.org Conflicts: fs/libfs.c [Context differences] Signed-off-by: Yifan Qiao qiaoyifan4@huawei.com --- fs/libfs.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-)
diff --git a/fs/libfs.c b/fs/libfs.c index dc0f7519045f..4e50155d317c 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -291,6 +291,18 @@ int simple_offset_add(struct offset_ctx *octx, struct dentry *dentry) return 0; }
+static int simple_offset_replace(struct offset_ctx *octx, struct dentry *dentry, + long offset) +{ + int ret; + + ret = mtree_store(&octx->mt, offset, dentry, GFP_KERNEL); + if (ret) + return ret; + offset_set(dentry, offset); + return 0; +} + /** * simple_offset_remove - Remove an entry to a directory's offset map * @octx: directory offset ctx to be updated @@ -316,6 +328,9 @@ void simple_offset_remove(struct offset_ctx *octx, struct dentry *dentry) * @new_dir: destination parent * @new_dentry: destination dentry * + * This API preserves the directory offset values. Caller provides + * appropriate serialization. + * * Returns zero on success. Otherwise a negative errno is returned and the * rename is rolled back. */ @@ -333,11 +348,11 @@ int simple_offset_rename_exchange(struct inode *old_dir, simple_offset_remove(old_ctx, old_dentry); simple_offset_remove(new_ctx, new_dentry);
- ret = simple_offset_add(new_ctx, old_dentry); + ret = simple_offset_replace(new_ctx, old_dentry, new_index); if (ret) goto out_restore;
- ret = simple_offset_add(old_ctx, new_dentry); + ret = simple_offset_replace(old_ctx, new_dentry, old_index); if (ret) { simple_offset_remove(new_ctx, old_dentry); goto out_restore; @@ -352,10 +367,8 @@ int simple_offset_rename_exchange(struct inode *old_dir, return 0;
out_restore: - offset_set(old_dentry, old_index); - xa_store(&old_ctx->xa, old_index, old_dentry, GFP_KERNEL); - offset_set(new_dentry, new_index); - xa_store(&new_ctx->xa, new_index, new_dentry, GFP_KERNEL); + (void)simple_offset_replace(old_ctx, old_dentry, old_index); + (void)simple_offset_replace(new_ctx, new_dentry, new_index); return ret; }