aboutsummaryrefslogtreecommitdiffstats
path: root/fs/dcache.c
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2014-02-17 17:58:42 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2014-08-07 14:40:10 -0400
commit908790fa3b779d37365e6b28e3aa0f6e833020c3 (patch)
tree60719e471e80dbbf48f984520de7e8f3e22e1a38 /fs/dcache.c
parent75a2352d0110960aeee1a28ddc09a55f97c99100 (diff)
dcache: d_splice_alias mustn't create directory aliases
Currently if d_splice_alias finds a directory with an alias that is not IS_ROOT or not DCACHE_DISCONNECTED, it creates a duplicate directory. Duplicate directory dentries are unacceptable; it is better just to error out. (In the case of a local filesystem the most likely case is filesystem corruption: for example, perhaps two directories point to the same child directory, and the other parent has already been found and cached.) Note that distributed filesystems may encounter this case in normal operation if a remote host moves a directory to a location different from the one we last cached in the dcache. For that reason, such filesystems should instead use d_materialise_unique, which tries to move the old directory alias to the right place instead of erroring out. Signed-off-by: J. Bruce Fields <bfields@redhat.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/dcache.c')
-rw-r--r--fs/dcache.c11
1 files changed, 9 insertions, 2 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index 8c09db9bb2a4..a191eebf1d63 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -2653,6 +2653,9 @@ static void __d_materialise_dentry(struct dentry *dentry, struct dentry *anon)
2653 * DCACHE_DISCONNECTED), then d_move that in place of the given dentry 2653 * DCACHE_DISCONNECTED), then d_move that in place of the given dentry
2654 * and return it, else simply d_add the inode to the dentry and return NULL. 2654 * and return it, else simply d_add the inode to the dentry and return NULL.
2655 * 2655 *
2656 * If a non-IS_ROOT directory is found, the filesystem is corrupt, and
2657 * we should error out: directories can't have multiple aliases.
2658 *
2656 * This is needed in the lookup routine of any filesystem that is exportable 2659 * This is needed in the lookup routine of any filesystem that is exportable
2657 * (via knfsd) so that we can build dcache paths to directories effectively. 2660 * (via knfsd) so that we can build dcache paths to directories effectively.
2658 * 2661 *
@@ -2673,9 +2676,13 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
2673 2676
2674 if (inode && S_ISDIR(inode->i_mode)) { 2677 if (inode && S_ISDIR(inode->i_mode)) {
2675 spin_lock(&inode->i_lock); 2678 spin_lock(&inode->i_lock);
2676 new = __d_find_alias(inode, 1); 2679 new = __d_find_any_alias(inode);
2677 if (new) { 2680 if (new) {
2678 BUG_ON(!(new->d_flags & DCACHE_DISCONNECTED)); 2681 if (!IS_ROOT(new) || !(new->d_flags & DCACHE_DISCONNECTED)) {
2682 spin_unlock(&inode->i_lock);
2683 dput(new);
2684 return ERR_PTR(-EIO);
2685 }
2679 write_seqlock(&rename_lock); 2686 write_seqlock(&rename_lock);
2680 __d_materialise_dentry(dentry, new); 2687 __d_materialise_dentry(dentry, new);
2681 write_sequnlock(&rename_lock); 2688 write_sequnlock(&rename_lock);