diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2015-08-15 14:36:41 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2015-08-21 02:34:37 -0400 |
commit | a03e283bf5c3d4851b4998122196ce9f849e6dfb (patch) | |
tree | 993a15c5162722fa702a490540e8ee374cead082 /fs | |
parent | cde93be45a8a90d8c264c776fab63487b5038a65 (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')
-rw-r--r-- | fs/dcache.c | 7 |
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; |
2746 | out_err: | 2746 | out_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); |