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