diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-08-06 12:18:34 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-08-07 15:15:57 -0400 |
commit | 905f8d16e32fd48499e3f8b9a2d9f746af3e0949 (patch) | |
tree | 425b4fa10b788fa7f4e820890c4fac1861408340 | |
parent | 45328c354e8ae16b67cb3adb72ab57459f9e5fd6 (diff) |
NFSv4: Don't call put_rpccred() from an rcu callback
Doing so would require us to introduce bh-safe locks into put_rpccred().
This patch fixes the lockdep complaint reported by Marc Dietrich:
inconsistent {softirq-on-W} -> {in-softirq-W} usage.
swapper/0 [HC0[0]:SC1[1]:HE1:SE0] takes:
(rpc_credcache_lock){-+..}, at: [<c01dc487>]
_atomic_dec_and_lock+0x17/0x60
{softirq-on-W} state was registered at:
[<c013e870>] __lock_acquire+0x650/0x1030
[<c013f2b1>] lock_acquire+0x61/0x80
[<c02db9ac>] _spin_lock+0x2c/0x40
[<c01dc487>] _atomic_dec_and_lock+0x17/0x60
[<dced55fd>] put_rpccred+0x5d/0x100 [sunrpc]
[<dced56c1>] rpcauth_unbindcred+0x21/0x60 [sunrpc]
[<dced3fd4>] a0 [sunrpc]
[<dcecefe0>] rpc_call_sync+0x30/0x40 [sunrpc]
[<dcedc73b>] rpcb_register+0xdb/0x180 [sunrpc]
[<dced65b3>] svc_register+0x93/0x160 [sunrpc]
[<dced6ebe>] __svc_create+0x1ee/0x220 [sunrpc]
[<dced7053>] svc_create+0x13/0x20 [sunrpc]
[<dcf6d722>] nfs_callback_up+0x82/0x120 [nfs]
[<dcf48f36>] nfs_get_client+0x176/0x390 [nfs]
[<dcf49181>] nfs4_set_client+0x31/0x190 [nfs]
[<dcf49983>] nfs4_create_server+0x63/0x3b0 [nfs]
[<dcf52426>] nfs4_get_sb+0x346/0x5b0 [nfs]
[<c017b444>] vfs_kern_mount+0x94/0x110
[<c0190a62>] do_mount+0x1f2/0x7d0
[<c01910a6>] sys_mount+0x66/0xa0
[<c0104046>] syscall_call+0x7/0xb
[<ffffffff>] 0xffffffff
irq event stamp: 5277830
hardirqs last enabled at (5277830): [<c017530a>] kmem_cache_free+0x8a/0xc0
hardirqs last disabled at (5277829): [<c01752d2>] kmem_cache_free+0x52/0xc0
softirqs last enabled at (5277798): [<c0124173>] __do_softirq+0xa3/0xc0
softirqs last disabled at (5277817): [<c01241d7>] do_softirq+0x47/0x50
other info that might help us debug this:
no locks held by swapper/0.
stack backtrace:
[<c0104fda>] show_trace_log_lvl+0x1a/0x30
[<c0105c02>] show_trace+0x12/0x20
[<c0105d15>] dump_stack+0x15/0x20
[<c013ccc3>] print_usage_bug+0x153/0x160
[<c013d8b9>] mark_lock+0x449/0x620
[<c013e824>] __lock_acquire+0x604/0x1030
[<c013f2b1>] lock_acquire+0x61/0x80
[<c02db9ac>] _spin_lock+0x2c/0x40
[<c01dc487>] _atomic_dec_and_lock+0x17/0x60
[<dced55fd>] put_rpccred+0x5d/0x100 [sunrpc]
[<dcf6bf83>] nfs_free_delegation_callback+0x13/0x20 [nfs]
[<c012f9ea>] __rcu_process_callbacks+0x6a/0x1c0
[<c012fb52>] rcu_process_callbacks+0x12/0x30
[<c0124218>] tasklet_action+0x38/0x80
[<c0124125>] __do_softirq+0x55/0xc0
[<c01241d7>] do_softirq+0x47/0x50
[<c0124605>] irq_exit+0x35/0x40
[<c0112463>] smp_apic_timer_interrupt+0x43/0x80
[<c0104a77>] apic_timer_interrupt+0x33/0x38
[<c02690df>] cpuidle_idle_call+0x6f/0x90
[<c01023c3>] cpu_idle+0x43/0x70
[<c02d8c27>] rest_init+0x47/0x50
[<c03bcb6a>] start_kernel+0x22a/0x2b0
[<00000000>] 0x0
=======================
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r-- | fs/nfs/delegation.c | 21 |
1 files changed, 15 insertions, 6 deletions
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 20ac403469a0..c55a761c22bb 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
@@ -20,10 +20,8 @@ | |||
20 | #include "delegation.h" | 20 | #include "delegation.h" |
21 | #include "internal.h" | 21 | #include "internal.h" |
22 | 22 | ||
23 | static void nfs_free_delegation(struct nfs_delegation *delegation) | 23 | static void nfs_do_free_delegation(struct nfs_delegation *delegation) |
24 | { | 24 | { |
25 | if (delegation->cred) | ||
26 | put_rpccred(delegation->cred); | ||
27 | kfree(delegation); | 25 | kfree(delegation); |
28 | } | 26 | } |
29 | 27 | ||
@@ -31,7 +29,18 @@ static void nfs_free_delegation_callback(struct rcu_head *head) | |||
31 | { | 29 | { |
32 | struct nfs_delegation *delegation = container_of(head, struct nfs_delegation, rcu); | 30 | struct nfs_delegation *delegation = container_of(head, struct nfs_delegation, rcu); |
33 | 31 | ||
34 | nfs_free_delegation(delegation); | 32 | nfs_do_free_delegation(delegation); |
33 | } | ||
34 | |||
35 | static void nfs_free_delegation(struct nfs_delegation *delegation) | ||
36 | { | ||
37 | struct rpc_cred *cred; | ||
38 | |||
39 | cred = rcu_dereference(delegation->cred); | ||
40 | rcu_assign_pointer(delegation->cred, NULL); | ||
41 | call_rcu(&delegation->rcu, nfs_free_delegation_callback); | ||
42 | if (cred) | ||
43 | put_rpccred(cred); | ||
35 | } | 44 | } |
36 | 45 | ||
37 | static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_state *state) | 46 | static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_state *state) |
@@ -166,7 +175,7 @@ static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation * | |||
166 | int res = 0; | 175 | int res = 0; |
167 | 176 | ||
168 | res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid); | 177 | res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid); |
169 | call_rcu(&delegation->rcu, nfs_free_delegation_callback); | 178 | nfs_free_delegation(delegation); |
170 | return res; | 179 | return res; |
171 | } | 180 | } |
172 | 181 | ||
@@ -448,7 +457,7 @@ restart: | |||
448 | spin_unlock(&clp->cl_lock); | 457 | spin_unlock(&clp->cl_lock); |
449 | rcu_read_unlock(); | 458 | rcu_read_unlock(); |
450 | if (delegation != NULL) | 459 | if (delegation != NULL) |
451 | call_rcu(&delegation->rcu, nfs_free_delegation_callback); | 460 | nfs_free_delegation(delegation); |
452 | goto restart; | 461 | goto restart; |
453 | } | 462 | } |
454 | rcu_read_unlock(); | 463 | rcu_read_unlock(); |