diff options
author | Helge Deller <deller@gmx.de> | 2007-03-16 00:59:29 -0400 |
---|---|---|
committer | Dmitry Torokhov <dtor@insightbb.com> | 2007-03-16 00:59:29 -0400 |
commit | 9575499dfebc0f0fbbf122223f02e9e92630661d (patch) | |
tree | d43f958bec192f127907ba393762a0a4728fea4c /drivers/input/serio/hp_sdc.c | |
parent | 5a90e5bca96696f1daa0bb0a9db299eb40241ada (diff) |
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.c | 22 |
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); | |||
100 | EXPORT_SYMBOL(hp_sdc_release_hil_irq); | 100 | EXPORT_SYMBOL(hp_sdc_release_hil_irq); |
101 | EXPORT_SYMBOL(hp_sdc_release_cooked_irq); | 101 | EXPORT_SYMBOL(hp_sdc_release_cooked_irq); |
102 | 102 | ||
103 | EXPORT_SYMBOL(__hp_sdc_enqueue_transaction); | ||
103 | EXPORT_SYMBOL(hp_sdc_enqueue_transaction); | 104 | EXPORT_SYMBOL(hp_sdc_enqueue_transaction); |
104 | EXPORT_SYMBOL(hp_sdc_dequeue_transaction); | 105 | EXPORT_SYMBOL(hp_sdc_dequeue_transaction); |
105 | 106 | ||
@@ -593,18 +594,15 @@ unsigned long hp_sdc_put(void) | |||
593 | } | 594 | } |
594 | 595 | ||
595 | /******* Functions called in either user or kernel context ****/ | 596 | /******* Functions called in either user or kernel context ****/ |
596 | int hp_sdc_enqueue_transaction(hp_sdc_transaction *this) | 597 | int __hp_sdc_enqueue_transaction(hp_sdc_transaction *this) |
597 | { | 598 | { |
598 | unsigned long flags; | ||
599 | int i; | 599 | int i; |
600 | 600 | ||
601 | if (this == NULL) { | 601 | if (this == NULL) { |
602 | tasklet_schedule(&hp_sdc.task); | 602 | BUG(); |
603 | return -EINVAL; | 603 | return -EINVAL; |
604 | } | 604 | } |
605 | 605 | ||
606 | write_lock_irqsave(&hp_sdc.lock, flags); | ||
607 | |||
608 | /* Can't have same transaction on queue twice */ | 606 | /* Can't have same transaction on queue twice */ |
609 | for (i = 0; i < HP_SDC_QUEUE_LEN; i++) | 607 | for (i = 0; i < HP_SDC_QUEUE_LEN; i++) |
610 | if (hp_sdc.tq[i] == this) | 608 | if (hp_sdc.tq[i] == this) |
@@ -617,21 +615,29 @@ int hp_sdc_enqueue_transaction(hp_sdc_transaction *this) | |||
617 | for (i = 0; i < HP_SDC_QUEUE_LEN; i++) | 615 | for (i = 0; i < HP_SDC_QUEUE_LEN; i++) |
618 | if (hp_sdc.tq[i] == NULL) { | 616 | if (hp_sdc.tq[i] == NULL) { |
619 | hp_sdc.tq[i] = this; | 617 | hp_sdc.tq[i] = this; |
620 | write_unlock_irqrestore(&hp_sdc.lock, flags); | ||
621 | tasklet_schedule(&hp_sdc.task); | 618 | tasklet_schedule(&hp_sdc.task); |
622 | return 0; | 619 | return 0; |
623 | } | 620 | } |
624 | 621 | ||
625 | write_unlock_irqrestore(&hp_sdc.lock, flags); | ||
626 | printk(KERN_WARNING PREFIX "No free slot to add transaction.\n"); | 622 | printk(KERN_WARNING PREFIX "No free slot to add transaction.\n"); |
627 | return -EBUSY; | 623 | return -EBUSY; |
628 | 624 | ||
629 | fail: | 625 | fail: |
630 | write_unlock_irqrestore(&hp_sdc.lock,flags); | ||
631 | printk(KERN_WARNING PREFIX "Transaction add failed: transaction already queued?\n"); | 626 | printk(KERN_WARNING PREFIX "Transaction add failed: transaction already queued?\n"); |
632 | return -EINVAL; | 627 | return -EINVAL; |
633 | } | 628 | } |
634 | 629 | ||
630 | int hp_sdc_enqueue_transaction(hp_sdc_transaction *this) { | ||
631 | unsigned long flags; | ||
632 | int ret; | ||
633 | |||
634 | write_lock_irqsave(&hp_sdc.lock, flags); | ||
635 | ret = __hp_sdc_enqueue_transaction(this); | ||
636 | write_unlock_irqrestore(&hp_sdc.lock,flags); | ||
637 | |||
638 | return ret; | ||
639 | } | ||
640 | |||
635 | int hp_sdc_dequeue_transaction(hp_sdc_transaction *this) | 641 | int hp_sdc_dequeue_transaction(hp_sdc_transaction *this) |
636 | { | 642 | { |
637 | unsigned long flags; | 643 | unsigned long flags; |