From: Erez Zadok <ezk@xxxxxxxxxxxxx> Signed-off-by: Erez Zadok <ezk@xxxxxxxxxxxxx> Signed-off-by: Josef 'Jeff' Sipek <jsipek@xxxxxxxxxxxxx> --- fs/unionfs/rename.c | 30 ++++++++++++++++++++++++++++-- 1 files changed, 28 insertions(+), 2 deletions(-) diff --git a/fs/unionfs/rename.c b/fs/unionfs/rename.c index 4de984e..f8ea37a 100644 --- a/fs/unionfs/rename.c +++ b/fs/unionfs/rename.c @@ -457,18 +457,44 @@ int unionfs_rename(struct inode *old_dir, struct dentry *old_dentry, } } err = do_unionfs_rename(old_dir, old_dentry, new_dir, new_dentry); - out: if (err) /* clear the new_dentry stuff created */ d_drop(new_dentry); - else + else { /* * force re-lookup since the dir on ro branch is not renamed, * and lower dentries still indicate the un-renamed ones. */ if (S_ISDIR(old_dentry->d_inode->i_mode)) atomic_dec(&UNIONFS_D(old_dentry)->generation); + if (new_dentry->d_inode && + !S_ISDIR(new_dentry->d_inode->i_mode)) { + if (!unionfs_lower_inode(new_dentry->d_inode)) { + /* + * If we get here, it means that no copyup + * was needed, and that a file by the old + * name already existing on the destination + * branch; that file got renamed earlier in + * this function, so all we need to do here + * is set the lower inode. + */ + struct inode *inode; + inode = unionfs_lower_inode( + old_dentry->d_inode); + igrab(inode); + unionfs_set_lower_inode_idx( + new_dentry->d_inode, + dbstart(new_dentry), inode); + } + + } + /* if all of this renaming succeeded, update our times */ + unionfs_copy_attr_times(old_dir); + unionfs_copy_attr_times(new_dir); + unionfs_copy_attr_times(old_dentry->d_inode); + unionfs_copy_attr_times(new_dentry->d_inode); + } unionfs_unlock_dentry(new_dentry); unionfs_unlock_dentry(old_dentry); -- 1.5.2.2.238.g7cbf2f2 - To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html