[PATCH 3/8 v4] vfs: introduce s_op->is_same_inode()

From: Miklos Szeredi
Date: Tue Oct 26 2010 - 06:52:39 EST


From: Miklos Szeredi <mszeredi@xxxxxxx>

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 <mszeredi@xxxxxxx>
---
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@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/