make sure that __dentry_kill() always invalidates d_seq, unhashed or not [Linux 4.18]

This Linux kernel change "make sure that __dentry_kill() always invalidates d_seq, unhashed or not" is included in the Linux 4.18 release. This change is authored by Al Viro <viro [at] zeniv.linux.org.uk> on Thu Aug 9 10:15:54 2018 -0400. The commit for this change in Linux stable tree is 4c0d7cd (patch).

make sure that __dentry_kill() always invalidates d_seq, unhashed or not

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" <[email protected]>
Cc: [email protected]
Signed-off-by: Al Viro <[email protected]>

There are 7 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 fs/dcache.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/fs/dcache.c b/fs/dcache.c
index d677290..ceb7b49 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -358,14 +358,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)

Leave a Reply

Your email address will not be published. Required fields are marked *