From: Miklos Szeredi rename(2) says: "If oldpath and newpath are existing hard links referring to the same file, then rename() does nothing, and returns a success status." Overlayfs, however, uses dummy inodes and 'old_dentry->d_inode == new_dentry->d_inode' doesn't necessarily mean that they refer to the same file. Introduce a new superblock operation: ->is_same_inode() that returns a boolean value indicating whether the files referred to by the given dentries are the same or not. Export a vfs_is_same_inode() helper so that this can be checked recursively if one of the underlying filesystems is itself an overlayfs (or another fs that uses this service). Signed-off-by: Miklos Szeredi --- fs/namei.c | 17 ++++++++++++++--- include/linux/fs.h | 2 ++ 2 files changed, 16 insertions(+), 3 deletions(-) Index: linux-2.6/fs/namei.c =================================================================== --- linux-2.6.orig/fs/namei.c 2010-10-26 11:29:24.000000000 +0200 +++ linux-2.6/fs/namei.c 2010-10-26 11:29:26.000000000 +0200 @@ -2623,6 +2623,17 @@ static int vfs_rename_other(struct inode return error; } +bool vfs_is_same_inode(struct dentry *d1, struct dentry *d2) +{ + BUG_ON(d1->d_sb != d2->d_sb); + + if (d1->d_sb->s_op->is_same_inode && d1->d_inode && d2->d_inode) + return d1->d_sb->s_op->is_same_inode(d1, d2); + else + return d1->d_inode == d2->d_inode; +} +EXPORT_SYMBOL(vfs_is_same_inode); + int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { @@ -2630,9 +2641,9 @@ int vfs_rename(struct inode *old_dir, st int is_dir = S_ISDIR(old_dentry->d_inode->i_mode); const unsigned char *old_name; - if (old_dentry->d_inode == new_dentry->d_inode) - return 0; - + if (vfs_is_same_inode(old_dentry, new_dentry)) + return 0; + error = may_delete(old_dir, old_dentry, is_dir); if (error) return error; Index: linux-2.6/include/linux/fs.h =================================================================== --- linux-2.6.orig/include/linux/fs.h 2010-10-26 11:29:24.000000000 +0200 +++ linux-2.6/include/linux/fs.h 2010-10-26 11:29:26.000000000 +0200 @@ -1584,6 +1584,7 @@ struct super_operations { ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t); #endif int (*bdev_try_to_free_page)(struct super_block*, struct page*, gfp_t); + bool (*is_same_inode)(struct dentry *, struct dentry *); }; /* @@ -1821,6 +1822,7 @@ extern int vfs_statfs(struct path *, str extern int statfs_by_dentry(struct dentry *, struct kstatfs *); extern int freeze_super(struct super_block *super); extern int thaw_super(struct super_block *super); +extern bool vfs_is_same_inode(struct dentry *d1, struct dentry *d2); extern int current_umask(void); -- -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/