| From 4c0d7cd5c8416b1ef41534d19163cb07ffaa03ab Mon Sep 17 00:00:00 2001 |
| From: Al Viro <viro@zeniv.linux.org.uk> |
| Date: Thu, 9 Aug 2018 10:15:54 -0400 |
| Subject: make sure that __dentry_kill() always invalidates d_seq, unhashed or not |
| |
| From: Al Viro <viro@zeniv.linux.org.uk> |
| |
| commit 4c0d7cd5c8416b1ef41534d19163cb07ffaa03ab upstream. |
| |
| RCU pathwalk relies upon the assumption that anything that changes |
| ->d_inode of a dentry will invalidate its ->d_seq. That's almost |
| true - the one exception is that the final dput() of already unhashed |
| dentry does *not* touch ->d_seq at all. Unhashing does, though, |
| so for anything we'd found by RCU dcache lookup we are fine. |
| Unfortunately, we can *start* with an unhashed dentry or jump into |
| it. |
| |
| We could try and be careful in the (few) places where that could |
| happen. Or we could just make the final dput() invalidate the damn |
| thing, unhashed or not. The latter is much simpler and easier to |
| backport, so let's do it that way. |
| |
| Reported-by: "Dae R. Jeong" <threeearcat@gmail.com> |
| Cc: stable@vger.kernel.org |
| Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/dcache.c | 7 ++----- |
| 1 file changed, 2 insertions(+), 5 deletions(-) |
| |
| --- a/fs/dcache.c |
| +++ b/fs/dcache.c |
| @@ -352,14 +352,11 @@ static void dentry_unlink_inode(struct d |
| __releases(dentry->d_inode->i_lock) |
| { |
| struct inode *inode = dentry->d_inode; |
| - bool hashed = !d_unhashed(dentry); |
| |
| - if (hashed) |
| - raw_write_seqcount_begin(&dentry->d_seq); |
| + raw_write_seqcount_begin(&dentry->d_seq); |
| __d_clear_type_and_inode(dentry); |
| hlist_del_init(&dentry->d_u.d_alias); |
| - if (hashed) |
| - raw_write_seqcount_end(&dentry->d_seq); |
| + raw_write_seqcount_end(&dentry->d_seq); |
| spin_unlock(&dentry->d_lock); |
| spin_unlock(&inode->i_lock); |
| if (!inode->i_nlink) |