panic in do_last()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Dave,

I tried to reproduce bug "BUG at mm/filemap.c:202!"
https://lkml.org/lkml/2014/4/15/577 with the attached programs.
I can't reproduce it, but it triggered another bug related to commit  b18825a7c.

commit b18825a7c8e37a7cf6abb97a12a6ad71af160de7
Author: David Howells <dhowells@xxxxxxxxxx>
Date:   Thu Sep 12 19:22:53 2013 +0100

    VFS: Put a small type field into struct dentry::d_flags

[  216.673863] BUG: unable to handle kernel NULL pointer dereference
at           (null)
[  216.674235] IP: [<ffffffff81108961>] do_last.isra.44+0x7d2/0x9ea
[  216.674487] PGD 3d3f0067 PUD 3c82a067 PMD 0
[  216.674853] Oops: 0000 [#1] SMP
[  216.675126] Modules linked in:
[  216.675324] CPU: 1 PID: 30121 Comm: test Not tainted 3.15.0-rc1 #14
[  216.675501] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996),
BIOS Bochs 01/01/2011
[  216.675709] task: ffff88003d1788c0 ti: ffff88003ca84000 task.ti:
ffff88003ca84000
[  216.675906] RIP: 0010:[<ffffffff81108961>]  [<ffffffff81108961>]
do_last.isra.44+0x7d2/0x9ea
[  216.676195] RSP: 0018:ffff88003ca85cf8  EFLAGS: 00010246
[  216.676356] RAX: 0000000000000000 RBX: ffff88003ca85e40 RCX: 0000000000000020
[  216.676547] RDX: 000060ffc00002c0 RSI: 0000000000000101 RDI: ffff88003ca85e40
[  216.676737] RBP: ffff88003ca85d98 R08: ffff88003ca062d0 R09: ffff88003ca062d0
[  216.676933] R10: 2f2f2f2f2f2f2f2f R11: ffffffff81108817 R12: ffff88003ca85dd8
[  216.677123] R13: ffff88003ca3f400 R14: 0000000000000000 R15: ffff88003daba840
[  216.677434] FS:  00007f0453b55700(0000) GS:ffff88003fd00000(0000)
knlGS:0000000000000000
[  216.677808] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  216.677808] CR2: 0000000000000000 CR3: 0000000000047000 CR4: 00000000000006e0
[  216.677808] Stack:
[  216.677808]  ffff88003ca062d0 ffffffff8110576a 00000000000080d0
0000002600000000
[  216.677808]  ffff880000c083c0 ffff88003d1788c0 000081b600005d68
ffff88003ca85f24
[  216.677808]  ffff88003ca85dcc ffff8800010001c0 0100000578742ee8
0000000000000000
[  216.677808] Call Trace:
[  216.677808]  [<ffffffff8110576a>] ? link_path_walk+0x6c/0x739
[  216.677808]  [<ffffffff81108d7c>] path_openat+0x203/0x54b
[  216.677808]  [<ffffffff81109410>] do_filp_open+0x3a/0x8a
[  216.677808]  [<ffffffff8111383d>] ? __alloc_fd+0x60/0xec
[  216.677808]  [<ffffffff810fc334>] do_sys_open+0x14f/0x1de
[  216.677808]  [<ffffffff8110547a>] ? final_putname+0x35/0x39
[  216.677808]  [<ffffffff810fc3e5>] SyS_open+0x22/0x24
[  216.677808]  [<ffffffff81382cd2>] system_call_fastpath+0x16/0x1b

2872 static int do_last(struct nameidata *nd, struct path *path,
....
2993         inode = path->dentry->d_inode;   <---- Here "inode" is NULL
2994 finish_lookup:
2995         /* we _can_ be in RCU mode here */
2996         error = -ENOENT;
2997         if (d_is_negative(path->dentry)) {  <---- But here
"dentry->d_flags" is 0x 400088, so it's positive
2998                 path_to_nameidata(path, nd);
2999                 goto out;
3000         }

To reproduce it:
cc -o test test.c
write.sh &
1.sh &
1.sh &

I modified below code, then it can't be reproduced any more.
But I know it's not the correct fix.

diff --git a/fs/namei.c b/fs/namei.c
index c6157c8..951c6ee 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2994,7 +2994,7 @@ static int do_last(struct nameidata *nd, struct
path *path,
 finish_lookup:
        /* we _can_ be in RCU mode here */
        error = -ENOENT;
-       if (d_is_negative(path->dentry)) {
+      if (!inode) {
                path_to_nameidata(path, nd);
                goto out;
        }

One possibility is there is a race between __d_instantiate() and do_last()

cpu 0: in __d_instantiate()                                  cpu 1: in do_last()

set DCACHE_FILE_TYPE

 inode = path->dentry->d_inode (Didn't see ->d_inode set yet)
dentry->d_inode = inode;

 d_is_negative(path->dentry) (Saw DCACHE_FILE_TYPE set)

So I tried below fix, but it still not work.
Any idea?

diff --git a/fs/dcache.c b/fs/dcache.c
index 40707d8..15b2163 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1647,11 +1647,11 @@ static void __d_instantiate(struct dentry
*dentry, struct inode *inode)
        unsigned add_flags = d_flags_for_inode(inode);

        spin_lock(&dentry->d_lock);
+      dentry->d_inode = inode;
        dentry->d_flags &= ~DCACHE_ENTRY_TYPE;
        dentry->d_flags |= add_flags;
        if (inode)
                hlist_add_head(&dentry->d_alias, &inode->i_dentry);
-       dentry->d_inode = inode;
        dentry_rcuwalk_barrier(dentry);
        spin_unlock(&dentry->d_lock);
        fsnotify_d_instantiate(dentry, inode);

Attachment: 1.sh
Description: Bourne shell script

#include <stdio.h>
#include <stdlib.h>

int main()
{
	int fd;
	char c;
	int ret;

	while (1) {
		fd = open("/mnt/t.txt", 0666);
		if (fd != -1)
			break;
	}

	while (1) {
		ret = read(fd, &c, 1);
		if (ret != -1)
			break;
	}

	printf("%c\n", c);

	return 0;
}

Attachment: write.sh
Description: Bourne shell script


[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux