diff options
author | Jeff Layton <jlayton@redhat.com> | 2013-06-18 17:10:29 +0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2013-06-18 21:46:50 +0400 |
commit | e401452d923de5b27f61f707773ec38f5593d985 (patch) | |
tree | 55e0b396def5d438c61db191b403adeef2f50476 /net/sunrpc/rpc_pipe.c | |
parent | fe2d5395c417c2364936002b87901b02a18787b1 (diff) | |
download | linux-e401452d923de5b27f61f707773ec38f5593d985.tar.xz |
rpc_pipefs: only set rpc_dentry_ops if d_op isn't already set
We had a report of a reproducible WARNING:
[ 1360.039358] ------------[ cut here ]------------
[ 1360.043978] WARNING: at fs/dcache.c:1355 d_set_d_op+0x8d/0xc0()
[ 1360.049880] Hardware name: HP Z200 Workstation
[ 1360.054308] Modules linked in: nfsv4 nfs dns_resolver fscache nfsd
auth_rpcgss nfs_acl lockd sunrpc sg acpi_cpufreq mperf coretemp kvm_intel kvm
snd_hda_codec_realtek snd_hda_intel snd_hda_codec hp_wmi crc32c_intel
snd_hwdep e1000e snd_seq snd_seq_device snd_pcm snd_page_alloc snd_timer snd
sparse_keymap rfkill soundcore serio_raw ptp iTCO_wdt pps_core pcspkr
iTCO_vendor_support mei microcode lpc_ich mfd_core wmi xfs libcrc32c sr_mod
sd_mod cdrom crc_t10dif radeon i2c_algo_bit drm_kms_helper ttm ahci libahci
drm i2c_core libata dm_mirror dm_region_hash dm_log dm_mod [last unloaded:
auth_rpcgss]
[ 1360.107406] Pid: 8814, comm: mount.nfs4 Tainted: G I -------------- 3.9.0-0.55.el7.x86_64 #1
[ 1360.116771] Call Trace:
[ 1360.119219] [<ffffffff810610c0>] warn_slowpath_common+0x70/0xa0
[ 1360.125208] [<ffffffff810611aa>] warn_slowpath_null+0x1a/0x20
[ 1360.131025] [<ffffffff811af46d>] d_set_d_op+0x8d/0xc0
[ 1360.136159] [<ffffffffa05a7d6f>] __rpc_lookup_create_exclusive+0x4f/0x80 [sunrpc]
[ 1360.143710] [<ffffffffa05a8cc6>] rpc_mkpipe_dentry+0x86/0x170 [sunrpc]
[ 1360.150311] [<ffffffffa062a7b6>] nfs_idmap_new+0x96/0x130 [nfsv4]
[ 1360.156475] [<ffffffffa062e7cd>] nfs4_init_client+0xad/0x2d0 [nfsv4]
[ 1360.162902] [<ffffffff812f02df>] ? idr_get_empty_slot+0x16f/0x3c0
[ 1360.169062] [<ffffffff812f0582>] ? idr_mark_full+0x52/0x60
[ 1360.174615] [<ffffffff812f0699>] ? idr_alloc+0x79/0xe0
[ 1360.179826] [<ffffffffa0598081>] ? __rpc_init_priority_wait_queue+0x81/0xc0 [sunrpc]
[ 1360.187635] [<ffffffffa05980f3>] ? rpc_init_wait_queue+0x13/0x20 [sunrpc]
[ 1360.194493] [<ffffffffa05d05da>] nfs_get_client+0x27a/0x350 [nfs]
[ 1360.200666] [<ffffffffa062e438>] nfs4_set_client.isra.8+0x78/0x100 [nfsv4]
[ 1360.207624] [<ffffffffa062f2f3>] nfs4_create_server+0xf3/0x3a0 [nfsv4]
[ 1360.214222] [<ffffffffa06284be>] nfs4_remote_mount+0x2e/0x60 [nfsv4]
[ 1360.220644] [<ffffffff8119ea79>] mount_fs+0x39/0x1b0
[ 1360.225691] [<ffffffff81153880>] ? __alloc_percpu+0x10/0x20
[ 1360.231348] [<ffffffff811b7ccf>] vfs_kern_mount+0x5f/0xf0
[ 1360.236822] [<ffffffffa0628396>] nfs_do_root_mount+0x86/0xc0 [nfsv4]
[ 1360.243246] [<ffffffffa06287b4>] nfs4_try_mount+0x44/0xc0 [nfsv4]
[ 1360.249410] [<ffffffffa05d1457>] ? get_nfs_version+0x27/0x80 [nfs]
[ 1360.255659] [<ffffffffa05db985>] nfs_fs_mount+0x5c5/0xd10 [nfs]
[ 1360.261650] [<ffffffffa05dc550>] ? nfs_clone_super+0x140/0x140 [nfs]
[ 1360.268074] [<ffffffffa05da8e0>] ? param_set_portnr+0x60/0x60 [nfs]
[ 1360.274406] [<ffffffff8119ea79>] mount_fs+0x39/0x1b0
[ 1360.279443] [<ffffffff81153880>] ? __alloc_percpu+0x10/0x20
[ 1360.285088] [<ffffffff811b7ccf>] vfs_kern_mount+0x5f/0xf0
[ 1360.290556] [<ffffffff811b9f5d>] do_mount+0x1fd/0xa00
[ 1360.295677] [<ffffffff81137dee>] ? __get_free_pages+0xe/0x50
[ 1360.301405] [<ffffffff811b9be6>] ? copy_mount_options+0x36/0x170
[ 1360.307479] [<ffffffff811ba7e3>] sys_mount+0x83/0xc0
[ 1360.312515] [<ffffffff8160ad59>] system_call_fastpath+0x16/0x1b
[ 1360.318503] ---[ end trace 8fa1f4cbc36094a7 ]---
The problem is that we're ending up in __rpc_lookup_create_exclusive
with a negative dentry that already has d_op set. A little debugging
has shown that when we hit this, the d_ops are already set to
simple_dentry_operations.
I believe that what's happening is that during a mount, idmapd is racing
in and doing a lookup of /var/lib/nfs/rpc_pipefs/nfs/clnt???/idmap.
Before that dentry reference is released, the kernel races in to create
that file and finds the new negative dentry, which already has the
d_op set.
This patch just avoids setting the d_op if it's already set.
simple_dentry_operations and rpc_dentry_operations are functionally
equivalent so it shouldn't matter which one it's set to.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'net/sunrpc/rpc_pipe.c')
-rw-r--r-- | net/sunrpc/rpc_pipe.c | 3 |
1 files changed, 2 insertions, 1 deletions
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index e7ce4b3eb0bd..a816b3a69059 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -667,7 +667,8 @@ static struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent, return ERR_PTR(-ENOMEM); } if (dentry->d_inode == NULL) { - d_set_d_op(dentry, &rpc_dentry_operations); + if (!dentry->d_op) + d_set_d_op(dentry, &rpc_dentry_operations); return dentry; } dput(dentry); |