From 639f54186403aafcb3b3319a8f61e4b06c25eeef Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Thu, 18 Oct 2012 09:54:24 -0700 Subject: [PATCH] ledtrig-cpu: use spin_lock to replace mutex lock Mutex lock is not safe in atomic context like the bug reported by Miles Lane: --- ACPI: Preparing to enter system sleep state S3 PM: Saving platform NVS memory Disabling non-boot CPUs ... numa_remove_cpu cpu 1 node 0: mask now 0 Broke affinity for irq 46 smpboot: CPU 1 is now offline BUG: sleeping function called from invalid context at kernel/mutex.c:269 in_atomic(): 0, irqs_disabled(): 1, pid: 3561, name: pm-suspend 4 locks held by pm-suspend/3561: #0: (&buffer->mutex){+.+.+.}, at: [] sysfs_write_file+0x37/0x121 #1: (s_active#98){.+.+.+}, at: [] sysfs_write_file+0xd1/0x121 #2: (autosleep_lock){+.+.+.}, at: [] pm_autosleep_lock+0x12/0x14 #3: (pm_mutex){+.+.+.}, at: [] pm_suspend+0x38/0x1b8 irq event stamp: 103458 hardirqs last enabled at (103457): [] __mutex_unlock_slowpath+0x101/0x125 hardirqs last disabled at (103458): [] arch_suspend_disable_irqs+0xa/0xc softirqs last enabled at (103196): [] __do_softirq+0x12a/0x155 softirqs last disabled at (103171): [] call_softirq+0x1c/0x30 Pid: 3561, comm: pm-suspend Not tainted 3.6.0+ #26 Call Trace: [] ? print_irqtrace_events+0x9d/0xa1 [] __might_sleep+0x19f/0x1a8 [] mutex_lock_nested+0x20/0x3b [] ledtrig_cpu+0x3b/0x7b [] ledtrig_cpu_syscore_suspend+0xe/0x15 [] syscore_suspend+0x78/0xfd [] suspend_devices_and_enter+0x10f/0x201 [] pm_suspend+0xff/0x1b8 [] state_store+0x43/0x6c [] kobj_attr_store+0xf/0x1b [] sysfs_write_file+0xe9/0x121 [] vfs_write+0x9b/0xfd [] ? trace_hardirqs_on+0xd/0xf [] sys_write+0x4d/0x7a [] tracesys+0xdd/0xe2 --- This patch replace mutex lock with spin lock which is safe for this case. Reported-by: Miles Lane Reported-by: Rafael J. Wysocki Cc: Linus Walleij Signed-off-by: Bryan Wu --- drivers/leds/ledtrig-cpu.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/leds/ledtrig-cpu.c b/drivers/leds/ledtrig-cpu.c index b312056..9e78018 100644 --- a/drivers/leds/ledtrig-cpu.c +++ b/drivers/leds/ledtrig-cpu.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include "leds.h" #define MAX_NAME_LEN 8 @@ -33,7 +33,7 @@ struct led_trigger_cpu { char name[MAX_NAME_LEN]; struct led_trigger *_trig; - struct mutex lock; + spinlock_t lock; int lock_is_inited; }; @@ -50,11 +50,11 @@ void ledtrig_cpu(enum cpu_led_event ledevt) { struct led_trigger_cpu *trig = &__get_cpu_var(cpu_trig); - /* mutex lock should be initialized before calling mutex_call() */ + /* spin lock should be initialized before calling spinlock calls */ if (!trig->lock_is_inited) return; - mutex_lock(&trig->lock); + spin_lock(&trig->lock); /* Locate the correct CPU LED */ switch (ledevt) { @@ -76,7 +76,7 @@ void ledtrig_cpu(enum cpu_led_event ledevt) break; } - mutex_unlock(&trig->lock); + spin_unlock(&trig->lock); } EXPORT_SYMBOL(ledtrig_cpu); @@ -117,14 +117,14 @@ static int __init ledtrig_cpu_init(void) for_each_possible_cpu(cpu) { struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu); - mutex_init(&trig->lock); + spin_lock_init(&trig->lock); snprintf(trig->name, MAX_NAME_LEN, "cpu%d", cpu); - mutex_lock(&trig->lock); + spin_lock(&trig->lock); led_trigger_register_simple(trig->name, &trig->_trig); trig->lock_is_inited = 1; - mutex_unlock(&trig->lock); + spin_unlock(&trig->lock); } register_syscore_ops(&ledtrig_cpu_syscore_ops); @@ -142,15 +142,14 @@ static void __exit ledtrig_cpu_exit(void) for_each_possible_cpu(cpu) { struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu); - mutex_lock(&trig->lock); + spin_lock(&trig->lock); led_trigger_unregister_simple(trig->_trig); trig->_trig = NULL; memset(trig->name, 0, MAX_NAME_LEN); trig->lock_is_inited = 0; - mutex_unlock(&trig->lock); - mutex_destroy(&trig->lock); + spin_unlock(&trig->lock); } unregister_syscore_ops(&ledtrig_cpu_syscore_ops); -- 1.7.9.5