| From 0a377cff9428af2da2b293d11e07bc4dbf064ee5 Mon Sep 17 00:00:00 2001 |
| From: Trond Myklebust <Trond.Myklebust@netapp.com> |
| Date: Wed, 18 Aug 2010 09:25:42 -0400 |
| Subject: NFS: Fix an Oops in the NFSv4 atomic open code |
| |
| From: Trond Myklebust <Trond.Myklebust@netapp.com> |
| |
| commit 0a377cff9428af2da2b293d11e07bc4dbf064ee5 upstream. |
| |
| Adam Lackorzynski reports: |
| |
| with 2.6.35.2 I'm getting this reproducible Oops: |
| |
| [ 110.825396] BUG: unable to handle kernel NULL pointer dereference at |
| (null) |
| [ 110.828638] IP: [<ffffffff811247b7>] encode_attrs+0x1a/0x2a4 |
| [ 110.828638] PGD be89f067 PUD bf18f067 PMD 0 |
| [ 110.828638] Oops: 0000 [#1] SMP |
| [ 110.828638] last sysfs file: /sys/class/net/lo/operstate |
| [ 110.828638] CPU 2 |
| [ 110.828638] Modules linked in: rtc_cmos rtc_core rtc_lib amd64_edac_mod |
| i2c_amd756 edac_core i2c_core dm_mirror dm_region_hash dm_log dm_snapshot |
| sg sr_mod usb_storage ohci_hcd mptspi tg3 mptscsih mptbase usbcore nls_base |
| [last unloaded: scsi_wait_scan] |
| [ 110.828638] |
| [ 110.828638] Pid: 11264, comm: setchecksum Not tainted 2.6.35.2 #1 |
| [ 110.828638] RIP: 0010:[<ffffffff811247b7>] [<ffffffff811247b7>] |
| encode_attrs+0x1a/0x2a4 |
| [ 110.828638] RSP: 0000:ffff88003bf5b878 EFLAGS: 00010296 |
| [ 110.828638] RAX: ffff8800bddb48a8 RBX: ffff88003bf5bb18 RCX: |
| 0000000000000000 |
| [ 110.828638] RDX: ffff8800be258800 RSI: 0000000000000000 RDI: |
| ffff88003bf5b9f8 |
| [ 110.828638] RBP: 0000000000000000 R08: ffff8800bddb48a8 R09: |
| 0000000000000004 |
| [ 110.828638] R10: 0000000000000003 R11: ffff8800be779000 R12: |
| ffff8800be258800 |
| [ 110.828638] R13: ffff88003bf5b9f8 R14: ffff88003bf5bb20 R15: |
| ffff8800be258800 |
| [ 110.828638] FS: 0000000000000000(0000) GS:ffff880041e00000(0063) |
| knlGS:00000000556bd6b0 |
| [ 110.828638] CS: 0010 DS: 002b ES: 002b CR0: 000000008005003b |
| [ 110.828638] CR2: 0000000000000000 CR3: 00000000be8ef000 CR4: |
| 00000000000006e0 |
| [ 110.828638] DR0: 0000000000000000 DR1: 0000000000000000 DR2: |
| 0000000000000000 |
| [ 110.828638] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: |
| 0000000000000400 |
| [ 110.828638] Process setchecksum (pid: 11264, threadinfo |
| ffff88003bf5a000, task ffff88003f232210) |
| [ 110.828638] Stack: |
| [ 110.828638] 0000000000000000 ffff8800bfbcf920 0000000000000000 |
| 0000000000000ffe |
| [ 110.828638] <0> 0000000000000000 0000000000000000 0000000000000000 |
| 0000000000000000 |
| [ 110.828638] <0> 0000000000000000 0000000000000000 0000000000000000 |
| 0000000000000000 |
| [ 110.828638] Call Trace: |
| [ 110.828638] [<ffffffff81124c1f>] ? nfs4_xdr_enc_setattr+0x90/0xb4 |
| [ 110.828638] [<ffffffff81371161>] ? call_transmit+0x1c3/0x24a |
| [ 110.828638] [<ffffffff813774d9>] ? __rpc_execute+0x78/0x22a |
| [ 110.828638] [<ffffffff81371a91>] ? rpc_run_task+0x21/0x2b |
| [ 110.828638] [<ffffffff81371b7e>] ? rpc_call_sync+0x3d/0x5d |
| [ 110.828638] [<ffffffff8111e284>] ? _nfs4_do_setattr+0x11b/0x147 |
| [ 110.828638] [<ffffffff81109466>] ? nfs_init_locked+0x0/0x32 |
| [ 110.828638] [<ffffffff810ac521>] ? ifind+0x4e/0x90 |
| [ 110.828638] [<ffffffff8111e2fb>] ? nfs4_do_setattr+0x4b/0x6e |
| [ 110.828638] [<ffffffff8111e634>] ? nfs4_do_open+0x291/0x3a6 |
| [ 110.828638] [<ffffffff8111ed81>] ? nfs4_open_revalidate+0x63/0x14a |
| [ 110.828638] [<ffffffff811056c4>] ? nfs_open_revalidate+0xd7/0x161 |
| [ 110.828638] [<ffffffff810a2de4>] ? do_lookup+0x1a4/0x201 |
| [ 110.828638] [<ffffffff810a4733>] ? link_path_walk+0x6a/0x9d5 |
| [ 110.828638] [<ffffffff810a42b6>] ? do_last+0x17b/0x58e |
| [ 110.828638] [<ffffffff810a5fbe>] ? do_filp_open+0x1bd/0x56e |
| [ 110.828638] [<ffffffff811cd5e0>] ? _atomic_dec_and_lock+0x30/0x48 |
| [ 110.828638] [<ffffffff810a9b1b>] ? dput+0x37/0x152 |
| [ 110.828638] [<ffffffff810ae063>] ? alloc_fd+0x69/0x10a |
| [ 110.828638] [<ffffffff81099f39>] ? do_sys_open+0x56/0x100 |
| [ 110.828638] [<ffffffff81027a22>] ? ia32_sysret+0x0/0x5 |
| [ 110.828638] Code: 83 f1 01 e8 f5 ca ff ff 48 83 c4 50 5b 5d 41 5c c3 41 |
| 57 41 56 41 55 49 89 fd 41 54 49 89 d4 55 48 89 f5 53 48 81 ec 18 01 00 00 |
| <8b> 06 89 c2 83 e2 08 83 fa 01 19 db 83 e3 f8 83 c3 18 a8 01 8d |
| [ 110.828638] RIP [<ffffffff811247b7>] encode_attrs+0x1a/0x2a4 |
| [ 110.828638] RSP <ffff88003bf5b878> |
| [ 110.828638] CR2: 0000000000000000 |
| [ 112.840396] ---[ end trace 95282e83fd77358f ]--- |
| |
| We need to ensure that the O_EXCL flag is turned off if the user doesn't |
| set O_CREAT. |
| |
| Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| fs/nfs/dir.c | 2 +- |
| fs/nfs/nfs4proc.c | 8 +++++--- |
| 2 files changed, 6 insertions(+), 4 deletions(-) |
| |
| --- a/fs/nfs/dir.c |
| +++ b/fs/nfs/dir.c |
| @@ -1103,7 +1103,7 @@ static int nfs_open_revalidate(struct de |
| if ((openflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) |
| goto no_open_dput; |
| /* We can't create new files, or truncate existing ones here */ |
| - openflags &= ~(O_CREAT|O_TRUNC); |
| + openflags &= ~(O_CREAT|O_EXCL|O_TRUNC); |
| |
| /* |
| * Note: we're not holding inode->i_mutex and so may be racing with |
| --- a/fs/nfs/nfs4proc.c |
| +++ b/fs/nfs/nfs4proc.c |
| @@ -2023,7 +2023,8 @@ nfs4_atomic_open(struct inode *dir, stru |
| struct rpc_cred *cred; |
| struct nfs4_state *state; |
| struct dentry *res; |
| - fmode_t fmode = nd->intent.open.flags & (FMODE_READ | FMODE_WRITE | FMODE_EXEC); |
| + int open_flags = nd->intent.open.flags; |
| + fmode_t fmode = open_flags & (FMODE_READ | FMODE_WRITE | FMODE_EXEC); |
| |
| if (nd->flags & LOOKUP_CREATE) { |
| attr.ia_mode = nd->intent.open.create_mode; |
| @@ -2031,8 +2032,9 @@ nfs4_atomic_open(struct inode *dir, stru |
| if (!IS_POSIXACL(dir)) |
| attr.ia_mode &= ~current_umask(); |
| } else { |
| + open_flags &= ~O_EXCL; |
| attr.ia_valid = 0; |
| - BUG_ON(nd->intent.open.flags & O_CREAT); |
| + BUG_ON(open_flags & O_CREAT); |
| } |
| |
| cred = rpc_lookup_cred(); |
| @@ -2041,7 +2043,7 @@ nfs4_atomic_open(struct inode *dir, stru |
| parent = dentry->d_parent; |
| /* Protect against concurrent sillydeletes */ |
| nfs_block_sillyrename(parent); |
| - state = nfs4_do_open(dir, &path, fmode, nd->intent.open.flags, &attr, cred); |
| + state = nfs4_do_open(dir, &path, fmode, open_flags, &attr, cred); |
| put_rpccred(cred); |
| if (IS_ERR(state)) { |
| if (PTR_ERR(state) == -ENOENT) { |