linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* panic in do_last()
@ 2014-04-18  1:14 Lin Ming
  2014-04-18  1:57 ` Al Viro
  0 siblings, 1 reply; 12+ messages in thread
From: Lin Ming @ 2014-04-18  1:14 UTC (permalink / raw)
  To: David Howells; +Cc: linux-fsdevel, viro, Hugh Dickins

[-- Attachment #1: Type: text/plain, Size: 4577 bytes --]

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@redhat.com>
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 #2: 1.sh --]
[-- Type: application/x-sh, Size: 43 bytes --]

[-- Attachment #3: test.c --]
[-- Type: text/x-csrc, Size: 261 bytes --]

#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 #4: write.sh --]
[-- Type: application/x-sh, Size: 104 bytes --]

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: panic in do_last()
  2014-04-18  1:14 panic in do_last() Lin Ming
@ 2014-04-18  1:57 ` Al Viro
  2014-04-18  2:17   ` Al Viro
       [not found]   ` <CAF1ivSbqM2LorrED3MvgKBDxA9sLz_RkOEPwAfvYYmL5C9K0vA@mail.gmail.com>
  0 siblings, 2 replies; 12+ messages in thread
From: Al Viro @ 2014-04-18  1:57 UTC (permalink / raw)
  To: Lin Ming; +Cc: David Howells, linux-fsdevel, Hugh Dickins

On Thu, Apr 17, 2014 at 06:14:51PM -0700, Lin Ming wrote:
> 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@redhat.com>
> 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

Where is it in do_last()?  Hard to tell without even the hex dump of
oopsing code (and trying to reproduce it here hasn't produced any oopsen
so far).

And your test.c is _really_ weird:

> 		fd = open("/mnt/t.txt", 0666);

Just what is that 0666 doing, in your opinion?  And how is it different
from O_NOCTTY | O_EXCL | O_RDWR (which also makes zero sense)?

And this read() loop is just plain odd - you are leaving it if read(fd, &c, 1)
gives you 0 and proceed to print (uninitialized in that case) value of c...

Anyway, I'd really like to see your .config (or, better yet, disassembly of
do_last) along with the hex dump of oopsing code.  Without that...

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: panic in do_last()
  2014-04-18  1:57 ` Al Viro
@ 2014-04-18  2:17   ` Al Viro
  2014-04-18  2:22     ` Lin Ming
  2014-04-18  2:35     ` Lin Ming
       [not found]   ` <CAF1ivSbqM2LorrED3MvgKBDxA9sLz_RkOEPwAfvYYmL5C9K0vA@mail.gmail.com>
  1 sibling, 2 replies; 12+ messages in thread
From: Al Viro @ 2014-04-18  2:17 UTC (permalink / raw)
  To: Lin Ming; +Cc: David Howells, linux-fsdevel, Hugh Dickins

On Fri, Apr 18, 2014 at 02:57:50AM +0100, Al Viro wrote:

> Where is it in do_last()?  Hard to tell without even the hex dump of
> oopsing code (and trying to reproduce it here hasn't produced any oopsen
> so far).

Hmm...  Still no oopsen, but it looks like it *is* possible to get
screwed there.  RCU mode isn't a problem, AFAICS (we'll fail on d_seq
mismatch in complete_walk() and that will be the end of it), but
non-lazy mode *can* get buggered.  We are holding a reference to
nd->path.dentry and that's enough to prevent positive-to-negative
transition, but negative-to-positive is fair game.  So it does
happen and we end up with nd->inode being set to NULL.  And _that_
promptly blows up on
        if (!S_ISREG(nd->inode->i_mode))
                will_truncate = false;
Actually, it might very well be the only source of breakage - that late
in the game (already out of RCU mode, for starters) we don't give a damn
about nd->inode.

Ah, actually there's also
                BUG_ON(inode != path->dentry->d_inode);
in symlink case (similar "negative to positive", but it will be a symlink(2),
not creat(2)).  Pointless BUG_ON, actually...

The reason why your reordering hadn't done any good is that CPU cache is free
to reorder behind your back - no barriers between these two stores.

I'd still like the disassembly of your do_last() and the missing hex dump...

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: panic in do_last()
  2014-04-18  2:17   ` Al Viro
@ 2014-04-18  2:22     ` Lin Ming
  2014-04-18  2:35     ` Lin Ming
  1 sibling, 0 replies; 12+ messages in thread
From: Lin Ming @ 2014-04-18  2:22 UTC (permalink / raw)
  To: Al Viro; +Cc: David Howells, linux-fsdevel, Hugh Dickins

