summaryrefslogtreecommitdiffstats
path: root/drivers/input/serio/hp_sdc.c
diff options
context:
space:
mode:
authorHelge Deller <deller@gmx.de>2007-03-16 00:59:29 -0400
committerDmitry Torokhov <dtor@insightbb.com>2007-03-16 00:59:29 -0400
commit9575499dfebc0f0fbbf122223f02e9e92630661d (patch)
treed43f958bec192f127907ba393762a0a4728fea4c /drivers/input/serio/hp_sdc.c
parent5a90e5bca96696f1daa0bb0a9db299eb40241ada (diff)
downloadlinux-9575499dfebc0f0fbbf122223f02e9e92630661d.tar.gz
linux-9575499dfebc0f0fbbf122223f02e9e92630661d.tar.bz2
linux-9575499dfebc0f0fbbf122223f02e9e92630661d.zip
Input: HIL - fix rwlock recursion bug
The following bug happens when insmoding hp_sdc_mlc.ko: HP SDC MLC: Registering the System Domain Controller's HIL MLC. BUG: rwlock recursion on CPU#0, hotplug/1814, 00854734 Backtrace: [<10267560>] _raw_write_lock+0x50/0x88 [<10104008>] _write_lock_irqsave+0x14/0x24 [<008537d4>] hp_sdc_mlc_out+0x38/0x25c [hp_sdc_mlc] [<0084ebd8>] hilse_donode+0x308/0x470 [hil_mlc] [<0084ed80>] hil_mlcs_process+0x40/0x6c [hil_mlc] [<10130f80>] tasklet_action+0x78/0xb8 [<10130cec>] __do_softirq+0x60/0xcc [<1010428c>] __lock_text_end+0x38/0x48 [<10108348>] do_cpu_irq_mask+0xf0/0x11c [<1010b068>] intr_return+0x0/0xc Signed-off-by: Helge Deller <deller@gmx.de> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/serio/hp_sdc.c')
-rw-r--r--drivers/input/serio/hp_sdc.c22
1 files changed, 14 insertions, 8 deletions
diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c
index 31826e601fba..6af199805ffc 100644
--- a/drivers/input/serio/hp_sdc.c
+++ b/drivers/input/serio/hp_sdc.c
@@ -100,6 +100,7 @@ EXPORT_SYMBOL(hp_sdc_release_timer_irq);
EXPORT_SYMBOL(hp_sdc_release_hil_irq);
EXPORT_SYMBOL(hp_sdc_release_cooked_irq);
+EXPORT_SYMBOL(__hp_sdc_enqueue_transaction);
EXPORT_SYMBOL(hp_sdc_enqueue_transaction);
EXPORT_SYMBOL(hp_sdc_dequeue_transaction);
@@ -593,18 +594,15 @@ unsigned long hp_sdc_put(void)
}
/******* Functions called in either user or kernel context ****/
-int hp_sdc_enqueue_transaction(hp_sdc_transaction *this)
+int __hp_sdc_enqueue_transaction(hp_sdc_transaction *this)
{
- unsigned long flags;
int i;
if (this == NULL) {
- tasklet_schedule(&hp_sdc.task);
+ BUG();
return -EINVAL;
}
- write_lock_irqsave(&hp_sdc.lock, flags);
-
/* Can't have same transaction on queue twice */
for (i = 0; i < HP_SDC_QUEUE_LEN; i++)
if (hp_sdc.tq[i] == this)
@@ -617,21 +615,29 @@ int hp_sdc_enqueue_transaction(hp_sdc_transaction *this)
for (i = 0; i < HP_SDC_QUEUE_LEN; i++)
if (hp_sdc.tq[i] == NULL) {
hp_sdc.tq[i] = this;
- write_unlock_irqrestore(&hp_sdc.lock, flags);
tasklet_schedule(&hp_sdc.task);
return 0;
}
- write_unlock_irqrestore(&hp_sdc.lock, flags);
printk(KERN_WARNING PREFIX "No free slot to add transaction.\n");
return -EBUSY;
fail:
- write_unlock_irqrestore(&hp_sdc.lock,flags);
printk(KERN_WARNING PREFIX "Transaction add failed: transaction already queued?\n");
return -EINVAL;
}
+int hp_sdc_enqueue_transaction(hp_sdc_transaction *this) {
+ unsigned long flags;
+ int ret;
+
+ write_lock_irqsave(&hp_sdc.lock, flags);
+ ret = __hp_sdc_enqueue_transaction(this);
+ write_unlock_irqrestore(&hp_sdc.lock,flags);
+
+ return ret;
+}
+
int hp_sdc_dequeue_transaction(hp_sdc_transaction *this)
{
unsigned long flags;