From 905f8d16e32fd48499e3f8b9a2d9f746af3e0949 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 6 Aug 2007 12:18:34 -0400 Subject: 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: [] _atomic_dec_and_lock+0x17/0x60 {softirq-on-W} state was registered at: [] __lock_acquire+0x650/0x1030 [] lock_acquire+0x61/0x80 [] _spin_lock+0x2c/0x40 [] _atomic_dec_and_lock+0x17/0x60 [] put_rpccred+0x5d/0x100 [sunrpc] [] rpcauth_unbindcred+0x21/0x60 [sunrpc] [] a0 [sunrpc] [] rpc_call_sync+0x30/0x40 [sunrpc] [] rpcb_register+0xdb/0x180 [sunrpc] [] svc_register+0x93/0x160 [sunrpc] [] __svc_create+0x1ee/0x220 [sunrpc] [] svc_create+0x13/0x20 [sunrpc] [] nfs_callback_up+0x82/0x120 [nfs] [] nfs_get_client+0x176/0x390 [nfs] [] nfs4_set_client+0x31/0x190 [nfs] [] nfs4_create_server+0x63/0x3b0 [nfs] [] nfs4_get_sb+0x346/0x5b0 [nfs] [] vfs_kern_mount+0x94/0x110 [] do_mount+0x1f2/0x7d0 [] sys_mount+0x66/0xa0 [] syscall_call+0x7/0xb [] 0xffffffff irq event stamp: 5277830 hardirqs last enabled at (5277830): [] kmem_cache_free+0x8a/0xc0 hardirqs last disabled at (5277829): [] kmem_cache_free+0x52/0xc0 softirqs last enabled at (5277798): [] __do_softirq+0xa3/0xc0 softirqs last disabled at (5277817): [] do_softirq+0x47/0x50 other info that might help us debug this: no locks held by swapper/0. stack backtrace: [] show_trace_log_lvl+0x1a/0x30 [] show_trace+0x12/0x20 [] dump_stack+0x15/0x20 [] print_usage_bug+0x153/0x160 [] mark_lock+0x449/0x620 [] __lock_acquire+0x604/0x1030 [] lock_acquire+0x61/0x80 [] _spin_lock+0x2c/0x40 [] _atomic_dec_and_lock+0x17/0x60 [] put_rpccred+0x5d/0x100 [sunrpc] [] nfs_free_delegation_callback+0x13/0x20 [nfs] [] __rcu_process_callbacks+0x6a/0x1c0 [] rcu_process_callbacks+0x12/0x30 [] tasklet_action+0x38/0x80 [] __do_softirq+0x55/0xc0 [] do_softirq+0x47/0x50 [] irq_exit+0x35/0x40 [] smp_apic_timer_interrupt+0x43/0x80 [] apic_timer_interrupt+0x33/0x38 [] cpuidle_idle_call+0x6f/0x90 [] cpu_idle+0x43/0x70 [] rest_init+0x47/0x50 [] start_kernel+0x22a/0x2b0 [<00000000>] 0x0 ======================= Signed-off-by: Trond Myklebust --- fs/nfs/delegation.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'fs/nfs') 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 @@ #include "delegation.h" #include "internal.h" -static void nfs_free_delegation(struct nfs_delegation *delegation) +static void nfs_do_free_delegation(struct nfs_delegation *delegation) { - if (delegation->cred) - put_rpccred(delegation->cred); kfree(delegation); } @@ -31,7 +29,18 @@ static void nfs_free_delegation_callback(struct rcu_head *head) { struct nfs_delegation *delegation = container_of(head, struct nfs_delegation, rcu); - nfs_free_delegation(delegation); + nfs_do_free_delegation(delegation); +} + +static void nfs_free_delegation(struct nfs_delegation *delegation) +{ + struct rpc_cred *cred; + + cred = rcu_dereference(delegation->cred); + rcu_assign_pointer(delegation->cred, NULL); + call_rcu(&delegation->rcu, nfs_free_delegation_callback); + if (cred) + put_rpccred(cred); } 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 * int res = 0; res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid); - call_rcu(&delegation->rcu, nfs_free_delegation_callback); + nfs_free_delegation(delegation); return res; } @@ -448,7 +457,7 @@ restart: spin_unlock(&clp->cl_lock); rcu_read_unlock(); if (delegation != NULL) - call_rcu(&delegation->rcu, nfs_free_delegation_callback); + nfs_free_delegation(delegation); goto restart; } rcu_read_unlock(); -- cgit v1.2.3-55-g7522