[-- Attachment #1: Type: text/plain, Size: 242 bytes --]

On Thu, Apr 17, 2014 at 7:17 PM, Al Viro <viro@zeniv.linux.org.uk> wrote:
> I'd still like the disassembly of your do_last() and the missing hex dump...

disassmebly of do_last() attached.
the missing hex dump should be in previous panic.log

[-- Attachment #2: do_last.S --]
[-- Type: application/octet-stream, Size: 73085 bytes --]


vmlinux:     file format elf64-x86-64


Disassembly of section .text:

ffffffff81108dd3 <do_last.isra.44>:
}

/*
 * Handle the last step of open()
 */
static int do_last(struct nameidata *nd, struct path *path,
ffffffff81108dd3:	e8 68 a7 27 00       	callq  ffffffff81383540 <__fentry__>
ffffffff81108dd8:	55                   	push   %rbp
ffffffff81108dd9:	48 89 e5             	mov    %rsp,%rbp
ffffffff81108ddc:	41 57                	push   %r15
ffffffff81108dde:	41 56                	push   %r14
ffffffff81108de0:	41 55                	push   %r13
ffffffff81108de2:	49 89 d5             	mov    %rdx,%r13
ffffffff81108de5:	41 54                	push   %r12
ffffffff81108de7:	49 89 f4             	mov    %rsi,%r12
ffffffff81108dea:	53                   	push   %rbx
ffffffff81108deb:	48 89 fb             	mov    %rdi,%rbx
ffffffff81108dee:	48 83 ec 78          	sub    $0x78,%rsp
		   struct file *file, const struct open_flags *op,
		   int *opened, struct filename *name)
{
	struct dentry *dir = nd->path.dentry;
	int open_flag = op->open_flag;
ffffffff81108df2:	8b 11                	mov    (%rcx),%edx
 */
static int do_last(struct nameidata *nd, struct path *path,
		   struct file *file, const struct open_flags *op,
		   int *opened, struct filename *name)
{
	struct dentry *dir = nd->path.dentry;
ffffffff81108df4:	48 8b 47 08          	mov    0x8(%rdi),%rax
}

/*
 * Handle the last step of open()
 */
static int do_last(struct nameidata *nd, struct path *path,
ffffffff81108df8:	48 89 4d 98          	mov    %rcx,-0x68(%rbp)
ffffffff81108dfc:	4c 89 45 a0          	mov    %r8,-0x60(%rbp)
	bool will_truncate = (open_flag & O_TRUNC) != 0;
	bool got_write = false;
	int acc_mode = op->acc_mode;
	struct inode *inode;
	bool symlink_ok = false;
	struct path save_parent = { .dentry = NULL, .mnt = NULL };
ffffffff81108e00:	48 c7 45 c0 00 00 00 	movq   $0x0,-0x40(%rbp)
ffffffff81108e07:	00 
ffffffff81108e08:	48 c7 45 c8 00 00 00 	movq   $0x0,-0x38(%rbp)
ffffffff81108e0f:	00 
 */
static int do_last(struct nameidata *nd, struct path *path,
		   struct file *file, const struct open_flags *op,
		   int *opened, struct filename *name)
{
	struct dentry *dir = nd->path.dentry;
ffffffff81108e10:	48 89 45 80          	mov    %rax,-0x80(%rbp)
	int open_flag = op->open_flag;
	bool will_truncate = (open_flag & O_TRUNC) != 0;
ffffffff81108e14:	89 d0                	mov    %edx,%eax
static int do_last(struct nameidata *nd, struct path *path,
		   struct file *file, const struct open_flags *op,
		   int *opened, struct filename *name)
{
	struct dentry *dir = nd->path.dentry;
	int open_flag = op->open_flag;
ffffffff81108e16:	89 55 94             	mov    %edx,-0x6c(%rbp)
	bool will_truncate = (open_flag & O_TRUNC) != 0;
ffffffff81108e19:	c1 e8 09             	shr    $0x9,%eax
	int error;

	nd->flags &= ~LOOKUP_PARENT;
	nd->flags |= op->intent;

	if (nd->last_type != LAST_NORM) {
ffffffff81108e1c:	8b 57 44             	mov    0x44(%rdi),%edx
		   struct file *file, const struct open_flags *op,
		   int *opened, struct filename *name)
{
	struct dentry *dir = nd->path.dentry;
	int open_flag = op->open_flag;
	bool will_truncate = (open_flag & O_TRUNC) != 0;
ffffffff81108e1f:	83 e0 01             	and    $0x1,%eax
ffffffff81108e22:	88 45 aa             	mov    %al,-0x56(%rbp)
	bool got_write = false;
	int acc_mode = op->acc_mode;
ffffffff81108e25:	8b 41 08             	mov    0x8(%rcx),%eax
ffffffff81108e28:	89 85 7c ff ff ff    	mov    %eax,-0x84(%rbp)
	bool symlink_ok = false;
	struct path save_parent = { .dentry = NULL, .mnt = NULL };
	bool retried = false;
	int error;

	nd->flags &= ~LOOKUP_PARENT;
ffffffff81108e2e:	8b 47 38             	mov    0x38(%rdi),%eax
ffffffff81108e31:	83 e0 ef             	and    $0xffffffef,%eax
ffffffff81108e34:	89 47 38             	mov    %eax,0x38(%rdi)
	nd->flags |= op->intent;
ffffffff81108e37:	0b 41 0c             	or     0xc(%rcx),%eax

	if (nd->last_type != LAST_NORM) {
ffffffff81108e3a:	85 d2                	test   %edx,%edx
	struct path save_parent = { .dentry = NULL, .mnt = NULL };
	bool retried = false;
	int error;

	nd->flags &= ~LOOKUP_PARENT;
	nd->flags |= op->intent;
ffffffff81108e3c:	89 47 38             	mov    %eax,0x38(%rdi)

	if (nd->last_type != LAST_NORM) {
ffffffff81108e3f:	74 29                	je     ffffffff81108e6a <do_last.isra.44+0x97>
	return inode_permission(nd->inode, MAY_EXEC);
}

static inline int handle_dots(struct nameidata *nd, int type)
{
	if (type == LAST_DOTDOT) {
ffffffff81108e41:	83 fa 03             	cmp    $0x3,%edx
ffffffff81108e44:	0f 85 0c 09 00 00    	jne    ffffffff81109756 <do_last.isra.44+0x983>
		if (nd->flags & LOOKUP_RCU) {
ffffffff81108e4a:	a8 40                	test   $0x40,%al
ffffffff81108e4c:	74 12                	je     ffffffff81108e60 <do_last.isra.44+0x8d>
			if (follow_dotdot_rcu(nd))
ffffffff81108e4e:	e8 d8 c0 ff ff       	callq  ffffffff81104f2b <follow_dotdot_rcu>
ffffffff81108e53:	85 c0                	test   %eax,%eax
ffffffff81108e55:	0f 85 f3 08 00 00    	jne    ffffffff8110974e <do_last.isra.44+0x97b>
ffffffff81108e5b:	e9 f6 08 00 00       	jmpq   ffffffff81109756 <do_last.isra.44+0x983>
				return -ECHILD;
		} else
			follow_dotdot(nd);
ffffffff81108e60:	e8 16 c5 ff ff       	callq  ffffffff8110537b <follow_dotdot>
ffffffff81108e65:	e9 ec 08 00 00       	jmpq   ffffffff81109756 <do_last.isra.44+0x983>
		if (error)
			return error;
		goto finish_open;
	}

	if (!(open_flag & O_CREAT)) {
ffffffff81108e6a:	f6 45 94 40          	testb  $0x40,-0x6c(%rbp)
ffffffff81108e6e:	75 64                	jne    ffffffff81108ed4 <do_last.isra.44+0x101>
		if (nd->last.name[nd->last.len])
ffffffff81108e70:	8b 57 14             	mov    0x14(%rdi),%edx
ffffffff81108e73:	48 8b 4f 18          	mov    0x18(%rdi),%rcx
ffffffff81108e77:	80 3c 11 00          	cmpb   $0x0,(%rcx,%rdx,1)
ffffffff81108e7b:	74 06                	je     ffffffff81108e83 <do_last.isra.44+0xb0>
			nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
ffffffff81108e7d:	83 c8 03             	or     $0x3,%eax
ffffffff81108e80:	89 47 38             	mov    %eax,0x38(%rdi)
		if (open_flag & O_PATH && !(nd->flags & LOOKUP_FOLLOW))
ffffffff81108e83:	f7 45 94 00 00 20 00 	testl  $0x200000,-0x6c(%rbp)
	int open_flag = op->open_flag;
	bool will_truncate = (open_flag & O_TRUNC) != 0;
	bool got_write = false;
	int acc_mode = op->acc_mode;
	struct inode *inode;
	bool symlink_ok = false;
ffffffff81108e8a:	c6 45 93 00          	movb   $0x0,-0x6d(%rbp)
	}

	if (!(open_flag & O_CREAT)) {
		if (nd->last.name[nd->last.len])
			nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
		if (open_flag & O_PATH && !(nd->flags & LOOKUP_FOLLOW))
ffffffff81108e8e:	74 0f                	je     ffffffff81108e9f <do_last.isra.44+0xcc>
ffffffff81108e90:	8b 43 38             	mov    0x38(%rbx),%eax
ffffffff81108e93:	83 e0 01             	and    $0x1,%eax
ffffffff81108e96:	83 f0 01             	xor    $0x1,%eax
ffffffff81108e99:	83 e0 01             	and    $0x1,%eax
ffffffff81108e9c:	88 45 93             	mov    %al,-0x6d(%rbp)
			symlink_ok = true;
		/* we _can_ be in RCU mode here */
		error = lookup_fast(nd, path, &inode);
ffffffff81108e9f:	48 8d 55 b8          	lea    -0x48(%rbp),%rdx
ffffffff81108ea3:	4c 89 e6             	mov    %r12,%rsi
ffffffff81108ea6:	48 89 df             	mov    %rbx,%rdi
ffffffff81108ea9:	e8 eb cc ff ff       	callq  ffffffff81105b99 <lookup_fast>
		if (likely(!error))
ffffffff81108eae:	83 f8 00             	cmp    $0x0,%eax
		if (nd->last.name[nd->last.len])
			nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
		if (open_flag & O_PATH && !(nd->flags & LOOKUP_FOLLOW))
			symlink_ok = true;
		/* we _can_ be in RCU mode here */
		error = lookup_fast(nd, path, &inode);
ffffffff81108eb1:	41 89 c6             	mov    %eax,%r14d
	bool got_write = false;
	int acc_mode = op->acc_mode;
	struct inode *inode;
	bool symlink_ok = false;
	struct path save_parent = { .dentry = NULL, .mnt = NULL };
	bool retried = false;
ffffffff81108eb4:	c6 45 92 00          	movb   $0x0,-0x6e(%rbp)
			nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
		if (open_flag & O_PATH && !(nd->flags & LOOKUP_FOLLOW))
			symlink_ok = true;
		/* we _can_ be in RCU mode here */
		error = lookup_fast(nd, path, &inode);
		if (likely(!error))
ffffffff81108eb8:	0f 84 9d 05 00 00    	je     ffffffff8110945b <do_last.isra.44+0x688>
			goto finish_lookup;

		if (error < 0)
ffffffff81108ebe:	0f 8c f5 07 00 00    	jl     ffffffff811096b9 <do_last.isra.44+0x8e6>
			goto out;

		BUG_ON(nd->inode != dir->d_inode);
ffffffff81108ec4:	48 8b 45 80          	mov    -0x80(%rbp),%rax
ffffffff81108ec8:	48 8b 40 30          	mov    0x30(%rax),%rax
ffffffff81108ecc:	48 39 43 30          	cmp    %rax,0x30(%rbx)
ffffffff81108ed0:	74 32                	je     ffffffff81108f04 <do_last.isra.44+0x131>
ffffffff81108ed2:	0f 0b                	ud2    
		/*
		 * This will *only* deal with leaving RCU mode - LOOKUP_JUMPED
		 * has been cleared when we got to the last component we are
		 * about to look up
		 */
		error = complete_walk(nd);
ffffffff81108ed4:	e8 d8 c1 ff ff       	callq  ffffffff811050b1 <complete_walk>
		if (error)
ffffffff81108ed9:	85 c0                	test   %eax,%eax
		/*
		 * This will *only* deal with leaving RCU mode - LOOKUP_JUMPED
		 * has been cleared when we got to the last component we are
		 * about to look up
		 */
		error = complete_walk(nd);
ffffffff81108edb:	41 89 c6             	mov    %eax,%r14d
		if (error)
ffffffff81108ede:	0f 85 c7 08 00 00    	jne    ffffffff811097ab <do_last.isra.44+0x9d8>
			return error;

		audit_inode(name, dir, LOOKUP_PARENT);
		error = -EISDIR;
		/* trailing slashes? */
		if (nd->last.name[nd->last.len])
ffffffff81108ee4:	8b 43 14             	mov    0x14(%rbx),%eax
ffffffff81108ee7:	48 8b 53 18          	mov    0x18(%rbx),%rdx
ffffffff81108eeb:	80 3c 02 00          	cmpb   $0x0,(%rdx,%rax,1)
ffffffff81108eef:	74 0b                	je     ffffffff81108efc <do_last.isra.44+0x129>
		error = complete_walk(nd);
		if (error)
			return error;

		audit_inode(name, dir, LOOKUP_PARENT);
		error = -EISDIR;
ffffffff81108ef1:	41 be eb ff ff ff    	mov    $0xffffffeb,%r14d
ffffffff81108ef7:	e9 bd 07 00 00       	jmpq   ffffffff811096b9 <do_last.isra.44+0x8e6>
	bool got_write = false;
	int acc_mode = op->acc_mode;
	struct inode *inode;
	bool symlink_ok = false;
	struct path save_parent = { .dentry = NULL, .mnt = NULL };
	bool retried = false;
ffffffff81108efc:	c6 45 92 00          	movb   $0x0,-0x6e(%rbp)
	int open_flag = op->open_flag;
	bool will_truncate = (open_flag & O_TRUNC) != 0;
	bool got_write = false;
	int acc_mode = op->acc_mode;
	struct inode *inode;
	bool symlink_ok = false;
ffffffff81108f00:	c6 45 93 00          	movb   $0x0,-0x6d(%rbp)
		if (nd->last.name[nd->last.len])
			goto out;
	}

retry_lookup:
	if (op->open_flag & (O_CREAT | O_TRUNC | O_WRONLY | O_RDWR)) {
ffffffff81108f04:	48 8b 55 98          	mov    -0x68(%rbp),%rdx
ffffffff81108f08:	c6 45 ab 00          	movb   $0x0,-0x55(%rbp)
ffffffff81108f0c:	f7 02 43 02 00 00    	testl  $0x243,(%rdx)
ffffffff81108f12:	74 0e                	je     ffffffff81108f22 <do_last.isra.44+0x14f>
		error = mnt_want_write(nd->path.mnt);
ffffffff81108f14:	48 8b 3b             	mov    (%rbx),%rdi
ffffffff81108f17:	e8 2c d2 00 00       	callq  ffffffff81116148 <mnt_want_write>
		if (!error)
ffffffff81108f1c:	85 c0                	test   %eax,%eax
ffffffff81108f1e:	0f 94 45 ab          	sete   -0x55(%rbp)
		 * do _not_ fail yet - we might not need that or fail with
		 * a different error; let lookup_open() decide; we'll be
		 * dropping this one anyway.
		 */
	}
	mutex_lock(&dir->d_inode->i_mutex);
ffffffff81108f22:	48 8b 45 80          	mov    -0x80(%rbp),%rax
ffffffff81108f26:	48 8b 40 30          	mov    0x30(%rax),%rax
ffffffff81108f2a:	48 89 c7             	mov    %rax,%rdi
ffffffff81108f2d:	48 81 c7 a0 00 00 00 	add    $0xa0,%rdi
ffffffff81108f34:	e8 7e 8b 27 00       	callq  ffffffff81381ab7 <mutex_lock>
static int lookup_open(struct nameidata *nd, struct path *path,
			struct file *file,
			const struct open_flags *op,
			bool got_write, int *opened)
{
	struct dentry *dir = nd->path.dentry;
ffffffff81108f39:	4c 8b 73 08          	mov    0x8(%rbx),%r14
	struct inode *dir_inode = dir->d_inode;
	struct dentry *dentry;
	int error;
	bool need_lookup;

	*opened &= ~FILE_CREATED;
ffffffff81108f3d:	48 8b 55 a0          	mov    -0x60(%rbp),%rdx
	dentry = lookup_dcache(&nd->last, dir, nd->flags, &need_lookup);
ffffffff81108f41:	48 8d 7b 10          	lea    0x10(%rbx),%rdi
ffffffff81108f45:	48 8d 4d b7          	lea    -0x49(%rbp),%rcx
			struct file *file,
			const struct open_flags *op,
			bool got_write, int *opened)
{
	struct dentry *dir = nd->path.dentry;
	struct inode *dir_inode = dir->d_inode;
ffffffff81108f49:	4d 8b 46 30          	mov    0x30(%r14),%r8
	struct dentry *dentry;
	int error;
	bool need_lookup;

	*opened &= ~FILE_CREATED;
ffffffff81108f4d:	83 22 fe             	andl   $0xfffffffe,(%rdx)
	dentry = lookup_dcache(&nd->last, dir, nd->flags, &need_lookup);
ffffffff81108f50:	4c 89 f6             	mov    %r14,%rsi
ffffffff81108f53:	8b 53 38             	mov    0x38(%rbx),%edx
ffffffff81108f56:	4c 89 85 60 ff ff ff 	mov    %r8,-0xa0(%rbp)
ffffffff81108f5d:	e8 50 c8 ff ff       	callq  ffffffff811057b2 <lookup_dcache>
	if (IS_ERR(dentry))
ffffffff81108f62:	48 3d 00 f0 ff ff    	cmp    $0xfffffffffffff000,%rax
	struct dentry *dentry;
	int error;
	bool need_lookup;

	*opened &= ~FILE_CREATED;
	dentry = lookup_dcache(&nd->last, dir, nd->flags, &need_lookup);
ffffffff81108f68:	49 89 c7             	mov    %rax,%r15
	if (IS_ERR(dentry))
ffffffff81108f6b:	4c 8b 85 60 ff ff ff 	mov    -0xa0(%rbp),%r8
ffffffff81108f72:	76 05                	jbe    ffffffff81108f79 <do_last.isra.44+0x1a6>
ffffffff81108f74:	e9 61 03 00 00       	jmpq   ffffffff811092da <do_last.isra.44+0x507>
		return PTR_ERR(dentry);

	/* Cached positive dentry: will open in f_op->open */
	if (!need_lookup && dentry->d_inode)
ffffffff81108f79:	8a 45 b7             	mov    -0x49(%rbp),%al
ffffffff81108f7c:	84 c0                	test   %al,%al
ffffffff81108f7e:	88 45 a9             	mov    %al,-0x57(%rbp)
ffffffff81108f81:	75 0b                	jne    ffffffff81108f8e <do_last.isra.44+0x1bb>
ffffffff81108f83:	49 83 7f 30 00       	cmpq   $0x0,0x30(%r15)
ffffffff81108f88:	0f 85 b7 03 00 00    	jne    ffffffff81109345 <do_last.isra.44+0x572>
		goto out_no_open;

	if ((nd->flags & LOOKUP_OPEN) && dir_inode->i_op->atomic_open) {
ffffffff81108f8e:	8b 53 38             	mov    0x38(%rbx),%edx
ffffffff81108f91:	f6 c6 01             	test   $0x1,%dh
ffffffff81108f94:	0f 84 1b 03 00 00    	je     ffffffff811092b5 <do_last.isra.44+0x4e2>
ffffffff81108f9a:	49 8b 40 20          	mov    0x20(%r8),%rax
ffffffff81108f9e:	48 83 b8 b8 00 00 00 	cmpq   $0x0,0xb8(%rax)
ffffffff81108fa5:	00 
ffffffff81108fa6:	0f 84 09 03 00 00    	je     ffffffff811092b5 <do_last.isra.44+0x4e2>
			struct path *path, struct file *file,
			const struct open_flags *op,
			bool got_write, bool need_lookup,
			int *opened)
{
	struct inode *dir =  nd->path.dentry->d_inode;
ffffffff81108fac:	48 8b 43 08          	mov    0x8(%rbx),%rax
	unsigned open_flag = open_to_namei_flags(op->open_flag);
ffffffff81108fb0:	48 8b 55 98          	mov    -0x68(%rbp),%rdx
			struct path *path, struct file *file,
			const struct open_flags *op,
			bool got_write, bool need_lookup,
			int *opened)
{
	struct inode *dir =  nd->path.dentry->d_inode;
ffffffff81108fb4:	48 8b 40 30          	mov    0x30(%rax),%rax
	unsigned open_flag = open_to_namei_flags(op->open_flag);
ffffffff81108fb8:	44 8b 32             	mov    (%rdx),%r14d
			struct path *path, struct file *file,
			const struct open_flags *op,
			bool got_write, bool need_lookup,
			int *opened)
{
	struct inode *dir =  nd->path.dentry->d_inode;
ffffffff81108fbb:	48 89 45 88          	mov    %rax,-0x78(%rbp)
	return error;
}

static inline int open_to_namei_flags(int flag)
{
	if ((flag & O_ACCMODE) == 3)
ffffffff81108fbf:	44 89 f0             	mov    %r14d,%eax
ffffffff81108fc2:	83 e0 03             	and    $0x3,%eax
		flag--;
ffffffff81108fc5:	83 f8 03             	cmp    $0x3,%eax
ffffffff81108fc8:	0f 94 c0             	sete   %al
ffffffff81108fcb:	0f b6 c0             	movzbl %al,%eax
ffffffff81108fce:	41 29 c6             	sub    %eax,%r14d
	int acc_mode;
	int create_error = 0;
	struct dentry *const DENTRY_NOT_SET = (void *) -1UL;
	bool excl;

	BUG_ON(dentry->d_inode);
ffffffff81108fd1:	49 83 7f 30 00       	cmpq   $0x0,0x30(%r15)
ffffffff81108fd6:	74 02                	je     ffffffff81108fda <do_last.isra.44+0x207>
ffffffff81108fd8:	0f 0b                	ud2    

	/* Don't create child dentry for a dead directory. */
	if (unlikely(IS_DEADDIR(dir))) {
ffffffff81108fda:	48 8b 45 88          	mov    -0x78(%rbp),%rax
ffffffff81108fde:	f6 40 0c 10          	testb  $0x10,0xc(%rax)
ffffffff81108fe2:	0f 85 3d 02 00 00    	jne    ffffffff81109225 <do_last.isra.44+0x452>
		error = -ENOENT;
		goto out;
	}

	mode = op->mode;
ffffffff81108fe8:	48 8b 55 98          	mov    -0x68(%rbp),%rdx
	if ((open_flag & O_CREAT) && !IS_POSIXACL(dir))
ffffffff81108fec:	41 f6 c6 40          	test   $0x40,%r14b
	if (unlikely(IS_DEADDIR(dir))) {
		error = -ENOENT;
		goto out;
	}

	mode = op->mode;
ffffffff81108ff0:	8b 52 04             	mov    0x4(%rdx),%edx
ffffffff81108ff3:	66 89 55 90          	mov    %dx,-0x70(%rbp)
	if ((open_flag & O_CREAT) && !IS_POSIXACL(dir))
ffffffff81108ff7:	74 15                	je     ffffffff8110900e <do_last.isra.44+0x23b>
ffffffff81108ff9:	48 8b 40 28          	mov    0x28(%rax),%rax
ffffffff81108ffd:	f6 40 52 01          	testb  $0x1,0x52(%rax)
ffffffff81109001:	75 0b                	jne    ffffffff8110900e <do_last.isra.44+0x23b>
		mode &= ~current_umask();
ffffffff81109003:	e8 c0 a5 01 00       	callq  ffffffff811235c8 <current_umask>
ffffffff81109008:	f7 d0                	not    %eax
ffffffff8110900a:	66 21 45 90          	and    %ax,-0x70(%rbp)

	excl = (open_flag & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT);
ffffffff8110900e:	44 89 f0             	mov    %r14d,%eax
ffffffff81109011:	25 c0 00 00 00       	and    $0xc0,%eax
ffffffff81109016:	3d c0 00 00 00       	cmp    $0xc0,%eax
	if (excl)
		open_flag &= ~O_TRUNC;
ffffffff8110901b:	44 89 f0             	mov    %r14d,%eax

	mode = op->mode;
	if ((open_flag & O_CREAT) && !IS_POSIXACL(dir))
		mode &= ~current_umask();

	excl = (open_flag & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT);
ffffffff8110901e:	0f 94 45 a8          	sete   -0x58(%rbp)
	if (excl)
		open_flag &= ~O_TRUNC;
ffffffff81109022:	80 e4 fd             	and    $0xfd,%ah
ffffffff81109025:	80 7d a8 00          	cmpb   $0x0,-0x58(%rbp)
ffffffff81109029:	44 0f 45 f0          	cmovne %eax,%r14d
ffffffff8110902d:	44 89 75 ac          	mov    %r14d,-0x54(%rbp)
	 * to check access and if not granted clear O_CREAT from the flags.
	 *
	 * Another problem is returing the "right" error value (e.g. for an
	 * O_EXCL open we want to return EEXIST not EROFS).
	 */
	if (((open_flag & (O_CREAT | O_TRUNC)) ||
ffffffff81109031:	41 81 e6 43 02 00 00 	and    $0x243,%r14d
	struct inode *dir =  nd->path.dentry->d_inode;
	unsigned open_flag = open_to_namei_flags(op->open_flag);
	umode_t mode;
	int error;
	int acc_mode;
	int create_error = 0;
ffffffff81109038:	41 be 00 00 00 00    	mov    $0x0,%r14d
	 * to check access and if not granted clear O_CREAT from the flags.
	 *
	 * Another problem is returing the "right" error value (e.g. for an
	 * O_EXCL open we want to return EEXIST not EROFS).
	 */
	if (((open_flag & (O_CREAT | O_TRUNC)) ||
ffffffff8110903e:	74 27                	je     ffffffff81109067 <do_last.isra.44+0x294>
	    (open_flag & O_ACCMODE) != O_RDONLY) && unlikely(!got_write)) {
ffffffff81109040:	80 7d ab 00          	cmpb   $0x0,-0x55(%rbp)
ffffffff81109044:	75 21                	jne    ffffffff81109067 <do_last.isra.44+0x294>
		if (!(open_flag & O_CREAT)) {
ffffffff81109046:	f6 45 ac 40          	testb  $0x40,-0x54(%rbp)
ffffffff8110904a:	0f 84 f9 01 00 00    	je     ffffffff81109249 <do_last.isra.44+0x476>
			/*
			 * No O_CREATE -> atomicity not a requirement -> fall
			 * back to lookup + open
			 */
			goto no_open;
		} else if (open_flag & (O_EXCL | O_TRUNC)) {
ffffffff81109050:	f7 45 ac 80 02 00 00 	testl  $0x280,-0x54(%rbp)
ffffffff81109057:	0f 85 e6 01 00 00    	jne    ffffffff81109243 <do_last.isra.44+0x470>
			create_error = -EROFS;
			goto no_open;
		} else {
			/* No side effects, safe to clear O_CREAT */
			create_error = -EROFS;
			open_flag &= ~O_CREAT;
ffffffff8110905d:	83 65 ac bf          	andl   $0xffffffbf,-0x54(%rbp)
			/* Fall back and fail with the right error */
			create_error = -EROFS;
			goto no_open;
		} else {
			/* No side effects, safe to clear O_CREAT */
			create_error = -EROFS;
ffffffff81109061:	41 be e2 ff ff ff    	mov    $0xffffffe2,%r14d
			open_flag &= ~O_CREAT;
		}
	}

	if (open_flag & O_CREAT) {
ffffffff81109067:	f6 45 ac 40          	testb  $0x40,-0x54(%rbp)
ffffffff8110906b:	74 3f                	je     ffffffff811090ac <do_last.isra.44+0x2d9>
{
	int error = security_path_mknod(dir, dentry, mode, 0);
	if (error)
		return error;

	error = inode_permission(dir->dentry->d_inode, MAY_WRITE | MAY_EXEC);
ffffffff8110906d:	48 8b 43 08          	mov    0x8(%rbx),%rax
ffffffff81109071:	be 03 00 00 00       	mov    $0x3,%esi
ffffffff81109076:	48 8b 78 30          	mov    0x30(%rax),%rdi
ffffffff8110907a:	e8 7c d2 ff ff       	callq  ffffffff811062fb <inode_permission>
	if (error)
ffffffff8110907f:	85 c0                	test   %eax,%eax
ffffffff81109081:	75 18                	jne    ffffffff8110909b <do_last.isra.44+0x2c8>
		return error;

	return security_inode_create(dir->dentry->d_inode, dentry, mode);
ffffffff81109083:	48 8b 43 08          	mov    0x8(%rbx),%rax
ffffffff81109087:	0f b7 55 90          	movzwl -0x70(%rbp),%edx
ffffffff8110908b:	4c 89 fe             	mov    %r15,%rsi
ffffffff8110908e:	48 8b 78 30          	mov    0x30(%rax),%rdi
ffffffff81109092:	e8 3c d0 0d 00       	callq  ffffffff811e60d3 <security_inode_create>
		}
	}

	if (open_flag & O_CREAT) {
		error = may_o_create(&nd->path, dentry, mode);
		if (error) {
ffffffff81109097:	85 c0                	test   %eax,%eax
ffffffff81109099:	74 11                	je     ffffffff811090ac <do_last.isra.44+0x2d9>
			create_error = error;
			if (open_flag & O_EXCL)
ffffffff8110909b:	f6 45 ac 80          	testb  $0x80,-0x54(%rbp)
	int error = security_path_mknod(dir, dentry, mode, 0);
	if (error)
		return error;

	error = inode_permission(dir->dentry->d_inode, MAY_WRITE | MAY_EXEC);
	if (error)
ffffffff8110909f:	41 89 c6             	mov    %eax,%r14d

	if (open_flag & O_CREAT) {
		error = may_o_create(&nd->path, dentry, mode);
		if (error) {
			create_error = error;
			if (open_flag & O_EXCL)
ffffffff811090a2:	0f 85 a1 01 00 00    	jne    ffffffff81109249 <do_last.isra.44+0x476>
				goto no_open;
			open_flag &= ~O_CREAT;
ffffffff811090a8:	83 65 ac bf          	andl   $0xffffffbf,-0x54(%rbp)
		}
	}

	if (nd->flags & LOOKUP_DIRECTORY)
		open_flag |= O_DIRECTORY;
ffffffff811090ac:	8b 45 ac             	mov    -0x54(%rbp),%eax

	file->f_path.dentry = DENTRY_NOT_SET;
	file->f_path.mnt = nd->path.mnt;
	error = dir->i_op->atomic_open(dir, dentry, file, open_flag, mode,
ffffffff811090af:	48 8b 55 88          	mov    -0x78(%rbp),%rdx
ffffffff811090b3:	4c 89 fe             	mov    %r15,%rsi
ffffffff811090b6:	44 0f b7 45 90       	movzwl -0x70(%rbp),%r8d
ffffffff811090bb:	4c 8b 4d a0          	mov    -0x60(%rbp),%r9
ffffffff811090bf:	48 8b 7d 88          	mov    -0x78(%rbp),%rdi
			open_flag &= ~O_CREAT;
		}
	}

	if (nd->flags & LOOKUP_DIRECTORY)
		open_flag |= O_DIRECTORY;
ffffffff811090c3:	0d 00 00 01 00       	or     $0x10000,%eax
ffffffff811090c8:	f6 43 38 02          	testb  $0x2,0x38(%rbx)

	file->f_path.dentry = DENTRY_NOT_SET;
ffffffff811090cc:	49 c7 45 18 ff ff ff 	movq   $0xffffffffffffffff,0x18(%r13)
ffffffff811090d3:	ff 
			open_flag &= ~O_CREAT;
		}
	}

	if (nd->flags & LOOKUP_DIRECTORY)
		open_flag |= O_DIRECTORY;
ffffffff811090d4:	0f 44 45 ac          	cmove  -0x54(%rbp),%eax
ffffffff811090d8:	89 45 ac             	mov    %eax,-0x54(%rbp)

	file->f_path.dentry = DENTRY_NOT_SET;
	file->f_path.mnt = nd->path.mnt;
ffffffff811090db:	48 8b 03             	mov    (%rbx),%rax
	error = dir->i_op->atomic_open(dir, dentry, file, open_flag, mode,
ffffffff811090de:	8b 4d ac             	mov    -0x54(%rbp),%ecx

	if (nd->flags & LOOKUP_DIRECTORY)
		open_flag |= O_DIRECTORY;

	file->f_path.dentry = DENTRY_NOT_SET;
	file->f_path.mnt = nd->path.mnt;
ffffffff811090e1:	49 89 45 10          	mov    %rax,0x10(%r13)
	error = dir->i_op->atomic_open(dir, dentry, file, open_flag, mode,
ffffffff811090e5:	48 8b 42 20          	mov    0x20(%rdx),%rax
ffffffff811090e9:	4c 89 ea             	mov    %r13,%rdx
ffffffff811090ec:	ff 90 b8 00 00 00    	callq  *0xb8(%rax)
				      opened);
	if (error < 0) {
ffffffff811090f2:	83 f8 00             	cmp    $0x0,%eax
ffffffff811090f5:	7d 17                	jge    ffffffff8110910e <do_last.isra.44+0x33b>
		if (create_error && error == -ENOENT)
ffffffff811090f7:	83 f8 fe             	cmp    $0xfffffffe,%eax
ffffffff811090fa:	0f 85 30 01 00 00    	jne    ffffffff81109230 <do_last.isra.44+0x45d>
ffffffff81109100:	45 85 f6             	test   %r14d,%r14d
ffffffff81109103:	0f 85 56 02 00 00    	jne    ffffffff8110935f <do_last.isra.44+0x58c>
ffffffff81109109:	e9 22 01 00 00       	jmpq   ffffffff81109230 <do_last.isra.44+0x45d>
			error = create_error;
		goto out;
	}

	if (error) {	/* returned 1, that is */
ffffffff8110910e:	0f 84 a3 00 00 00    	je     ffffffff811091b7 <do_last.isra.44+0x3e4>
		if (WARN_ON(file->f_path.dentry == DENTRY_NOT_SET)) {
ffffffff81109114:	49 8b 45 18          	mov    0x18(%r13),%rax
ffffffff81109118:	48 83 f8 ff          	cmp    $0xffffffffffffffff,%rax
ffffffff8110911c:	0f 85 41 06 00 00    	jne    ffffffff81109763 <do_last.isra.44+0x990>
ffffffff81109122:	be 98 0a 00 00       	mov    $0xa98,%esi
ffffffff81109127:	48 c7 c7 91 a0 4e 81 	mov    $0xffffffff814ea091,%rdi
			error = -EIO;
ffffffff8110912e:	41 be fb ff ff ff    	mov    $0xfffffffb,%r14d
			error = create_error;
		goto out;
	}

	if (error) {	/* returned 1, that is */
		if (WARN_ON(file->f_path.dentry == DENTRY_NOT_SET)) {
ffffffff81109134:	e8 9a 05 f3 ff       	callq  ffffffff810396d3 <warn_slowpath_null>
ffffffff81109139:	e9 21 02 00 00       	jmpq   ffffffff8110935f <do_last.isra.44+0x58c>
			error = -EIO;
			goto out;
		}
		if (file->f_path.dentry) {
			dput(dentry);
ffffffff8110913e:	4c 89 ff             	mov    %r15,%rdi
ffffffff81109141:	e8 83 65 00 00       	callq  ffffffff8110f6c9 <dput>
			dentry = file->f_path.dentry;
ffffffff81109146:	4d 8b 7d 18          	mov    0x18(%r13),%r15
		}
		if (*opened & FILE_CREATED)
ffffffff8110914a:	48 8b 45 a0          	mov    -0x60(%rbp),%rax
ffffffff8110914e:	f6 00 01             	testb  $0x1,(%rax)
ffffffff81109151:	74 1e                	je     ffffffff81109171 <do_last.isra.44+0x39e>
 */
static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
{
	audit_inode_child(inode, dentry, AUDIT_TYPE_CHILD_CREATE);

	fsnotify(inode, FS_CREATE, dentry->d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name, 0);
ffffffff81109153:	49 8b 57 30          	mov    0x30(%r15),%rdx
ffffffff81109157:	4d 8b 47 28          	mov    0x28(%r15),%r8
ffffffff8110915b:	45 31 c9             	xor    %r9d,%r9d
ffffffff8110915e:	48 8b 7d 88          	mov    -0x78(%rbp),%rdi
ffffffff81109162:	b9 02 00 00 00       	mov    $0x2,%ecx
ffffffff81109167:	be 00 01 00 00       	mov    $0x100,%esi
ffffffff8110916c:	e8 d4 73 02 00       	callq  ffffffff81130545 <fsnotify>
			fsnotify_create(dir, dentry);
		if (!dentry->d_inode) {
ffffffff81109171:	49 83 7f 30 00       	cmpq   $0x0,0x30(%r15)
ffffffff81109176:	75 23                	jne    ffffffff8110919b <do_last.isra.44+0x3c8>
			WARN_ON(*opened & FILE_CREATED);
ffffffff81109178:	48 8b 55 a0          	mov    -0x60(%rbp),%rdx
ffffffff8110917c:	f6 02 01             	testb  $0x1,(%rdx)
ffffffff8110917f:	0f 84 bb 01 00 00    	je     ffffffff81109340 <do_last.isra.44+0x56d>
ffffffff81109185:	be a3 0a 00 00       	mov    $0xaa3,%esi
ffffffff8110918a:	48 c7 c7 91 a0 4e 81 	mov    $0xffffffff814ea091,%rdi
ffffffff81109191:	e8 3d 05 f3 ff       	callq  ffffffff810396d3 <warn_slowpath_null>
ffffffff81109196:	e9 a5 01 00 00       	jmpq   ffffffff81109340 <do_last.isra.44+0x56d>
			if (create_error) {
				error = create_error;
				goto out;
			}
		} else {
			if (excl && !(*opened & FILE_CREATED)) {
ffffffff8110919b:	80 7d a8 00          	cmpb   $0x0,-0x58(%rbp)
ffffffff8110919f:	0f 84 a0 01 00 00    	je     ffffffff81109345 <do_last.isra.44+0x572>
ffffffff811091a5:	48 8b 45 a0          	mov    -0x60(%rbp),%rax
ffffffff811091a9:	f6 00 01             	testb  $0x1,(%rax)
ffffffff811091ac:	0f 85 93 01 00 00    	jne    ffffffff81109345 <do_last.isra.44+0x572>
ffffffff811091b2:	e9 81 00 00 00       	jmpq   ffffffff81109238 <do_last.isra.44+0x465>
	/*
	 * We didn't have the inode before the open, so check open permission
	 * here.
	 */
	acc_mode = op->acc_mode;
	if (*opened & FILE_CREATED) {
ffffffff811091b7:	48 8b 45 a0          	mov    -0x60(%rbp),%rax

	/*
	 * We didn't have the inode before the open, so check open permission
	 * here.
	 */
	acc_mode = op->acc_mode;
ffffffff811091bb:	48 8b 55 98          	mov    -0x68(%rbp),%rdx
	if (*opened & FILE_CREATED) {
ffffffff811091bf:	f6 00 01             	testb  $0x1,(%rax)

	/*
	 * We didn't have the inode before the open, so check open permission
	 * here.
	 */
	acc_mode = op->acc_mode;
ffffffff811091c2:	8b 72 08             	mov    0x8(%rdx),%esi
	if (*opened & FILE_CREATED) {
ffffffff811091c5:	74 3a                	je     ffffffff81109201 <do_last.isra.44+0x42e>
		WARN_ON(!(open_flag & O_CREAT));
ffffffff811091c7:	f6 45 ac 40          	testb  $0x40,-0x54(%rbp)
ffffffff811091cb:	75 11                	jne    ffffffff811091de <do_last.isra.44+0x40b>
ffffffff811091cd:	be b7 0a 00 00       	mov    $0xab7,%esi
ffffffff811091d2:	48 c7 c7 91 a0 4e 81 	mov    $0xffffffff814ea091,%rdi
ffffffff811091d9:	e8 f5 04 f3 ff       	callq  ffffffff810396d3 <warn_slowpath_null>
ffffffff811091de:	49 8b 57 30          	mov    0x30(%r15),%rdx
ffffffff811091e2:	4d 8b 47 28          	mov    0x28(%r15),%r8
ffffffff811091e6:	be 00 01 00 00       	mov    $0x100,%esi
ffffffff811091eb:	48 8b 7d 88          	mov    -0x78(%rbp),%rdi
ffffffff811091ef:	45 31 c9             	xor    %r9d,%r9d
ffffffff811091f2:	b9 02 00 00 00       	mov    $0x2,%ecx
ffffffff811091f7:	e8 49 73 02 00       	callq  ffffffff81130545 <fsnotify>
		fsnotify_create(dir, dentry);
		acc_mode = MAY_OPEN;
ffffffff811091fc:	be 20 00 00 00       	mov    $0x20,%esi
	}
	error = may_open(&file->f_path, acc_mode, open_flag);
ffffffff81109201:	8b 55 ac             	mov    -0x54(%rbp),%edx
ffffffff81109204:	49 8d 7d 10          	lea    0x10(%r13),%rdi
ffffffff81109208:	e8 dc fa ff ff       	callq  ffffffff81108ce9 <may_open>
	if (error)
ffffffff8110920d:	85 c0                	test   %eax,%eax
	if (*opened & FILE_CREATED) {
		WARN_ON(!(open_flag & O_CREAT));
		fsnotify_create(dir, dentry);
		acc_mode = MAY_OPEN;
	}
	error = may_open(&file->f_path, acc_mode, open_flag);
ffffffff8110920f:	41 89 c6             	mov    %eax,%r14d
	if (error)
ffffffff81109212:	0f 84 47 01 00 00    	je     ffffffff8110935f <do_last.isra.44+0x58c>
		fput(file);
ffffffff81109218:	4c 89 ef             	mov    %r13,%rdi
ffffffff8110921b:	e8 d6 56 ff ff       	callq  ffffffff810fe8f6 <fput>
ffffffff81109220:	e9 3a 01 00 00       	jmpq   ffffffff8110935f <do_last.isra.44+0x58c>

	BUG_ON(dentry->d_inode);

	/* Don't create child dentry for a dead directory. */
	if (unlikely(IS_DEADDIR(dir))) {
		error = -ENOENT;
ffffffff81109225:	41 be fe ff ff ff    	mov    $0xfffffffe,%r14d
ffffffff8110922b:	e9 2f 01 00 00       	jmpq   ffffffff8110935f <do_last.isra.44+0x58c>
	file->f_path.dentry = DENTRY_NOT_SET;
	file->f_path.mnt = nd->path.mnt;
	error = dir->i_op->atomic_open(dir, dentry, file, open_flag, mode,
				      opened);
	if (error < 0) {
		if (create_error && error == -ENOENT)
ffffffff81109230:	41 89 c6             	mov    %eax,%r14d
ffffffff81109233:	e9 27 01 00 00       	jmpq   ffffffff8110935f <do_last.isra.44+0x58c>
				error = create_error;
				goto out;
			}
		} else {
			if (excl && !(*opened & FILE_CREATED)) {
				error = -EEXIST;
ffffffff81109238:	41 be ef ff ff ff    	mov    $0xffffffef,%r14d
ffffffff8110923e:	e9 1c 01 00 00       	jmpq   ffffffff8110935f <do_last.isra.44+0x58c>
			 * back to lookup + open
			 */
			goto no_open;
		} else if (open_flag & (O_EXCL | O_TRUNC)) {
			/* Fall back and fail with the right error */
			create_error = -EROFS;
ffffffff81109243:	41 be e2 ff ff ff    	mov    $0xffffffe2,%r14d
out:
	dput(dentry);
	return error;

no_open:
	if (need_lookup) {
ffffffff81109249:	80 7d a9 00          	cmpb   $0x0,-0x57(%rbp)
ffffffff8110924d:	0f 84 f2 00 00 00    	je     ffffffff81109345 <do_last.isra.44+0x572>
		dentry = lookup_real(dir, dentry, nd->flags);
ffffffff81109253:	8b 53 38             	mov    0x38(%rbx),%edx
ffffffff81109256:	48 8b 7d 88          	mov    -0x78(%rbp),%rdi
ffffffff8110925a:	4c 89 fe             	mov    %r15,%rsi
ffffffff8110925d:	e8 82 bc ff ff       	callq  ffffffff81104ee4 <lookup_real>
		if (IS_ERR(dentry))
ffffffff81109262:	48 3d 00 f0 ff ff    	cmp    $0xfffffffffffff000,%rax
	dput(dentry);
	return error;

no_open:
	if (need_lookup) {
		dentry = lookup_real(dir, dentry, nd->flags);
ffffffff81109268:	49 89 c7             	mov    %rax,%r15
		if (IS_ERR(dentry))
ffffffff8110926b:	76 02                	jbe    ffffffff8110926f <do_last.isra.44+0x49c>
ffffffff8110926d:	eb 6b                	jmp    ffffffff811092da <do_last.isra.44+0x507>
			return PTR_ERR(dentry);

		if (create_error) {
ffffffff8110926f:	45 85 f6             	test   %r14d,%r14d
ffffffff81109272:	0f 84 cd 00 00 00    	je     ffffffff81109345 <do_last.isra.44+0x572>
			int open_flag = op->open_flag;
ffffffff81109278:	48 8b 45 98          	mov    -0x68(%rbp),%rax
ffffffff8110927c:	8b 10                	mov    (%rax),%edx

			error = create_error;
			if ((open_flag & O_EXCL)) {
ffffffff8110927e:	f6 c2 80             	test   $0x80,%dl
ffffffff81109281:	74 07                	je     ffffffff8110928a <do_last.isra.44+0x4b7>
				if (!dentry->d_inode)
ffffffff81109283:	49 83 7f 30 00       	cmpq   $0x0,0x30(%r15)
ffffffff81109288:	eb 20                	jmp    ffffffff811092aa <do_last.isra.44+0x4d7>
					goto out;
			} else if (!dentry->d_inode) {
ffffffff8110928a:	49 8b 47 30          	mov    0x30(%r15),%rax
ffffffff8110928e:	48 85 c0             	test   %rax,%rax
ffffffff81109291:	0f 84 c8 00 00 00    	je     ffffffff8110935f <do_last.isra.44+0x58c>
				goto out;
			} else if ((open_flag & O_TRUNC) &&
ffffffff81109297:	80 e6 02             	and    $0x2,%dh
ffffffff8110929a:	0f 84 a5 00 00 00    	je     ffffffff81109345 <do_last.isra.44+0x572>
				   S_ISREG(dentry->d_inode->i_mode)) {
ffffffff811092a0:	8b 00                	mov    (%rax),%eax
ffffffff811092a2:	66 25 00 f0          	and    $0xf000,%ax
			if ((open_flag & O_EXCL)) {
				if (!dentry->d_inode)
					goto out;
			} else if (!dentry->d_inode) {
				goto out;
			} else if ((open_flag & O_TRUNC) &&
ffffffff811092a6:	66 3d 00 80          	cmp    $0x8000,%ax
ffffffff811092aa:	0f 84 af 00 00 00    	je     ffffffff8110935f <do_last.isra.44+0x58c>
ffffffff811092b0:	e9 90 00 00 00       	jmpq   ffffffff81109345 <do_last.isra.44+0x572>
	if ((nd->flags & LOOKUP_OPEN) && dir_inode->i_op->atomic_open) {
		return atomic_open(nd, dentry, path, file, op, got_write,
				   need_lookup, opened);
	}

	if (need_lookup) {
ffffffff811092b5:	80 7d a9 00          	cmpb   $0x0,-0x57(%rbp)
ffffffff811092b9:	74 27                	je     ffffffff811092e2 <do_last.isra.44+0x50f>
		BUG_ON(dentry->d_inode);
ffffffff811092bb:	49 83 7f 30 00       	cmpq   $0x0,0x30(%r15)
ffffffff811092c0:	74 02                	je     ffffffff811092c4 <do_last.isra.44+0x4f1>
ffffffff811092c2:	0f 0b                	ud2    

		dentry = lookup_real(dir_inode, dentry, nd->flags);
ffffffff811092c4:	4c 89 fe             	mov    %r15,%rsi
ffffffff811092c7:	4c 89 c7             	mov    %r8,%rdi
ffffffff811092ca:	e8 15 bc ff ff       	callq  ffffffff81104ee4 <lookup_real>
		if (IS_ERR(dentry))
ffffffff811092cf:	48 3d 00 f0 ff ff    	cmp    $0xfffffffffffff000,%rax
	}

	if (need_lookup) {
		BUG_ON(dentry->d_inode);

		dentry = lookup_real(dir_inode, dentry, nd->flags);
ffffffff811092d5:	49 89 c7             	mov    %rax,%r15
		if (IS_ERR(dentry))
ffffffff811092d8:	76 08                	jbe    ffffffff811092e2 <do_last.isra.44+0x50f>
			return PTR_ERR(dentry);
ffffffff811092da:	45 89 fe             	mov    %r15d,%r14d
ffffffff811092dd:	e9 85 00 00 00       	jmpq   ffffffff81109367 <do_last.isra.44+0x594>
	}

	/* Negative dentry, just create the file */
	if (!dentry->d_inode && (op->open_flag & O_CREAT)) {
ffffffff811092e2:	49 83 7f 30 00       	cmpq   $0x0,0x30(%r15)
ffffffff811092e7:	75 5c                	jne    ffffffff81109345 <do_last.isra.44+0x572>
ffffffff811092e9:	48 8b 55 98          	mov    -0x68(%rbp),%rdx
ffffffff811092ed:	f6 02 40             	testb  $0x40,(%rdx)
ffffffff811092f0:	74 53                	je     ffffffff81109345 <do_last.isra.44+0x572>
		umode_t mode = op->mode;
		if (!IS_POSIXACL(dir->d_inode))
ffffffff811092f2:	49 8b 46 30          	mov    0x30(%r14),%rax
			return PTR_ERR(dentry);
	}

	/* Negative dentry, just create the file */
	if (!dentry->d_inode && (op->open_flag & O_CREAT)) {
		umode_t mode = op->mode;
ffffffff811092f6:	8b 52 04             	mov    0x4(%rdx),%edx
		if (!IS_POSIXACL(dir->d_inode))
ffffffff811092f9:	48 8b 40 28          	mov    0x28(%rax),%rax
ffffffff811092fd:	f6 40 52 01          	testb  $0x1,0x52(%rax)
ffffffff81109301:	75 15                	jne    ffffffff81109318 <do_last.isra.44+0x545>
			mode &= ~current_umask();
ffffffff81109303:	89 95 60 ff ff ff    	mov    %edx,-0xa0(%rbp)
ffffffff81109309:	e8 ba a2 01 00       	callq  ffffffff811235c8 <current_umask>
ffffffff8110930e:	8b 95 60 ff ff ff    	mov    -0xa0(%rbp),%edx
ffffffff81109314:	f7 d0                	not    %eax
ffffffff81109316:	21 c2                	and    %eax,%edx
		 * rw->ro transition does not occur between
		 * the time when the file is created and when
		 * a permanent write count is taken through
		 * the 'struct file' in finish_open().
		 */
		if (!got_write) {
ffffffff81109318:	80 7d ab 00          	cmpb   $0x0,-0x55(%rbp)
ffffffff8110931c:	74 3b                	je     ffffffff81109359 <do_last.isra.44+0x586>
			error = -EROFS;
			goto out_dput;
		}
		*opened |= FILE_CREATED;
ffffffff8110931e:	48 8b 45 a0          	mov    -0x60(%rbp),%rax
		error = security_path_mknod(&nd->path, dentry, mode, 0);
		if (error)
			goto out_dput;
		error = vfs_create(dir->d_inode, dentry, mode,
ffffffff81109322:	0f b7 d2             	movzwl %dx,%edx
ffffffff81109325:	4c 89 fe             	mov    %r15,%rsi
		 */
		if (!got_write) {
			error = -EROFS;
			goto out_dput;
		}
		*opened |= FILE_CREATED;
ffffffff81109328:	83 08 01             	orl    $0x1,(%rax)
		error = security_path_mknod(&nd->path, dentry, mode, 0);
		if (error)
			goto out_dput;
		error = vfs_create(dir->d_inode, dentry, mode,
ffffffff8110932b:	8b 4b 38             	mov    0x38(%rbx),%ecx
ffffffff8110932e:	49 8b 7e 30          	mov    0x30(%r14),%rdi
ffffffff81109332:	c1 e9 0a             	shr    $0xa,%ecx
ffffffff81109335:	83 e1 01             	and    $0x1,%ecx
ffffffff81109338:	e8 94 db ff ff       	callq  ffffffff81106ed1 <vfs_create>
ffffffff8110933d:	41 89 c6             	mov    %eax,%r14d
				   nd->flags & LOOKUP_EXCL);
		if (error)
ffffffff81109340:	45 85 f6             	test   %r14d,%r14d
ffffffff81109343:	75 1a                	jne    ffffffff8110935f <do_last.isra.44+0x58c>
			goto out_dput;
	}
out_no_open:
	path->dentry = dentry;
ffffffff81109345:	4d 89 7c 24 08       	mov    %r15,0x8(%r12)
	path->mnt = nd->path.mnt;
ffffffff8110934a:	48 8b 03             	mov    (%rbx),%rax
	return 1;
ffffffff8110934d:	41 be 01 00 00 00    	mov    $0x1,%r14d
		if (error)
			goto out_dput;
	}
out_no_open:
	path->dentry = dentry;
	path->mnt = nd->path.mnt;
ffffffff81109353:	49 89 04 24          	mov    %rax,(%r12)
ffffffff81109357:	eb 0e                	jmp    ffffffff81109367 <do_last.isra.44+0x594>
		 * the time when the file is created and when
		 * a permanent write count is taken through
		 * the 'struct file' in finish_open().
		 */
		if (!got_write) {
			error = -EROFS;
ffffffff81109359:	41 be e2 ff ff ff    	mov    $0xffffffe2,%r14d
	path->dentry = dentry;
	path->mnt = nd->path.mnt;
	return 1;

out_dput:
	dput(dentry);
ffffffff8110935f:	4c 89 ff             	mov    %r15,%rdi
ffffffff81109362:	e8 62 63 00 00       	callq  ffffffff8110f6c9 <dput>
		 * dropping this one anyway.
		 */
	}
	mutex_lock(&dir->d_inode->i_mutex);
	error = lookup_open(nd, path, file, op, got_write, opened);
	mutex_unlock(&dir->d_inode->i_mutex);
ffffffff81109367:	48 8b 55 80          	mov    -0x80(%rbp),%rdx
ffffffff8110936b:	48 8b 52 30          	mov    0x30(%rdx),%rdx
ffffffff8110936f:	48 89 d7             	mov    %rdx,%rdi
ffffffff81109372:	48 81 c7 a0 00 00 00 	add    $0xa0,%rdi
ffffffff81109379:	e8 4a 85 27 00       	callq  ffffffff813818c8 <mutex_unlock>

	if (error <= 0) {
ffffffff8110937e:	41 83 fe 00          	cmp    $0x0,%r14d
ffffffff81109382:	7f 31                	jg     ffffffff811093b5 <do_last.isra.44+0x5e2>
		if (error)
ffffffff81109384:	0f 85 21 03 00 00    	jne    ffffffff811096ab <do_last.isra.44+0x8d8>
			goto out;

		if ((*opened & FILE_CREATED) ||
ffffffff8110938a:	48 8b 45 a0          	mov    -0x60(%rbp),%rax
ffffffff8110938e:	f6 00 01             	testb  $0x1,(%rax)
ffffffff81109391:	0f 85 93 02 00 00    	jne    ffffffff8110962a <do_last.isra.44+0x857>
		    !S_ISREG(file_inode(file)->i_mode))
ffffffff81109397:	49 8b 45 20          	mov    0x20(%r13),%rax
			will_truncate = false;
ffffffff8110939b:	8a 55 aa             	mov    -0x56(%rbp),%dl
	if (error <= 0) {
		if (error)
			goto out;

		if ((*opened & FILE_CREATED) ||
		    !S_ISREG(file_inode(file)->i_mode))
ffffffff8110939e:	8b 00                	mov    (%rax),%eax
ffffffff811093a0:	66 25 00 f0          	and    $0xf000,%ax
			will_truncate = false;
ffffffff811093a4:	66 3d 00 80          	cmp    $0x8000,%ax
ffffffff811093a8:	b0 00                	mov    $0x0,%al
ffffffff811093aa:	0f 45 d0             	cmovne %eax,%edx
ffffffff811093ad:	88 55 aa             	mov    %dl,-0x56(%rbp)
ffffffff811093b0:	e9 79 02 00 00       	jmpq   ffffffff8110962e <do_last.isra.44+0x85b>

		audit_inode(name, file->f_path.dentry, 0);
		goto opened;
	}

	if (*opened & FILE_CREATED) {
ffffffff811093b5:	48 8b 45 a0          	mov    -0x60(%rbp),%rax
ffffffff811093b9:	f6 00 01             	testb  $0x1,(%rax)
ffffffff811093bc:	74 47                	je     ffffffff81109405 <do_last.isra.44+0x632>
		/* Don't check for write permission, don't truncate */
		open_flag &= ~O_TRUNC;
ffffffff811093be:	81 65 94 ff fd ff ff 	andl   $0xfffffdff,-0x6c(%rbp)
}

static inline void path_to_nameidata(const struct path *path,
					struct nameidata *nd)
{
	if (!(nd->flags & LOOKUP_RCU)) {
ffffffff811093c5:	f6 43 38 40          	testb  $0x40,0x38(%rbx)
ffffffff811093c9:	75 17                	jne    ffffffff811093e2 <do_last.isra.44+0x60f>
		dput(nd->path.dentry);
ffffffff811093cb:	48 8b 7b 08          	mov    0x8(%rbx),%rdi
ffffffff811093cf:	e8 f5 62 00 00       	callq  ffffffff8110f6c9 <dput>
		if (nd->path.mnt != path->mnt)
ffffffff811093d4:	48 8b 3b             	mov    (%rbx),%rdi
ffffffff811093d7:	49 3b 3c 24          	cmp    (%r12),%rdi
ffffffff811093db:	74 05                	je     ffffffff811093e2 <do_last.isra.44+0x60f>
			mntput(nd->path.mnt);
ffffffff811093dd:	e8 b1 ca 00 00       	callq  ffffffff81115e93 <mntput>
	}
	nd->path.mnt = path->mnt;
ffffffff811093e2:	49 8b 04 24          	mov    (%r12),%rax
	}

	if (*opened & FILE_CREATED) {
		/* Don't check for write permission, don't truncate */
		open_flag &= ~O_TRUNC;
		will_truncate = false;
ffffffff811093e6:	c6 45 aa 00          	movb   $0x0,-0x56(%rbp)
		acc_mode = MAY_OPEN;
ffffffff811093ea:	c7 85 7c ff ff ff 20 	movl   $0x20,-0x84(%rbp)
ffffffff811093f1:	00 00 00 
	if (!(nd->flags & LOOKUP_RCU)) {
		dput(nd->path.dentry);
		if (nd->path.mnt != path->mnt)
			mntput(nd->path.mnt);
	}
	nd->path.mnt = path->mnt;
ffffffff811093f4:	48 89 03             	mov    %rax,(%rbx)
	nd->path.dentry = path->dentry;
ffffffff811093f7:	49 8b 44 24 08       	mov    0x8(%r12),%rax
ffffffff811093fc:	48 89 43 08          	mov    %rax,0x8(%rbx)
ffffffff81109400:	e9 d9 01 00 00       	jmpq   ffffffff811095de <do_last.isra.44+0x80b>
	/*
	 * If atomic_open() acquired write access it is dropped now due to
	 * possible mount and symlink following (this might be optimized away if
	 * necessary...)
	 */
	if (got_write) {
ffffffff81109405:	80 7d ab 00          	cmpb   $0x0,-0x55(%rbp)
ffffffff81109409:	74 08                	je     ffffffff81109413 <do_last.isra.44+0x640>
		mnt_drop_write(nd->path.mnt);
ffffffff8110940b:	48 8b 3b             	mov    (%rbx),%rdi
ffffffff8110940e:	e8 75 bf 00 00       	callq  ffffffff81115388 <mnt_drop_write>
		got_write = false;
	}

	error = -EEXIST;
	if ((open_flag & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT))
ffffffff81109413:	8b 45 94             	mov    -0x6c(%rbp),%eax
ffffffff81109416:	25 c0 00 00 00       	and    $0xc0,%eax
ffffffff8110941b:	3d c0 00 00 00       	cmp    $0xc0,%eax
ffffffff81109420:	0f 84 a9 02 00 00    	je     ffffffff811096cf <do_last.isra.44+0x8fc>
		goto exit_dput;

	error = follow_managed(path, nd->flags);
ffffffff81109426:	8b 73 38             	mov    0x38(%rbx),%esi
ffffffff81109429:	4c 89 e7             	mov    %r12,%rdi
ffffffff8110942c:	e8 f2 c0 ff ff       	callq  ffffffff81105523 <follow_managed>
	if (error < 0)
ffffffff81109431:	83 f8 00             	cmp    $0x0,%eax

	error = -EEXIST;
	if ((open_flag & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT))
		goto exit_dput;

	error = follow_managed(path, nd->flags);
ffffffff81109434:	41 89 c6             	mov    %eax,%r14d
	if (error < 0)
ffffffff81109437:	0f 8c 98 02 00 00    	jl     ffffffff811096d5 <do_last.isra.44+0x902>
		goto exit_dput;

	if (error)
ffffffff8110943d:	74 07                	je     ffffffff81109446 <do_last.isra.44+0x673>
		nd->flags |= LOOKUP_JUMPED;
ffffffff8110943f:	81 4b 38 00 10 00 00 	orl    $0x1000,0x38(%rbx)

	BUG_ON(nd->flags & LOOKUP_RCU);
ffffffff81109446:	f6 43 38 40          	testb  $0x40,0x38(%rbx)
ffffffff8110944a:	74 02                	je     ffffffff8110944e <do_last.isra.44+0x67b>
ffffffff8110944c:	0f 0b                	ud2    
	inode = path->dentry->d_inode;
ffffffff8110944e:	49 8b 44 24 08       	mov    0x8(%r12),%rax
ffffffff81109453:	48 8b 40 30          	mov    0x30(%rax),%rax
ffffffff81109457:	48 89 45 b8          	mov    %rax,-0x48(%rbp)
finish_lookup:
	/* we _can_ be in RCU mode here */
	error = -ENOENT;
	if (d_is_negative(path->dentry)) {
ffffffff8110945b:	49 8b 74 24 08       	mov    0x8(%r12),%rsi
ffffffff81109460:	8b 43 38             	mov    0x38(%rbx),%eax
ffffffff81109463:	8b 16                	mov    (%rsi),%edx
ffffffff81109465:	81 e2 00 00 70 00    	and    $0x700000,%edx
ffffffff8110946b:	75 36                	jne    ffffffff811094a3 <do_last.isra.44+0x6d0>
}

static inline void path_to_nameidata(const struct path *path,
					struct nameidata *nd)
{
	if (!(nd->flags & LOOKUP_RCU)) {
ffffffff8110946d:	a8 40                	test   $0x40,%al
ffffffff8110946f:	75 17                	jne    ffffffff81109488 <do_last.isra.44+0x6b5>
		dput(nd->path.dentry);
ffffffff81109471:	48 8b 7b 08          	mov    0x8(%rbx),%rdi
ffffffff81109475:	e8 4f 62 00 00       	callq  ffffffff8110f6c9 <dput>
		if (nd->path.mnt != path->mnt)
ffffffff8110947a:	48 8b 3b             	mov    (%rbx),%rdi
ffffffff8110947d:	49 3b 3c 24          	cmp    (%r12),%rdi
ffffffff81109481:	74 05                	je     ffffffff81109488 <do_last.isra.44+0x6b5>
			mntput(nd->path.mnt);
ffffffff81109483:	e8 0b ca 00 00       	callq  ffffffff81115e93 <mntput>
	}
	nd->path.mnt = path->mnt;
ffffffff81109488:	49 8b 04 24          	mov    (%r12),%rax

	BUG_ON(nd->flags & LOOKUP_RCU);
	inode = path->dentry->d_inode;
finish_lookup:
	/* we _can_ be in RCU mode here */
	error = -ENOENT;
ffffffff8110948c:	41 be fe ff ff ff    	mov    $0xfffffffe,%r14d
	if (!(nd->flags & LOOKUP_RCU)) {
		dput(nd->path.dentry);
		if (nd->path.mnt != path->mnt)
			mntput(nd->path.mnt);
	}
	nd->path.mnt = path->mnt;
ffffffff81109492:	48 89 03             	mov    %rax,(%rbx)
	nd->path.dentry = path->dentry;
ffffffff81109495:	49 8b 44 24 08       	mov    0x8(%r12),%rax
ffffffff8110949a:	48 89 43 08          	mov    %rax,0x8(%rbx)
ffffffff8110949e:	e9 16 02 00 00       	jmpq   ffffffff811096b9 <do_last.isra.44+0x8e6>
 * so we keep a cache of "no, this doesn't need follow_link"
 * for the common case.
 */
static inline int should_follow_link(struct dentry *dentry, int follow)
{
	return unlikely(d_is_symlink(dentry)) ? follow : 0;
ffffffff811094a3:	81 fa 00 00 30 00    	cmp    $0x300000,%edx
ffffffff811094a9:	75 37                	jne    ffffffff811094e2 <do_last.isra.44+0x70f>
	if (d_is_negative(path->dentry)) {
		path_to_nameidata(path, nd);
		goto out;
	}

	if (should_follow_link(path->dentry, !symlink_ok)) {
ffffffff811094ab:	80 7d 93 00          	cmpb   $0x0,-0x6d(%rbp)
ffffffff811094af:	75 31                	jne    ffffffff811094e2 <do_last.isra.44+0x70f>
		if (nd->flags & LOOKUP_RCU) {
ffffffff811094b1:	a8 40                	test   $0x40,%al
ffffffff811094b3:	75 1a                	jne    ffffffff811094cf <do_last.isra.44+0x6fc>
			if (unlikely(unlazy_walk(nd, path->dentry))) {
				error = -ECHILD;
				goto out;
			}
		}
		BUG_ON(inode != path->dentry->d_inode);
ffffffff811094b5:	49 8b 44 24 08       	mov    0x8(%r12),%rax
ffffffff811094ba:	48 8b 50 30          	mov    0x30(%rax),%rdx
ffffffff811094be:	48 39 55 b8          	cmp    %rdx,-0x48(%rbp)
ffffffff811094c2:	75 1c                	jne    ffffffff811094e0 <do_last.isra.44+0x70d>
		return 1;
ffffffff811094c4:	41 be 01 00 00 00    	mov    $0x1,%r14d
ffffffff811094ca:	e9 dc 02 00 00       	jmpq   ffffffff811097ab <do_last.isra.44+0x9d8>
		goto out;
	}

	if (should_follow_link(path->dentry, !symlink_ok)) {
		if (nd->flags & LOOKUP_RCU) {
			if (unlikely(unlazy_walk(nd, path->dentry))) {
ffffffff811094cf:	48 89 df             	mov    %rbx,%rdi
ffffffff811094d2:	e8 48 bf ff ff       	callq  ffffffff8110541f <unlazy_walk>
ffffffff811094d7:	85 c0                	test   %eax,%eax
ffffffff811094d9:	74 da                	je     ffffffff811094b5 <do_last.isra.44+0x6e2>
ffffffff811094db:	e9 c0 02 00 00       	jmpq   ffffffff811097a0 <do_last.isra.44+0x9cd>
				error = -ECHILD;
				goto out;
			}
		}
		BUG_ON(inode != path->dentry->d_inode);
ffffffff811094e0:	0f 0b                	ud2    
		return 1;
	}

	if ((nd->flags & LOOKUP_RCU) || nd->path.mnt != path->mnt) {
ffffffff811094e2:	a8 40                	test   $0x40,%al
ffffffff811094e4:	75 20                	jne    ffffffff81109506 <do_last.isra.44+0x733>
ffffffff811094e6:	48 8b 03             	mov    (%rbx),%rax
ffffffff811094e9:	49 3b 04 24          	cmp    (%r12),%rax
ffffffff811094ed:	48 8b 7b 08          	mov    0x8(%rbx),%rdi
ffffffff811094f1:	74 1c                	je     ffffffff8110950f <do_last.isra.44+0x73c>

static inline void path_to_nameidata(const struct path *path,
					struct nameidata *nd)
{
	if (!(nd->flags & LOOKUP_RCU)) {
		dput(nd->path.dentry);
ffffffff811094f3:	e8 d1 61 00 00       	callq  ffffffff8110f6c9 <dput>
		if (nd->path.mnt != path->mnt)
ffffffff811094f8:	48 8b 3b             	mov    (%rbx),%rdi
ffffffff811094fb:	49 3b 3c 24          	cmp    (%r12),%rdi
ffffffff811094ff:	74 05                	je     ffffffff81109506 <do_last.isra.44+0x733>
			mntput(nd->path.mnt);
ffffffff81109501:	e8 8d c9 00 00       	callq  ffffffff81115e93 <mntput>
	}
	nd->path.mnt = path->mnt;
ffffffff81109506:	49 8b 04 24          	mov    (%r12),%rax
ffffffff8110950a:	48 89 03             	mov    %rax,(%rbx)
ffffffff8110950d:	eb 10                	jmp    ffffffff8110951f <do_last.isra.44+0x74c>
	}

	if ((nd->flags & LOOKUP_RCU) || nd->path.mnt != path->mnt) {
		path_to_nameidata(path, nd);
	} else {
		save_parent.dentry = nd->path.dentry;
ffffffff8110950f:	48 89 7d c8          	mov    %rdi,-0x38(%rbp)
		save_parent.mnt = mntget(path->mnt);
ffffffff81109513:	48 89 c7             	mov    %rax,%rdi
ffffffff81109516:	e8 d0 b9 00 00       	callq  ffffffff81114eeb <mntget>
ffffffff8110951b:	48 89 45 c0          	mov    %rax,-0x40(%rbp)
		nd->path.dentry = path->dentry;
ffffffff8110951f:	49 8b 44 24 08       	mov    0x8(%r12),%rax
ffffffff81109524:	48 89 43 08          	mov    %rax,0x8(%rbx)

	}
	nd->inode = inode;
ffffffff81109528:	48 8b 45 b8          	mov    -0x48(%rbp),%rax
ffffffff8110952c:	48 89 43 30          	mov    %rax,0x30(%rbx)
	/* Why this, you ask?  _Now_ we might have grown LOOKUP_JUMPED... */
finish_open:
	error = complete_walk(nd);
ffffffff81109530:	48 89 df             	mov    %rbx,%rdi
ffffffff81109533:	e8 79 bb ff ff       	callq  ffffffff811050b1 <complete_walk>
	if (error) {
ffffffff81109538:	85 c0                	test   %eax,%eax

	}
	nd->inode = inode;
	/* Why this, you ask?  _Now_ we might have grown LOOKUP_JUMPED... */
finish_open:
	error = complete_walk(nd);
ffffffff8110953a:	41 89 c6             	mov    %eax,%r14d
	if (error) {
ffffffff8110953d:	74 0e                	je     ffffffff8110954d <do_last.isra.44+0x77a>
		path_put(&save_parent);
ffffffff8110953f:	48 8d 7d c0          	lea    -0x40(%rbp),%rdi
ffffffff81109543:	e8 15 bb ff ff       	callq  ffffffff8110505d <path_put>
ffffffff81109548:	e9 5e 02 00 00       	jmpq   ffffffff811097ab <do_last.isra.44+0x9d8>
		return error;
	}
	audit_inode(name, nd->path.dentry, 0);
	error = -EISDIR;
	if ((open_flag & O_CREAT) && d_is_dir(nd->path.dentry))
ffffffff8110954d:	f6 45 94 40          	testb  $0x40,-0x6c(%rbp)
ffffffff81109551:	74 2c                	je     ffffffff8110957f <do_last.isra.44+0x7ac>
const struct inode_operations page_symlink_inode_operations = {
	.readlink	= generic_readlink,
	.follow_link	= page_follow_link_light,
	.put_link	= page_put_link,
};
EXPORT_SYMBOL(page_symlink_inode_operations);
ffffffff81109553:	48 8b 43 08          	mov    0x8(%rbx),%rax
	spin_unlock(&dentry->d_lock);
}

static inline unsigned __d_entry_type(const struct dentry *dentry)
{
	return dentry->d_flags & DCACHE_ENTRY_TYPE;
ffffffff81109557:	8b 00                	mov    (%rax),%eax
ffffffff81109559:	25 00 00 70 00       	and    $0x700000,%eax
	return __d_entry_type(dentry) == DCACHE_AUTODIR_TYPE;
}

static inline bool d_is_dir(const struct dentry *dentry)
{
	return d_can_lookup(dentry) || d_is_autodir(dentry);
ffffffff8110955e:	3d 00 00 10 00       	cmp    $0x100000,%eax
ffffffff81109563:	74 0d                	je     ffffffff81109572 <do_last.isra.44+0x79f>
ffffffff81109565:	3d 00 00 20 00       	cmp    $0x200000,%eax
ffffffff8110956a:	0f 94 c0             	sete   %al
ffffffff8110956d:	0f b6 c0             	movzbl %al,%eax
ffffffff81109570:	eb 05                	jmp    ffffffff81109577 <do_last.isra.44+0x7a4>
ffffffff81109572:	b8 01 00 00 00       	mov    $0x1,%eax
		path_put(&save_parent);
		return error;
	}
	audit_inode(name, nd->path.dentry, 0);
	error = -EISDIR;
	if ((open_flag & O_CREAT) && d_is_dir(nd->path.dentry))
ffffffff81109577:	85 c0                	test   %eax,%eax
ffffffff81109579:	0f 85 72 f9 ff ff    	jne    ffffffff81108ef1 <do_last.isra.44+0x11e>
		goto out;
	error = -ENOTDIR;
	if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry))
ffffffff8110957f:	f6 43 38 02          	testb  $0x2,0x38(%rbx)
ffffffff81109583:	74 1c                	je     ffffffff811095a1 <do_last.isra.44+0x7ce>
const struct inode_operations page_symlink_inode_operations = {
	.readlink	= generic_readlink,
	.follow_link	= page_follow_link_light,
	.put_link	= page_put_link,
};
EXPORT_SYMBOL(page_symlink_inode_operations);
ffffffff81109585:	48 8b 43 08          	mov    0x8(%rbx),%rax
	}
	audit_inode(name, nd->path.dentry, 0);
	error = -EISDIR;
	if ((open_flag & O_CREAT) && d_is_dir(nd->path.dentry))
		goto out;
	error = -ENOTDIR;
ffffffff81109589:	41 be ec ff ff ff    	mov    $0xffffffec,%r14d
	spin_unlock(&dentry->d_lock);
}

static inline unsigned __d_entry_type(const struct dentry *dentry)
{
	return dentry->d_flags & DCACHE_ENTRY_TYPE;
ffffffff8110958f:	8b 00                	mov    (%rax),%eax
ffffffff81109591:	25 00 00 70 00       	and    $0x700000,%eax
	if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry))
ffffffff81109596:	3d 00 00 10 00       	cmp    $0x100000,%eax
ffffffff8110959b:	0f 85 18 01 00 00    	jne    ffffffff811096b9 <do_last.isra.44+0x8e6>
		goto out;
	if (!S_ISREG(nd->inode->i_mode))
ffffffff811095a1:	48 8b 43 30          	mov    0x30(%rbx),%rax
ffffffff811095a5:	8b 00                	mov    (%rax),%eax
ffffffff811095a7:	66 25 00 f0          	and    $0xf000,%ax
ffffffff811095ab:	66 3d 00 80          	cmp    $0x8000,%ax
ffffffff811095af:	75 1f                	jne    ffffffff811095d0 <do_last.isra.44+0x7fd>
		will_truncate = false;

	if (will_truncate) {
ffffffff811095b1:	80 7d aa 00          	cmpb   $0x0,-0x56(%rbp)
ffffffff811095b5:	74 23                	je     ffffffff811095da <do_last.isra.44+0x807>
		error = mnt_want_write(nd->path.mnt);
ffffffff811095b7:	48 8b 3b             	mov    (%rbx),%rdi
ffffffff811095ba:	e8 89 cb 00 00       	callq  ffffffff81116148 <mnt_want_write>
		if (error)
ffffffff811095bf:	85 c0                	test   %eax,%eax
		goto out;
	if (!S_ISREG(nd->inode->i_mode))
		will_truncate = false;

	if (will_truncate) {
		error = mnt_want_write(nd->path.mnt);
ffffffff811095c1:	41 89 c6             	mov    %eax,%r14d
		if (error)
ffffffff811095c4:	0f 85 ef 00 00 00    	jne    ffffffff811096b9 <do_last.isra.44+0x8e6>
			goto out;
		got_write = true;
ffffffff811095ca:	c6 45 ab 01          	movb   $0x1,-0x55(%rbp)
ffffffff811095ce:	eb 0e                	jmp    ffffffff811095de <do_last.isra.44+0x80b>
	if ((open_flag & O_CREAT) && d_is_dir(nd->path.dentry))
		goto out;
	error = -ENOTDIR;
	if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry))
		goto out;
	if (!S_ISREG(nd->inode->i_mode))
ffffffff811095d0:	c6 45 ab 00          	movb   $0x0,-0x55(%rbp)
ffffffff811095d4:	c6 45 aa 00          	movb   $0x0,-0x56(%rbp)
ffffffff811095d8:	eb 04                	jmp    ffffffff811095de <do_last.isra.44+0x80b>
		will_truncate = false;

	if (will_truncate) {
ffffffff811095da:	c6 45 ab 00          	movb   $0x0,-0x55(%rbp)
		if (error)
			goto out;
		got_write = true;
	}
finish_open_created:
	error = may_open(&nd->path, acc_mode, open_flag);
ffffffff811095de:	8b 55 94             	mov    -0x6c(%rbp),%edx
ffffffff811095e1:	8b b5 7c ff ff ff    	mov    -0x84(%rbp),%esi
ffffffff811095e7:	48 89 df             	mov    %rbx,%rdi
ffffffff811095ea:	e8 fa f6 ff ff       	callq  ffffffff81108ce9 <may_open>
	if (error)
ffffffff811095ef:	85 c0                	test   %eax,%eax
		if (error)
			goto out;
		got_write = true;
	}
finish_open_created:
	error = may_open(&nd->path, acc_mode, open_flag);
ffffffff811095f1:	41 89 c6             	mov    %eax,%r14d
	if (error)
ffffffff811095f4:	0f 85 b1 00 00 00    	jne    ffffffff811096ab <do_last.isra.44+0x8d8>
		goto out;
	file->f_path.mnt = nd->path.mnt;
ffffffff811095fa:	48 8b 03             	mov    (%rbx),%rax
	error = finish_open(file, nd->path.dentry, NULL, opened);
ffffffff811095fd:	48 8b 4d a0          	mov    -0x60(%rbp),%rcx
ffffffff81109601:	31 d2                	xor    %edx,%edx
ffffffff81109603:	4c 89 ef             	mov    %r13,%rdi
	}
finish_open_created:
	error = may_open(&nd->path, acc_mode, open_flag);
	if (error)
		goto out;
	file->f_path.mnt = nd->path.mnt;
ffffffff81109606:	49 89 45 10          	mov    %rax,0x10(%r13)
	error = finish_open(file, nd->path.dentry, NULL, opened);
ffffffff8110960a:	48 8b 73 08          	mov    0x8(%rbx),%rsi
ffffffff8110960e:	e8 91 29 ff ff       	callq  ffffffff810fbfa4 <finish_open>
	if (error) {
ffffffff81109613:	85 c0                	test   %eax,%eax
finish_open_created:
	error = may_open(&nd->path, acc_mode, open_flag);
	if (error)
		goto out;
	file->f_path.mnt = nd->path.mnt;
	error = finish_open(file, nd->path.dentry, NULL, opened);
ffffffff81109615:	41 89 c6             	mov    %eax,%r14d
	if (error) {
ffffffff81109618:	74 14                	je     ffffffff8110962e <do_last.isra.44+0x85b>
		if (error == -EOPENSTALE)
ffffffff8110961a:	3d fa fd ff ff       	cmp    $0xfffffdfa,%eax
ffffffff8110961f:	0f 85 86 00 00 00    	jne    ffffffff811096ab <do_last.isra.44+0x8d8>
ffffffff81109625:	e9 c2 00 00 00       	jmpq   ffffffff811096ec <do_last.isra.44+0x919>
		if (error)
			goto out;

		if ((*opened & FILE_CREATED) ||
		    !S_ISREG(file_inode(file)->i_mode))
			will_truncate = false;
ffffffff8110962a:	c6 45 aa 00          	movb   $0x0,-0x56(%rbp)
		if (error == -EOPENSTALE)
			goto stale_open;
		goto out;
	}
opened:
	error = open_check_o_direct(file);
ffffffff8110962e:	4c 89 ef             	mov    %r13,%rdi
ffffffff81109631:	e8 e6 35 ff ff       	callq  ffffffff810fcc1c <open_check_o_direct>
	if (error)
ffffffff81109636:	85 c0                	test   %eax,%eax
		if (error == -EOPENSTALE)
			goto stale_open;
		goto out;
	}
opened:
	error = open_check_o_direct(file);
ffffffff81109638:	41 89 c6             	mov    %eax,%r14d
	if (error)
ffffffff8110963b:	0f 85 a1 00 00 00    	jne    ffffffff811096e2 <do_last.isra.44+0x90f>
		goto exit_fput;
	error = ima_file_check(file, op->acc_mode);
	if (error)
		goto exit_fput;

	if (will_truncate) {
ffffffff81109641:	80 7d aa 00          	cmpb   $0x0,-0x56(%rbp)
ffffffff81109645:	74 64                	je     ffffffff811096ab <do_last.isra.44+0x8d8>
}

static int handle_truncate(struct file *filp)
{
	struct path *path = &filp->f_path;
	struct inode *inode = path->dentry->d_inode;
ffffffff81109647:	49 8b 45 18          	mov    0x18(%r13),%rax

#ifndef atomic_inc_unless_negative
static inline int atomic_inc_unless_negative(atomic_t *p)
{
	int v, v1;
	for (v = 0; v >= 0; v = v1) {
ffffffff8110964b:	31 d2                	xor    %edx,%edx
ffffffff8110964d:	4c 8b 60 30          	mov    0x30(%rax),%r12
		v1 = atomic_cmpxchg(p, v, v + 1);
ffffffff81109651:	8d 4a 01             	lea    0x1(%rdx),%ecx
#define atomic_inc_return(v)  (atomic_add_return(1, v))
#define atomic_dec_return(v)  (atomic_sub_return(1, v))

static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
{
	return cmpxchg(&v->counter, old, new);
ffffffff81109654:	89 d0                	mov    %edx,%eax
ffffffff81109656:	f0 41 0f b1 8c 24 30 	lock cmpxchg %ecx,0x130(%r12)
ffffffff8110965d:	01 00 00 
		if (likely(v1 == v))
ffffffff81109660:	39 d0                	cmp    %edx,%eax
ffffffff81109662:	0f 84 09 01 00 00    	je     ffffffff81109771 <do_last.isra.44+0x99e>

#ifndef atomic_inc_unless_negative
static inline int atomic_inc_unless_negative(atomic_t *p)
{
	int v, v1;
	for (v = 0; v >= 0; v = v1) {
ffffffff81109668:	85 c0                	test   %eax,%eax
ffffffff8110966a:	89 c2                	mov    %eax,%edx
ffffffff8110966c:	79 e3                	jns    ffffffff81109651 <do_last.isra.44+0x87e>
 * use {get,deny}_write_access() - these functions check the sign and refuse
 * to do the change if sign is wrong.
 */
static inline int get_write_access(struct inode *inode)
{
	return atomic_inc_unless_negative(&inode->i_writecount) ? 0 : -ETXTBSY;
ffffffff8110966e:	41 be e6 ff ff ff    	mov    $0xffffffe6,%r14d
ffffffff81109674:	eb 6c                	jmp    ffffffff811096e2 <do_last.isra.44+0x90f>
 * but no group execute bit -  an otherwise meaningless combination.
 */

static inline int __mandatory_lock(struct inode *ino)
{
	return (ino->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID;
ffffffff81109676:	66 8b 00             	mov    (%rax),%ax
ffffffff81109679:	66 25 08 04          	and    $0x408,%ax
 * otherwise these will be advisory locks
 */

static inline int mandatory_lock(struct inode *ino)
{
	return IS_MANDLOCK(ino) && __mandatory_lock(ino);
ffffffff8110967d:	66 3d 00 04          	cmp    $0x400,%ax
ffffffff81109681:	0f 84 01 01 00 00    	je     ffffffff81109788 <do_last.isra.44+0x9b5>
	 */
	error = locks_verify_locked(filp);
	if (!error)
		error = security_path_truncate(path);
	if (!error) {
		error = do_truncate(path->dentry, 0,
ffffffff81109687:	49 8b 7d 18          	mov    0x18(%r13),%rdi
ffffffff8110968b:	4c 89 e9             	mov    %r13,%rcx
ffffffff8110968e:	ba 60 80 00 00       	mov    $0x8060,%edx
ffffffff81109693:	31 f6                	xor    %esi,%esi
ffffffff81109695:	e8 1c 2a ff ff       	callq  ffffffff810fc0b6 <do_truncate>
ffffffff8110969a:	41 89 c6             	mov    %eax,%r14d
 *
 * Atomically decrements @v by 1.
 */
static inline void atomic_dec(atomic_t *v)
{
	asm volatile(LOCK_PREFIX "decl %0"
ffffffff8110969d:	f0 41 ff 8c 24 30 01 	lock decl 0x130(%r12)
ffffffff811096a4:	00 00 
	if (error)
		goto exit_fput;

	if (will_truncate) {
		error = handle_truncate(file);
		if (error)
ffffffff811096a6:	45 85 f6             	test   %r14d,%r14d
ffffffff811096a9:	75 37                	jne    ffffffff811096e2 <do_last.isra.44+0x90f>
			goto exit_fput;
	}
out:
	if (got_write)
ffffffff811096ab:	80 7d ab 00          	cmpb   $0x0,-0x55(%rbp)
ffffffff811096af:	74 08                	je     ffffffff811096b9 <do_last.isra.44+0x8e6>
		mnt_drop_write(nd->path.mnt);
ffffffff811096b1:	48 8b 3b             	mov    (%rbx),%rdi
ffffffff811096b4:	e8 cf bc 00 00       	callq  ffffffff81115388 <mnt_drop_write>
	path_put(&save_parent);
ffffffff811096b9:	48 8d 7d c0          	lea    -0x40(%rbp),%rdi
ffffffff811096bd:	e8 9b b9 ff ff       	callq  ffffffff8110505d <path_put>
	terminate_walk(nd);
ffffffff811096c2:	48 89 df             	mov    %rbx,%rdi
ffffffff811096c5:	e8 b8 b9 ff ff       	callq  ffffffff81105082 <terminate_walk>
ffffffff811096ca:	e9 dc 00 00 00       	jmpq   ffffffff811097ab <do_last.isra.44+0x9d8>
	if (got_write) {
		mnt_drop_write(nd->path.mnt);
		got_write = false;
	}

	error = -EEXIST;
ffffffff811096cf:	41 be ef ff ff ff    	mov    $0xffffffef,%r14d
	path_put(&save_parent);
	terminate_walk(nd);
	return error;

exit_dput:
	path_put_conditional(path, nd);
ffffffff811096d5:	48 89 de             	mov    %rbx,%rsi
ffffffff811096d8:	4c 89 e7             	mov    %r12,%rdi
ffffffff811096db:	e8 8b c4 ff ff       	callq  ffffffff81105b6b <path_put_conditional.isra.28>
ffffffff811096e0:	eb d7                	jmp    ffffffff811096b9 <do_last.isra.44+0x8e6>
	goto out;
exit_fput:
	fput(file);
ffffffff811096e2:	4c 89 ef             	mov    %r13,%rdi
ffffffff811096e5:	e8 0c 52 ff ff       	callq  ffffffff810fe8f6 <fput>
ffffffff811096ea:	eb bf                	jmp    ffffffff811096ab <do_last.isra.44+0x8d8>
	goto out;

stale_open:
	/* If no saved parent or already retried then can't retry */
	if (!save_parent.dentry || retried)
ffffffff811096ec:	48 8b 45 c8          	mov    -0x38(%rbp),%rax
ffffffff811096f0:	48 85 c0             	test   %rax,%rax
ffffffff811096f3:	74 b6                	je     ffffffff811096ab <do_last.isra.44+0x8d8>
ffffffff811096f5:	80 7d 92 00          	cmpb   $0x0,-0x6e(%rbp)
ffffffff811096f9:	75 b0                	jne    ffffffff811096ab <do_last.isra.44+0x8d8>
		goto out;

	BUG_ON(save_parent.dentry != dir);
ffffffff811096fb:	48 3b 45 80          	cmp    -0x80(%rbp),%rax
ffffffff811096ff:	74 02                	je     ffffffff81109703 <do_last.isra.44+0x930>
ffffffff81109701:	0f 0b                	ud2    
	path_put(&nd->path);
ffffffff81109703:	48 89 df             	mov    %rbx,%rdi
ffffffff81109706:	e8 52 b9 ff ff       	callq  ffffffff8110505d <path_put>
	nd->path = save_parent;
ffffffff8110970b:	48 8b 45 c8          	mov    -0x38(%rbp),%rax
ffffffff8110970f:	48 8b 7d c0          	mov    -0x40(%rbp),%rdi
	nd->inode = dir->d_inode;
ffffffff81109713:	48 8b 55 80          	mov    -0x80(%rbp),%rdx
	save_parent.mnt = NULL;
	save_parent.dentry = NULL;
	if (got_write) {
ffffffff81109717:	80 7d ab 00          	cmpb   $0x0,-0x55(%rbp)

	BUG_ON(save_parent.dentry != dir);
	path_put(&nd->path);
	nd->path = save_parent;
	nd->inode = dir->d_inode;
	save_parent.mnt = NULL;
ffffffff8110971b:	48 c7 45 c0 00 00 00 	movq   $0x0,-0x40(%rbp)
ffffffff81109722:	00 
	save_parent.dentry = NULL;
ffffffff81109723:	48 c7 45 c8 00 00 00 	movq   $0x0,-0x38(%rbp)
ffffffff8110972a:	00 
	if (!save_parent.dentry || retried)
		goto out;

	BUG_ON(save_parent.dentry != dir);
	path_put(&nd->path);
	nd->path = save_parent;
ffffffff8110972b:	48 89 3b             	mov    %rdi,(%rbx)
ffffffff8110972e:	48 89 43 08          	mov    %rax,0x8(%rbx)
	nd->inode = dir->d_inode;
ffffffff81109732:	48 8b 42 30          	mov    0x30(%rdx),%rax
	save_parent.dentry = NULL;
	if (got_write) {
		mnt_drop_write(nd->path.mnt);
		got_write = false;
	}
	retried = true;
ffffffff81109736:	c6 45 92 01          	movb   $0x1,-0x6e(%rbp)
		goto out;

	BUG_ON(save_parent.dentry != dir);
	path_put(&nd->path);
	nd->path = save_parent;
	nd->inode = dir->d_inode;
ffffffff8110973a:	48 89 43 30          	mov    %rax,0x30(%rbx)
	save_parent.mnt = NULL;
	save_parent.dentry = NULL;
	if (got_write) {
ffffffff8110973e:	0f 84 c0 f7 ff ff    	je     ffffffff81108f04 <do_last.isra.44+0x131>
		mnt_drop_write(nd->path.mnt);
ffffffff81109744:	e8 3f bc 00 00       	callq  ffffffff81115388 <mnt_drop_write>
ffffffff81109749:	e9 b6 f7 ff ff       	jmpq   ffffffff81108f04 <do_last.isra.44+0x131>
static inline int handle_dots(struct nameidata *nd, int type)
{
	if (type == LAST_DOTDOT) {
		if (nd->flags & LOOKUP_RCU) {
			if (follow_dotdot_rcu(nd))
				return -ECHILD;
ffffffff8110974e:	41 be f6 ff ff ff    	mov    $0xfffffff6,%r14d
ffffffff81109754:	eb 55                	jmp    ffffffff811097ab <do_last.isra.44+0x9d8>
	bool got_write = false;
	int acc_mode = op->acc_mode;
	struct inode *inode;
	bool symlink_ok = false;
	struct path save_parent = { .dentry = NULL, .mnt = NULL };
	bool retried = false;
ffffffff81109756:	c6 45 92 00          	movb   $0x0,-0x6e(%rbp)
	int open_flag = op->open_flag;
	bool will_truncate = (open_flag & O_TRUNC) != 0;
	bool got_write = false;
	int acc_mode = op->acc_mode;
	struct inode *inode;
	bool symlink_ok = false;
ffffffff8110975a:	c6 45 93 00          	movb   $0x0,-0x6d(%rbp)
ffffffff8110975e:	e9 cd fd ff ff       	jmpq   ffffffff81109530 <do_last.isra.44+0x75d>
	if (error) {	/* returned 1, that is */
		if (WARN_ON(file->f_path.dentry == DENTRY_NOT_SET)) {
			error = -EIO;
			goto out;
		}
		if (file->f_path.dentry) {
ffffffff81109763:	48 85 c0             	test   %rax,%rax
ffffffff81109766:	0f 85 d2 f9 ff ff    	jne    ffffffff8110913e <do_last.isra.44+0x36b>
ffffffff8110976c:	e9 d9 f9 ff ff       	jmpq   ffffffff8110914a <do_last.isra.44+0x377>
const struct inode_operations page_symlink_inode_operations = {
	.readlink	= generic_readlink,
	.follow_link	= page_follow_link_light,
	.put_link	= page_put_link,
};
EXPORT_SYMBOL(page_symlink_inode_operations);
ffffffff81109771:	49 8b 45 20          	mov    0x20(%r13),%rax
ffffffff81109775:	48 8b 50 28          	mov    0x28(%rax),%rdx
ffffffff81109779:	f6 42 50 40          	testb  $0x40,0x50(%rdx)
ffffffff8110977d:	0f 85 f3 fe ff ff    	jne    ffffffff81109676 <do_last.isra.44+0x8a3>
ffffffff81109783:	e9 ff fe ff ff       	jmpq   ffffffff81109687 <do_last.isra.44+0x8b4>
}

static inline int locks_verify_locked(struct file *file)
{
	if (mandatory_lock(file_inode(file)))
		return locks_mandatory_locked(file);
ffffffff81109788:	4c 89 ef             	mov    %r13,%rdi
ffffffff8110978b:	e8 52 0c 03 00       	callq  ffffffff8113a3e2 <locks_mandatory_locked>
		return error;
	/*
	 * Refuse to truncate files with mandatory locks held on them.
	 */
	error = locks_verify_locked(filp);
	if (!error)
ffffffff81109790:	85 c0                	test   %eax,%eax
ffffffff81109792:	41 89 c6             	mov    %eax,%r14d
ffffffff81109795:	0f 85 02 ff ff ff    	jne    ffffffff8110969d <do_last.isra.44+0x8ca>
ffffffff8110979b:	e9 e7 fe ff ff       	jmpq   ffffffff81109687 <do_last.isra.44+0x8b4>
	}

	if (should_follow_link(path->dentry, !symlink_ok)) {
		if (nd->flags & LOOKUP_RCU) {
			if (unlikely(unlazy_walk(nd, path->dentry))) {
				error = -ECHILD;
ffffffff811097a0:	41 be f6 ff ff ff    	mov    $0xfffffff6,%r14d
ffffffff811097a6:	e9 0e ff ff ff       	jmpq   ffffffff811096b9 <do_last.isra.44+0x8e6>
		mnt_drop_write(nd->path.mnt);
		got_write = false;
	}
	retried = true;
	goto retry_lookup;
}
ffffffff811097ab:	48 83 c4 78          	add    $0x78,%rsp
ffffffff811097af:	44 89 f0             	mov    %r14d,%eax
ffffffff811097b2:	5b                   	pop    %rbx
ffffffff811097b3:	41 5c                	pop    %r12
ffffffff811097b5:	41 5d                	pop    %r13
ffffffff811097b7:	41 5e                	pop    %r14
ffffffff811097b9:	41 5f                	pop    %r15
ffffffff811097bb:	5d                   	pop    %rbp
ffffffff811097bc:	c3                   	retq   

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: panic in do_last()
  2014-04-18  2:17   ` Al Viro
  2014-04-18  2:22     ` Lin Ming
@ 2014-04-18  2:35     ` Lin Ming
  2014-04-18  2:42       ` Al Viro
  1 sibling, 1 reply; 12+ messages in thread
From: Lin Ming @ 2014-04-18  2:35 UTC (permalink / raw)
  To: Al Viro; +Cc: David Howells, linux-fsdevel, Hugh Dickins

On Thu, Apr 17, 2014 at 7:17 PM, Al Viro <viro@zeniv.linux.org.uk> wrote:
> On Fri, Apr 18, 2014 at 02:57:50AM +0100, Al Viro wrote:
>
>> Where is it in do_last()?  Hard to tell without even the hex dump of
>> oopsing code (and trying to reproduce it here hasn't produced any oopsen
>> so far).
>
> Hmm...  Still no oopsen, but it looks like it *is* possible to get
> screwed there.  RCU mode isn't a problem, AFAICS (we'll fail on d_seq
> mismatch in complete_walk() and that will be the end of it), but
> non-lazy mode *can* get buggered.  We are holding a reference to
> nd->path.dentry and that's enough to prevent positive-to-negative
> transition, but negative-to-positive is fair game.  So it does
> happen and we end up with nd->inode being set to NULL.  And _that_
> promptly blows up on
>         if (!S_ISREG(nd->inode->i_mode))
>                 will_truncate = false;
> Actually, it might very well be the only source of breakage - that late
> in the game (already out of RCU mode, for starters) we don't give a damn
> about nd->inode.
>
> Ah, actually there's also
>                 BUG_ON(inode != path->dentry->d_inode);
> in symlink case (similar "negative to positive", but it will be a symlink(2),
> not creat(2)).  Pointless BUG_ON, actually...
>
> The reason why your reordering hadn't done any good is that CPU cache is free
> to reorder behind your back - no barriers between these two stores.

Added a barrier(), but still panic.

diff --git a/fs/dcache.c b/fs/dcache.c
index 40707d8..1d6b529 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1647,11 +1647,12 @@ 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;
+      barrier();
        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);

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: panic in do_last()
       [not found]   ` <CAF1ivSbqM2LorrED3MvgKBDxA9sLz_RkOEPwAfvYYmL5C9K0vA@mail.gmail.com>
@ 2014-04-18  2:38     ` Al Viro
  2014-04-18  2:48       ` Al Viro
  0 siblings, 1 reply; 12+ messages in thread
From: Al Viro @ 2014-04-18  2:38 UTC (permalink / raw)
  To: Lin Ming; +Cc: David Howells, linux-fsdevel, Hugh Dickins, Linus Torvalds

On Thu, Apr 17, 2014 at 07:16:30PM -0700, Lin Ming wrote:
> (gdb) list *do_last+0x7d2
> 0xffffffff811095a5 is in do_last (/home/mlin/linux/fs/namei.c:3036).
> 3031 if ((open_flag & O_CREAT) && d_is_dir(nd->path.dentry))
> 3032            goto out;
> 3033 error = -ENOTDIR;
> 3034 if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry))
> 3035            goto out;
> 3036 if (!S_ISREG(nd->inode->i_mode))
> 3037            will_truncate = false;

Aha, so my guess in another posting was correct.  OK...

So it's not about RCU case at all - if dentry changes under us
in lazy mode, we'll simply fail when we get to checking d_seq.  It's
non-lazy case + transition from negative to positive that causes the
trouble.

Another piece of breakage in there is should_follow_link() directly
afterwards - there the problem is with false negatives.  I.e. we
see new dentry->d_inode, but not the new dentry->d_flags.

I wonder if the right fix would be simply
	if (!inode || d_is_negative(dentry))
bailing out unless both updates are seen.  Probably cheaper than any
games with barriers...

Comments?

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: panic in do_last()
  2014-04-18  2:35     ` Lin Ming
@ 2014-04-18  2:42       ` Al Viro
  0 siblings, 0 replies; 12+ messages in thread
From: Al Viro @ 2014-04-18  2:42 UTC (permalink / raw)
  To: Lin Ming; +Cc: David Howells, linux-fsdevel, Hugh Dickins

On Thu, Apr 17, 2014 at 07:35:14PM -0700, Lin Ming wrote:
> Added a barrier(), but still panic.

Wrong kind of barrier ;-)  This one just says the compiler that it
shouldn't reorder; it doesn't help other CPUs at all.

Read Documentation/memory-barriers.txt for details, but I seriously
wonder if we _want_ to mess with barriers in the first place...

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: panic in do_last()
  2014-04-18  2:38     ` Al Viro
@ 2014-04-18  2:48       ` Al Viro
  2014-04-18  3:17         ` Al Viro
  0 siblings, 1 reply; 12+ messages in thread
From: Al Viro @ 2014-04-18  2:48 UTC (permalink / raw)
  To: Lin Ming; +Cc: David Howells, linux-fsdevel, Hugh Dickins, Linus Torvalds

On Fri, Apr 18, 2014 at 03:38:22AM +0100, Al Viro wrote:
> Aha, so my guess in another posting was correct.  OK...
> 
> So it's not about RCU case at all - if dentry changes under us
> in lazy mode, we'll simply fail when we get to checking d_seq.  It's
> non-lazy case + transition from negative to positive that causes the
> trouble.
> 
> Another piece of breakage in there is should_follow_link() directly
> afterwards - there the problem is with false negatives.  I.e. we
> see new dentry->d_inode, but not the new dentry->d_flags.
> 
> I wonder if the right fix would be simply
> 	if (!inode || d_is_negative(dentry))
> bailing out unless both updates are seen.  Probably cheaper than any
> games with barriers...

Crap...  No, it's a bit trickier - we start with clearing all flags,
so if we see the _intermediate_ d_flags and new d_inode, we'll sail
past the check.  Which would leave us with correct inode, but might
give us a false negative in should_follow_link().

Hmm...  How about the following, then?

diff --git a/fs/dcache.c b/fs/dcache.c
index 40707d8..494a9def 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1647,8 +1647,7 @@ 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_flags &= ~DCACHE_ENTRY_TYPE;
-	dentry->d_flags |= add_flags;
+	__d_set_type(dentry, add_flags);
 	if (inode)
 		hlist_add_head(&dentry->d_alias, &inode->i_dentry);
 	dentry->d_inode = inode;
diff --git a/fs/namei.c b/fs/namei.c
index c6157c8..7560db7 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2994,7 +2994,7 @@ retry_lookup:
 finish_lookup:
 	/* we _can_ be in RCU mode here */
 	error = -ENOENT;
-	if (d_is_negative(path->dentry)) {
+	if (!inode || d_is_negative(path->dentry)) {
 		path_to_nameidata(path, nd);
 		goto out;
 	}

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: panic in do_last()
  2014-04-18  2:48       ` Al Viro
@ 2014-04-18  3:17         ` Al Viro
  2014-04-18  3:40           ` Lin Ming
  0 siblings, 1 reply; 12+ messages in thread
From: Al Viro @ 2014-04-18  3:17 UTC (permalink / raw)
  To: Lin Ming; +Cc: David Howells, linux-fsdevel, Hugh Dickins, Linus Torvalds

On Fri, Apr 18, 2014 at 03:48:37AM +0100, Al Viro wrote:
> Crap...  No, it's a bit trickier - we start with clearing all flags,
> so if we see the _intermediate_ d_flags and new d_inode, we'll sail
> past the check.  Which would leave us with correct inode, but might
> give us a false negative in should_follow_link().

Note that most of the places calling d_is_...() are protected by
the following: if we'd obtained dentry by __lookup_hash() and friends
*after* grabbing ->i_mutex on parent, we are fine - both positive-to-negative
and negative-to-positive are possible only with ->i_mutex held, so it
gives us a barrier.

AFAICS, there are two more tricky places: walk_component() doing
        if (!inode)
                goto out_path_put;

        if (should_follow_link(path->dentry, follow)) {
with unpleasant consequences if the second test gives a false negative,
and similar for mountpoint_last().

Basically, we'd concentrated on RCU races back then, and missed the possibility
of non-RCU-but-without-i_mutex ones.  Proposed fix follows:

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
diff --git a/fs/dcache.c b/fs/dcache.c
index 40707d8..494a9def 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1647,8 +1647,7 @@ 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_flags &= ~DCACHE_ENTRY_TYPE;
-	dentry->d_flags |= add_flags;
+	__d_set_type(dentry, add_flags);
 	if (inode)
 		hlist_add_head(&dentry->d_alias, &inode->i_dentry);
 	dentry->d_inode = inode;
diff --git a/fs/namei.c b/fs/namei.c
index c6157c8..8016827 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1542,7 +1542,7 @@ static inline int walk_component(struct nameidata *nd, struct path *path,
 		inode = path->dentry->d_inode;
 	}
 	err = -ENOENT;
-	if (!inode)
+	if (!inode || d_is_negative(path->dentry))
 		goto out_path_put;
 
 	if (should_follow_link(path->dentry, follow)) {
@@ -2249,7 +2249,7 @@ mountpoint_last(struct nameidata *nd, struct path *path)
 	mutex_unlock(&dir->d_inode->i_mutex);
 
 done:
-	if (!dentry->d_inode) {
+	if (!dentry->d_inode || d_is_negative(dentry)) {
 		error = -ENOENT;
 		dput(dentry);
 		goto out;
@@ -2994,7 +2994,7 @@ retry_lookup:
 finish_lookup:
 	/* we _can_ be in RCU mode here */
 	error = -ENOENT;
-	if (d_is_negative(path->dentry)) {
+	if (!inode || d_is_negative(path->dentry)) {
 		path_to_nameidata(path, nd);
 		goto out;
 	}

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: panic in do_last()
  2014-04-18  3:17         ` Al Viro
@ 2014-04-18  3:40           ` Lin Ming
  2014-04-18 15:11             ` Lin Ming
  0 siblings, 1 reply; 12+ messages in thread
From: Lin Ming @ 2014-04-18  3:40 UTC (permalink / raw)
  To: Al Viro; +Cc: David Howells, linux-fsdevel, Hugh Dickins, Linus Torvalds

On Thu, Apr 17, 2014 at 8:17 PM, Al Viro <viro@zeniv.linux.org.uk> wrote:
> On Fri, Apr 18, 2014 at 03:48:37AM +0100, Al Viro wrote:
>> Crap...  No, it's a bit trickier - we start with clearing all flags,
>> so if we see the _intermediate_ d_flags and new d_inode, we'll sail
>> past the check.  Which would leave us with correct inode, but might
>> give us a false negative in should_follow_link().
>
> Note that most of the places calling d_is_...() are protected by
> the following: if we'd obtained dentry by __lookup_hash() and friends
> *after* grabbing ->i_mutex on parent, we are fine - both positive-to-negative
> and negative-to-positive are possible only with ->i_mutex held, so it
> gives us a barrier.
>
> AFAICS, there are two more tricky places: walk_component() doing
>         if (!inode)
>                 goto out_path_put;
>
>         if (should_follow_link(path->dentry, follow)) {
> with unpleasant consequences if the second test gives a false negative,
> and similar for mountpoint_last().
>
> Basically, we'd concentrated on RCU races back then, and missed the possibility
> of non-RCU-but-without-i_mutex ones.  Proposed fix follows:

Should be OK. I'll test it tomorrow.

Thanks.

>
> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
> ---
> diff --git a/fs/dcache.c b/fs/dcache.c
> index 40707d8..494a9def 100644
> --- a/fs/dcache.c
> +++ b/fs/dcache.c
> @@ -1647,8 +1647,7 @@ 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_flags &= ~DCACHE_ENTRY_TYPE;
> -       dentry->d_flags |= add_flags;
> +       __d_set_type(dentry, add_flags);
>         if (inode)
>                 hlist_add_head(&dentry->d_alias, &inode->i_dentry);
>         dentry->d_inode = inode;
> diff --git a/fs/namei.c b/fs/namei.c
> index c6157c8..8016827 100644
> --- a/fs/namei.c
> +++ b/fs/namei.c
> @@ -1542,7 +1542,7 @@ static inline int walk_component(struct nameidata *nd, struct path *path,
>                 inode = path->dentry->d_inode;
>         }
>         err = -ENOENT;
> -       if (!inode)
> +       if (!inode || d_is_negative(path->dentry))
>                 goto out_path_put;
>
>         if (should_follow_link(path->dentry, follow)) {
> @@ -2249,7 +2249,7 @@ mountpoint_last(struct nameidata *nd, struct path *path)
>         mutex_unlock(&dir->d_inode->i_mutex);
>
>  done:
> -       if (!dentry->d_inode) {
> +       if (!dentry->d_inode || d_is_negative(dentry)) {
>                 error = -ENOENT;
>                 dput(dentry);
>                 goto out;
> @@ -2994,7 +2994,7 @@ retry_lookup:
>  finish_lookup:
>         /* we _can_ be in RCU mode here */
>         error = -ENOENT;
> -       if (d_is_negative(path->dentry)) {
> +       if (!inode || d_is_negative(path->dentry)) {
>                 path_to_nameidata(path, nd);
>                 goto out;
>         }

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: panic in do_last()
  2014-04-18  3:40           ` Lin Ming
@ 2014-04-18 15:11             ` Lin Ming
  2014-04-22 17:51               ` Lin Ming
  0 siblings, 1 reply; 12+ messages in thread
From: Lin Ming @ 2014-04-18 15:11 UTC (permalink / raw)
  To: Al Viro; +Cc: David Howells, linux-fsdevel, Hugh Dickins, Linus Torvalds

On Thu, Apr 17, 2014 at 8:40 PM, Lin Ming <minggr@gmail.com> wrote:
> On Thu, Apr 17, 2014 at 8:17 PM, Al Viro <viro@zeniv.linux.org.uk> wrote:
>> On Fri, Apr 18, 2014 at 03:48:37AM +0100, Al Viro wrote:
>>> Crap...  No, it's a bit trickier - we start with clearing all flags,
>>> so if we see the _intermediate_ d_flags and new d_inode, we'll sail
>>> past the check.  Which would leave us with correct inode, but might
>>> give us a false negative in should_follow_link().
>>
>> Note that most of the places calling d_is_...() are protected by
>> the following: if we'd obtained dentry by __lookup_hash() and friends
>> *after* grabbing ->i_mutex on parent, we are fine - both positive-to-negative
>> and negative-to-positive are possible only with ->i_mutex held, so it
>> gives us a barrier.
>>
>> AFAICS, there are two more tricky places: walk_component() doing
>>         if (!inode)
>>                 goto out_path_put;
>>
>>         if (should_follow_link(path->dentry, follow)) {
>> with unpleasant consequences if the second test gives a false negative,
>> and similar for mountpoint_last().
>>
>> Basically, we'd concentrated on RCU races back then, and missed the possibility
>> of non-RCU-but-without-i_mutex ones.  Proposed fix follows:
>
> Should be OK. I'll test it tomorrow.

Confirmed it's OK.

Reported-and-tested-by: Lin Ming <minggr@gmail.com>

Thanks.

>
> Thanks.
>
>>
>> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
>> ---
>> diff --git a/fs/dcache.c b/fs/dcache.c
>> index 40707d8..494a9def 100644
>> --- a/fs/dcache.c
>> +++ b/fs/dcache.c
>> @@ -1647,8 +1647,7 @@ 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_flags &= ~DCACHE_ENTRY_TYPE;
>> -       dentry->d_flags |= add_flags;
>> +       __d_set_type(dentry, add_flags);
>>         if (inode)
>>                 hlist_add_head(&dentry->d_alias, &inode->i_dentry);
>>         dentry->d_inode = inode;
>> diff --git a/fs/namei.c b/fs/namei.c
>> index c6157c8..8016827 100644
>> --- a/fs/namei.c
>> +++ b/fs/namei.c
>> @@ -1542,7 +1542,7 @@ static inline int walk_component(struct nameidata *nd, struct path *path,
>>                 inode = path->dentry->d_inode;
>>         }
>>         err = -ENOENT;
>> -       if (!inode)
>> +       if (!inode || d_is_negative(path->dentry))
>>                 goto out_path_put;
>>
>>         if (should_follow_link(path->dentry, follow)) {
>> @@ -2249,7 +2249,7 @@ mountpoint_last(struct nameidata *nd, struct path *path)
>>         mutex_unlock(&dir->d_inode->i_mutex);
>>
>>  done:
>> -       if (!dentry->d_inode) {
>> +       if (!dentry->d_inode || d_is_negative(dentry)) {
>>                 error = -ENOENT;
>>                 dput(dentry);
>>                 goto out;
>> @@ -2994,7 +2994,7 @@ retry_lookup:
>>  finish_lookup:
>>         /* we _can_ be in RCU mode here */
>>         error = -ENOENT;
>> -       if (d_is_negative(path->dentry)) {
>> +       if (!inode || d_is_negative(path->dentry)) {
>>                 path_to_nameidata(path, nd);
>>                 goto out;
>>         }

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: panic in do_last()
  2014-04-18 15:11             ` Lin Ming
@ 2014-04-22 17:51               ` Lin Ming
  0 siblings, 0 replies; 12+ messages in thread
From: Lin Ming @ 2014-04-22 17:51 UTC (permalink / raw)
  To: Al Viro; +Cc: David Howells, linux-fsdevel, Hugh Dickins, Linus Torvalds

On Fri, Apr 18, 2014 at 8:11 AM, Lin Ming <minggr@gmail.com> wrote:
> On Thu, Apr 17, 2014 at 8:40 PM, Lin Ming <minggr@gmail.com> wrote:
>> On Thu, Apr 17, 2014 at 8:17 PM, Al Viro <viro@zeniv.linux.org.uk> wrote:
>>> On Fri, Apr 18, 2014 at 03:48:37AM +0100, Al Viro wrote:
>>>> Crap...  No, it's a bit trickier - we start with clearing all flags,
>>>> so if we see the _intermediate_ d_flags and new d_inode, we'll sail
>>>> past the check.  Which would leave us with correct inode, but might
>>>> give us a false negative in should_follow_link().
>>>
>>> Note that most of the places calling d_is_...() are protected by
>>> the following: if we'd obtained dentry by __lookup_hash() and friends
>>> *after* grabbing ->i_mutex on parent, we are fine - both positive-to-negative
>>> and negative-to-positive are possible only with ->i_mutex held, so it
>>> gives us a barrier.
>>>
>>> AFAICS, there are two more tricky places: walk_component() doing
>>>         if (!inode)
>>>                 goto out_path_put;
>>>
>>>         if (should_follow_link(path->dentry, follow)) {
>>> with unpleasant consequences if the second test gives a false negative,
>>> and similar for mountpoint_last().
>>>
>>> Basically, we'd concentrated on RCU races back then, and missed the possibility
>>> of non-RCU-but-without-i_mutex ones.  Proposed fix follows:
>>
>> Should be OK. I'll test it tomorrow.
>
> Confirmed it's OK.
>
> Reported-and-tested-by: Lin Ming <minggr@gmail.com>

Hi Al,

Was this fix merged in your vfs tree?

Thanks.

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2014-04-22 17:51 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-04-18  1:14 panic in do_last() Lin Ming
2014-04-18  1:57 ` Al Viro
2014-04-18  2:17   ` Al Viro
2014-04-18  2:22     ` Lin Ming
2014-04-18  2:35     ` Lin Ming
2014-04-18  2:42       ` Al Viro
     [not found]   ` <CAF1ivSbqM2LorrED3MvgKBDxA9sLz_RkOEPwAfvYYmL5C9K0vA@mail.gmail.com>
2014-04-18  2:38     ` Al Viro
2014-04-18  2:48       ` Al Viro
2014-04-18  3:17         ` Al Viro
2014-04-18  3:40           ` Lin Ming
2014-04-18 15:11             ` Lin Ming
2014-04-22 17:51               ` Lin Ming

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).