aboutsummaryrefslogtreecommitdiffstats
path: root/fs/dcache.c
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2015-08-15 14:36:41 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2015-08-21 02:34:37 -0400
commita03e283bf5c3d4851b4998122196ce9f849e6dfb (patch)
tree993a15c5162722fa702a490540e8ee374cead082 /fs/dcache.c
parentcde93be45a8a90d8c264c776fab63487b5038a65 (diff)
dcache: Reduce the scope of i_lock in d_splice_alias
i_lock is only needed until __d_find_any_alias calls dget on the alias dentry. After that the reference to new ensures that dentry_kill and d_delete will not remove the inode from the dentry, and remove the dentry from the inode->d_entry list. The inode i_lock came to be held over the the __d_move calls in d_splice_alias through a series of introduction of locks with increasing smaller scope. First it was the dcache_lock, then it was the dcache_inode_lock, and finally inode->i_lock. Furthermore inode->i_lock is not held over any other calls to d_move or __d_move so it can not provide any meaningful rename protection. Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/dcache.c')
-rw-r--r--fs/dcache.c7
1 files changed, 3 insertions, 4 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index e3b44ca75a1b..5c33aeb0f68f 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -2718,7 +2718,7 @@ struct dentry *d_ancestor(struct dentry *p1, struct dentry *p2)
2718 * This helper attempts to cope with remotely renamed directories 2718 * This helper attempts to cope with remotely renamed directories
2719 * 2719 *
2720 * It assumes that the caller is already holding 2720 * It assumes that the caller is already holding
2721 * dentry->d_parent->d_inode->i_mutex, inode->i_lock and rename_lock 2721 * dentry->d_parent->d_inode->i_mutex, and rename_lock
2722 * 2722 *
2723 * Note: If ever the locking in lock_rename() changes, then please 2723 * Note: If ever the locking in lock_rename() changes, then please
2724 * remember to update this too... 2724 * remember to update this too...
@@ -2744,7 +2744,6 @@ out_unalias:
2744 __d_move(alias, dentry, false); 2744 __d_move(alias, dentry, false);
2745 ret = 0; 2745 ret = 0;
2746out_err: 2746out_err:
2747 spin_unlock(&inode->i_lock);
2748 if (m2) 2747 if (m2)
2749 mutex_unlock(m2); 2748 mutex_unlock(m2);
2750 if (m1) 2749 if (m1)
@@ -2790,10 +2789,11 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
2790 if (S_ISDIR(inode->i_mode)) { 2789 if (S_ISDIR(inode->i_mode)) {
2791 struct dentry *new = __d_find_any_alias(inode); 2790 struct dentry *new = __d_find_any_alias(inode);
2792 if (unlikely(new)) { 2791 if (unlikely(new)) {
2792 /* The reference to new ensures it remains an alias */
2793 spin_unlock(&inode->i_lock);
2793 write_seqlock(&rename_lock); 2794 write_seqlock(&rename_lock);
2794 if (unlikely(d_ancestor(new, dentry))) { 2795 if (unlikely(d_ancestor(new, dentry))) {
2795 write_sequnlock(&rename_lock); 2796 write_sequnlock(&rename_lock);
2796 spin_unlock(&inode->i_lock);
2797 dput(new); 2797 dput(new);
2798 new = ERR_PTR(-ELOOP); 2798 new = ERR_PTR(-ELOOP);
2799 pr_warn_ratelimited( 2799 pr_warn_ratelimited(
@@ -2812,7 +2812,6 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
2812 } else { 2812 } else {
2813 __d_move(new, dentry, false); 2813 __d_move(new, dentry, false);
2814 write_sequnlock(&rename_lock); 2814 write_sequnlock(&rename_lock);
2815 spin_unlock(&inode->i_lock);
2816 security_d_instantiate(new, inode); 2815 security_d_instantiate(new, inode);
2817 } 2816 }
2818 iput(inode); 2817 iput(inode);