Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 15 additions & 25 deletions fs/libfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -344,22 +344,22 @@ void simple_offset_remove(struct offset_ctx *octx, struct dentry *dentry)
* 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.
* Caller must have grabbed a slot for new_dentry in the maple_tree
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment mentions "maple_tree" but the offset_ctx structure in this kernel version uses xarray (xa) not maple_tree. The comment should refer to "xarray" instead to match the actual data structure being used.

Suggested change
* Caller must have grabbed a slot for new_dentry in the maple_tree
* Caller must have grabbed a slot for new_dentry in the xarray

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment mentions "maple_tree" but the offset_ctx structure in this kernel version uses xarray (xa) not maple_tree. The comment should refer to "xarray" instead to match the actual data structure being used.

No.
The linux-stable maintenance policy requires that, when backporting patches, you keep them as close to the original commit as possible — even if the comments no longer match the modified code logic.

* associated with new_dir, even if dentry is negative.
*/
int simple_offset_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry)
void simple_offset_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_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 (WARN_ON(!new_offset))
return;

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);
simple_offset_remove(old_ctx, old_dentry);
offset_set(new_dentry, 0);
WARN_ON(simple_offset_replace(new_ctx, old_dentry, new_offset));
}

/**
Expand All @@ -386,31 +386,21 @@ int simple_offset_rename_exchange(struct inode *old_dir,
u32 new_index = dentry2offset(new_dentry);
int ret;

simple_offset_remove(old_ctx, old_dentry);
simple_offset_remove(new_ctx, new_dentry);
if (WARN_ON(!old_index || !new_index))
return -EINVAL;

ret = simple_offset_replace(new_ctx, old_dentry, new_index);
if (ret)
goto out_restore;
return ret;

ret = simple_offset_replace(old_ctx, new_dentry, old_index);
if (ret) {
simple_offset_remove(new_ctx, old_dentry);
goto out_restore;
simple_offset_replace(new_ctx, new_dentry, new_index);
return ret;
}

ret = simple_rename_exchange(old_dir, old_dentry, new_dir, new_dentry);
if (ret) {
simple_offset_remove(new_ctx, old_dentry);
simple_offset_remove(old_ctx, new_dentry);
goto out_restore;
}
simple_rename_exchange(old_dir, old_dentry, new_dir, new_dentry);
return 0;

out_restore:
(void)simple_offset_replace(old_ctx, old_dentry, old_index);
(void)simple_offset_replace(new_ctx, new_dentry, new_index);
return ret;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion include/linux/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -3306,7 +3306,7 @@ struct offset_ctx {
void simple_offset_init(struct offset_ctx *octx);
int simple_offset_add(struct offset_ctx *octx, struct dentry *dentry);
void simple_offset_remove(struct offset_ctx *octx, struct dentry *dentry);
int simple_offset_rename(struct inode *old_dir, struct dentry *old_dentry,
void simple_offset_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry);
int simple_offset_rename_exchange(struct inode *old_dir,
struct dentry *old_dentry,
Expand Down
18 changes: 13 additions & 5 deletions mm/shmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -3415,6 +3415,7 @@ static int shmem_rename2(struct mnt_idmap *idmap,
{
struct inode *inode = d_inode(old_dentry);
int they_are_dirs = S_ISDIR(inode->i_mode);
bool had_offset = false;
int error;

if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT))
Expand All @@ -3427,16 +3428,23 @@ static int shmem_rename2(struct mnt_idmap *idmap,
if (!simple_empty(new_dentry))
return -ENOTEMPTY;

error = simple_offset_add(shmem_get_offset_ctx(new_dir), new_dentry);
if (error == -EBUSY)
had_offset = true;
else if (unlikely(error))
return error;

if (flags & RENAME_WHITEOUT) {
error = shmem_whiteout(idmap, old_dir, old_dentry);
if (error)
if (error) {
if (!had_offset)
simple_offset_remove(shmem_get_offset_ctx(new_dir),
new_dentry);
return error;
}
}

error = simple_offset_rename(old_dir, old_dentry, new_dir, new_dentry);
if (error)
return error;

simple_offset_rename(old_dir, old_dentry, new_dir, new_dentry);
if (d_really_is_positive(new_dentry)) {
(void) shmem_unlink(new_dir, new_dentry);
if (they_are_dirs) {
Expand Down
Loading