mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 03:15:31 +09:00
libfs: Fix simple_offset_rename_exchange()
[ Upstream commit 23cdd0eed3f1fff3af323092b0b88945a7950d8e ]
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: a2e459555c ("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>
[ cel: adjusted to apply to origin/linux-6.6.y ]
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
307f68e49d
commit
3e716f31ff
25
fs/libfs.c
25
fs/libfs.c
@@ -294,6 +294,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)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
ret = xa_store(&octx->xa, offset, dentry, GFP_KERNEL);
|
||||
if (xa_is_err(ret))
|
||||
return xa_err(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
|
||||
@@ -351,6 +363,9 @@ int simple_offset_empty(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.
|
||||
*/
|
||||
@@ -368,11 +383,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;
|
||||
@@ -387,10 +402,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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user