diff options
author | Xiaotian Feng <xtfeng@gmail.com> | 2012-12-20 18:05:44 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-20 20:40:20 -0500 |
commit | ee297209bf0a25c6717b7c063e76795142d32f37 (patch) | |
tree | 7783b18e70c4bd5856727f6db4100a3b45ffb23b /fs/proc | |
parent | c4e18497d8fd92eef2c6e7eadcc1a107ccd115ea (diff) |
proc: fix inconsistent lock state
Lockdep found an inconsistent lock state when rcu is processing delayed
work in softirq. Currently, kernel is using spin_lock/spin_unlock to
protect proc_inum_ida, but proc_free_inum is called by rcu in softirq
context.
Use spin_lock_bh/spin_unlock_bh fix following lockdep warning.
=================================
[ INFO: inconsistent lock state ]
3.7.0 #36 Not tainted
---------------------------------
inconsistent {SOFTIRQ-ON-W} -> {IN-SOFTIRQ-W} usage.
swapper/1/0 [HC0[0]:SC1[1]:HE1:SE0] takes:
(proc_inum_lock){+.?...}, at: proc_free_inum+0x1c/0x50
{SOFTIRQ-ON-W} state was registered at:
__lock_acquire+0x8ae/0xca0
lock_acquire+0x199/0x200
_raw_spin_lock+0x41/0x50
proc_alloc_inum+0x4c/0xd0
alloc_mnt_ns+0x49/0xc0
create_mnt_ns+0x25/0x70
mnt_init+0x161/0x1c7
vfs_caches_init+0x107/0x11a
start_kernel+0x348/0x38c
x86_64_start_reservations+0x131/0x136
x86_64_start_kernel+0x103/0x112
irq event stamp: 2993422
hardirqs last enabled at (2993422): _raw_spin_unlock_irqrestore+0x55/0x80
hardirqs last disabled at (2993421): _raw_spin_lock_irqsave+0x29/0x70
softirqs last enabled at (2993394): _local_bh_enable+0x13/0x20
softirqs last disabled at (2993395): call_softirq+0x1c/0x30
other info that might help us debug this:
Possible unsafe locking scenario:
CPU0
----
lock(proc_inum_lock);
<Interrupt>
lock(proc_inum_lock);
*** DEADLOCK ***
no locks held by swapper/1/0.
stack backtrace:
Pid: 0, comm: swapper/1 Not tainted 3.7.0 #36
Call Trace:
<IRQ> [<ffffffff810a40f1>] ? vprintk_emit+0x471/0x510
print_usage_bug+0x2a5/0x2c0
mark_lock+0x33b/0x5e0
__lock_acquire+0x813/0xca0
lock_acquire+0x199/0x200
_raw_spin_lock+0x41/0x50
proc_free_inum+0x1c/0x50
free_pid_ns+0x1c/0x50
put_pid_ns+0x2e/0x50
put_pid+0x4a/0x60
delayed_put_pid+0x12/0x20
rcu_process_callbacks+0x462/0x790
__do_softirq+0x1b4/0x3b0
call_softirq+0x1c/0x30
do_softirq+0x59/0xd0
irq_exit+0x54/0xd0
smp_apic_timer_interrupt+0x95/0xa3
apic_timer_interrupt+0x72/0x80
cpuidle_enter_tk+0x10/0x20
cpuidle_enter_state+0x17/0x50
cpuidle_idle_call+0x287/0x520
cpu_idle+0xba/0x130
start_secondary+0x2b3/0x2bc
Signed-off-by: Xiaotian Feng <dannyfeng@tencent.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/proc')
-rw-r--r-- | fs/proc/generic.c | 12 |
1 files changed, 6 insertions, 6 deletions
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 7b3ae3cc0ef9..e659a0ff1da7 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c | |||
@@ -359,18 +359,18 @@ retry: | |||
359 | if (!ida_pre_get(&proc_inum_ida, GFP_KERNEL)) | 359 | if (!ida_pre_get(&proc_inum_ida, GFP_KERNEL)) |
360 | return -ENOMEM; | 360 | return -ENOMEM; |
361 | 361 | ||
362 | spin_lock(&proc_inum_lock); | 362 | spin_lock_bh(&proc_inum_lock); |
363 | error = ida_get_new(&proc_inum_ida, &i); | 363 | error = ida_get_new(&proc_inum_ida, &i); |
364 | spin_unlock(&proc_inum_lock); | 364 | spin_unlock_bh(&proc_inum_lock); |
365 | if (error == -EAGAIN) | 365 | if (error == -EAGAIN) |
366 | goto retry; | 366 | goto retry; |
367 | else if (error) | 367 | else if (error) |
368 | return error; | 368 | return error; |
369 | 369 | ||
370 | if (i > UINT_MAX - PROC_DYNAMIC_FIRST) { | 370 | if (i > UINT_MAX - PROC_DYNAMIC_FIRST) { |
371 | spin_lock(&proc_inum_lock); | 371 | spin_lock_bh(&proc_inum_lock); |
372 | ida_remove(&proc_inum_ida, i); | 372 | ida_remove(&proc_inum_ida, i); |
373 | spin_unlock(&proc_inum_lock); | 373 | spin_unlock_bh(&proc_inum_lock); |
374 | return -ENOSPC; | 374 | return -ENOSPC; |
375 | } | 375 | } |
376 | *inum = PROC_DYNAMIC_FIRST + i; | 376 | *inum = PROC_DYNAMIC_FIRST + i; |
@@ -379,9 +379,9 @@ retry: | |||
379 | 379 | ||
380 | void proc_free_inum(unsigned int inum) | 380 | void proc_free_inum(unsigned int inum) |
381 | { | 381 | { |
382 | spin_lock(&proc_inum_lock); | 382 | spin_lock_bh(&proc_inum_lock); |
383 | ida_remove(&proc_inum_ida, inum - PROC_DYNAMIC_FIRST); | 383 | ida_remove(&proc_inum_ida, inum - PROC_DYNAMIC_FIRST); |
384 | spin_unlock(&proc_inum_lock); | 384 | spin_unlock_bh(&proc_inum_lock); |
385 | } | 385 | } |
386 | 386 | ||
387 | static void *proc_follow_link(struct dentry *dentry, struct nameidata *nd) | 387 | static void *proc_follow_link(struct dentry *dentry, struct nameidata *nd) |