Commit 0ad8c416 authored by Long Li's avatar Long Li
Browse files

fs:/dcache.c: fix negative dentry flag warning in dentry_free

hulk inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I8WPQW


CVE: NA

--------------------------------

While run xfstests generic/429 on ext4, we get following report:

 WARNING: CPU: 4 PID: 5749 at fs/dcache.c:349 dentry_free.cold+0x20/0x76
 CPU: 4 PID: 5749 Comm: t_encrypted_d_r Not tainted 4.19.90-00004-g0ec2c5ee4e0 #1
 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.12.0-0-ga698c8995f-prebuilt.qemu.org 04/01/2014
 RIP: 0010:dentry_free.cold+0x20/0x76
 RSP: 0018:ffffbc0944a5bdf0 EFLAGS: 00010202
 RAX: 0000000000000024 RBX: ffff955f06e74f30 RCX: 0000000000000000
 RDX: 0000000000000000 RSI: ffff955f3bb168f8 RDI: ffff955f3bb168f8
 RBP: ffff955f06e4c6c0 R08: ffff955f3bb168f8 R09: 0000000000000005
 R10: 0000000000000c27 R11: ffffffffb57d3bad R12: ffff955f06e4c718
 R13: ffff955f06e4c718 R14: ffff955f06e74f30 R15: 0000000000000000
 FS:  00007f4ba0307b40(0000) GS:ffff955f3bb00000(0000) knlGS:0000000000000000
 CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
 CR2: 00007f4b9bcd1ff8 CR3: 0000000123666000 CR4: 00000000000006e0
 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
 Call Trace:
  __dentry_kill+0x219/0x340
  shrink_dentry_list+0xee/0x3e0
  shrink_dcache_parent+0x8c/0xc0
  vfs_rmdir+0x142/0x230
  do_rmdir+0x1c2/0x250
  __x64_sys_rmdir+0x1b/0x30
  do_syscall_64+0xcb/0x370
  entry_SYSCALL_64_after_hwframe+0x5c/0xc1

Look at generic/429 test case, removing the directory and accessing the
file that do not exist in the directory is done concurrently here. Consider
the following concurrent call flow, which triggers the warning of negative
dentry flag in dentry_free(). The root cause of the problem is that lack of
lock protection when determining whether the dentry needs to make a fast
put, it causes that the DCACHE_NEGATIVE_ACCOUNT flag to be set incorrectly.

       rmdir                          stat file
-------------------------     -------------------------
                              fast_dput
                                if (d_flags == (DCACHE_REFERENCED |
                                    DCACHE_LRU_LIST) && !d_unhashed(dentry))

shrink_dentry_list
  spin_lock(&dentry->d_lock)
  d_shrink_del(dentry)
  <clear DCACHE_LRU_LIST>
  __dentry_kill(dentry)
    dentry_unlist(dentry, parent)
    dentry->d_flags &= ~DCACHE_NEGATIVE_ACCOUNT
    <clear DCACHE_NEGATIVE_ACCOUNT>
    spin_unlock(&dentry->d_lock)

                                  spin_lock(&dentry->d_lock)
                                  limit_negative_dentry(dentry)
                                  <set DCACHE_NEGATIVE_ACCOUNT>
                                  spin_unlock(&dentry->d_lock)

    dentry_free(dentry)
      WARN_ON(dentry->d_flags & DCACHE_NEGATIVE_ACCOUNT)

Fix the problem by checking the dentry is dead before set neagtive flag.

Fixes: 0f4e7166 ("fs:/dcache.c: fix negative dentry limit not complete problem")
Signed-off-by: default avatarLong Li <leo.lilong@huawei.com>
parent 3a28772f
Loading
Loading
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment