summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2018-08-09 10:15:54 -0400
committerBen Hutchings <ben@decadent.org.uk>2018-11-20 18:05:56 +0000
commitc29c4ebd93e047cf3f578adf0e75dc090c90d567 (patch)
tree6f1810ce3322275ae406c85c34933222a9055a48
parentd7a300190970b02642899586d4233cf339f78bf5 (diff)
make sure that __dentry_kill() always invalidates d_seq, unhashed or not
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> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
-rw-r--r--fs/dcache.c7
1 files changed, 2 insertions, 5 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index 4bff38307fd7..c42ae8a079db 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -340,14 +340,11 @@ static void dentry_unlink_inode(struct dentry * dentry)
__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)