aboutsummaryrefslogtreecommitdiffstats
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
parent5a90e5bca96696f1daa0bb0a9db299eb40241ada (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>
-rw-r--r--drivers/input/serio/hil_mlc.c2
-rw-r--r--drivers/input/serio/hp_sdc.c22
-rw-r--r--drivers/input/serio/hp_sdc_mlc.c19
-rw-r--r--include/linux/hp_sdc.h1
4 files changed, 19 insertions, 25 deletions
diff --git a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c
index 485b0742842b..93a1a6ba216a 100644
--- a/drivers/input/serio/hil_mlc.c
+++ b/drivers/input/serio/hil_mlc.c
@@ -716,7 +716,9 @@ static int hilse_donode(hil_mlc *mlc)
716 break; 716 break;
717 717
718 case HILSE_CTS: 718 case HILSE_CTS:
719 write_lock_irqsave(&mlc->lock, flags);
719 nextidx = mlc->cts(mlc) ? node->bad : node->good; 720 nextidx = mlc->cts(mlc) ? node->bad : node->good;
721 write_unlock_irqrestore(&mlc->lock, flags);
720 break; 722 break;
721 723
722 default: 724 default:
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);
100EXPORT_SYMBOL(hp_sdc_release_hil_irq); 100EXPORT_SYMBOL(hp_sdc_release_hil_irq);
101EXPORT_SYMBOL(hp_sdc_release_cooked_irq); 101EXPORT_SYMBOL(hp_sdc_release_cooked_irq);
102 102
103EXPORT_SYMBOL(__hp_sdc_enqueue_transaction);
103EXPORT_SYMBOL(hp_sdc_enqueue_transaction); 104EXPORT_SYMBOL(hp_sdc_enqueue_transaction);
104EXPORT_SYMBOL(hp_sdc_dequeue_transaction); 105EXPORT_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 ****/
596int hp_sdc_enqueue_transaction(hp_sdc_transaction *this) 597int __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
630int 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
635int hp_sdc_dequeue_transaction(hp_sdc_transaction *this) 641int hp_sdc_dequeue_transaction(hp_sdc_transaction *this)
636{ 642{
637 unsigned long flags; 643 unsigned long flags;
diff --git a/drivers/input/serio/hp_sdc_mlc.c b/drivers/input/serio/hp_sdc_mlc.c
index cb0b28877e05..c45ea74d53e4 100644
--- a/drivers/input/serio/hp_sdc_mlc.c
+++ b/drivers/input/serio/hp_sdc_mlc.c
@@ -142,14 +142,11 @@ static void hp_sdc_mlc_isr (int irq, void *dev_id,
142 142
143static int hp_sdc_mlc_in(hil_mlc *mlc, suseconds_t timeout) 143static int hp_sdc_mlc_in(hil_mlc *mlc, suseconds_t timeout)
144{ 144{
145 unsigned long flags;
146 struct hp_sdc_mlc_priv_s *priv; 145 struct hp_sdc_mlc_priv_s *priv;
147 int rc = 2; 146 int rc = 2;
148 147
149 priv = mlc->priv; 148 priv = mlc->priv;
150 149
151 write_lock_irqsave(&mlc->lock, flags);
152
153 /* Try to down the semaphore */ 150 /* Try to down the semaphore */
154 if (down_trylock(&mlc->isem)) { 151 if (down_trylock(&mlc->isem)) {
155 struct timeval tv; 152 struct timeval tv;
@@ -178,21 +175,16 @@ static int hp_sdc_mlc_in(hil_mlc *mlc, suseconds_t timeout)
178 wasup: 175 wasup:
179 up(&mlc->isem); 176 up(&mlc->isem);
180 rc = 0; 177 rc = 0;
181 goto done;
182 done: 178 done:
183 write_unlock_irqrestore(&mlc->lock, flags);
184 return rc; 179 return rc;
185} 180}
186 181
187static int hp_sdc_mlc_cts(hil_mlc *mlc) 182static int hp_sdc_mlc_cts(hil_mlc *mlc)
188{ 183{
189 struct hp_sdc_mlc_priv_s *priv; 184 struct hp_sdc_mlc_priv_s *priv;
190 unsigned long flags;
191 185
192 priv = mlc->priv; 186 priv = mlc->priv;
193 187
194 write_lock_irqsave(&mlc->lock, flags);
195
196 /* Try to down the semaphores -- they should be up. */ 188 /* Try to down the semaphores -- they should be up. */
197 BUG_ON(down_trylock(&mlc->isem)); 189 BUG_ON(down_trylock(&mlc->isem));
198 BUG_ON(down_trylock(&mlc->osem)); 190 BUG_ON(down_trylock(&mlc->osem));
@@ -221,26 +213,21 @@ static int hp_sdc_mlc_cts(hil_mlc *mlc)
221 priv->tseq[2] = 1; 213 priv->tseq[2] = 1;
222 priv->tseq[3] = 0; 214 priv->tseq[3] = 0;
223 priv->tseq[4] = 0; 215 priv->tseq[4] = 0;
224 hp_sdc_enqueue_transaction(&priv->trans); 216 __hp_sdc_enqueue_transaction(&priv->trans);
225 busy: 217 busy:
226 write_unlock_irqrestore(&mlc->lock, flags);
227 return 1; 218 return 1;
228 done: 219 done:
229 priv->trans.act.semaphore = &mlc->osem; 220 priv->trans.act.semaphore = &mlc->osem;
230 up(&mlc->csem); 221 up(&mlc->csem);
231 write_unlock_irqrestore(&mlc->lock, flags);
232 return 0; 222 return 0;
233} 223}
234 224
235static void hp_sdc_mlc_out(hil_mlc *mlc) 225static void hp_sdc_mlc_out(hil_mlc *mlc)
236{ 226{
237 struct hp_sdc_mlc_priv_s *priv; 227 struct hp_sdc_mlc_priv_s *priv;
238 unsigned long flags;
239 228
240 priv = mlc->priv; 229 priv = mlc->priv;
241 230
242 write_lock_irqsave(&mlc->lock, flags);
243
244 /* Try to down the semaphore -- it should be up. */ 231 /* Try to down the semaphore -- it should be up. */
245 BUG_ON(down_trylock(&mlc->osem)); 232 BUG_ON(down_trylock(&mlc->osem));
246 233
@@ -250,7 +237,7 @@ static void hp_sdc_mlc_out(hil_mlc *mlc)
250 do_data: 237 do_data:
251 if (priv->emtestmode) { 238 if (priv->emtestmode) {
252 up(&mlc->osem); 239 up(&mlc->osem);
253 goto done; 240 return;
254 } 241 }
255 /* Shouldn't be sending commands when loop may be busy */ 242 /* Shouldn't be sending commands when loop may be busy */
256 BUG_ON(down_trylock(&mlc->csem)); 243 BUG_ON(down_trylock(&mlc->csem));
@@ -313,8 +300,6 @@ static void hp_sdc_mlc_out(hil_mlc *mlc)
313 } 300 }
314 enqueue: 301 enqueue:
315 hp_sdc_enqueue_transaction(&priv->trans); 302 hp_sdc_enqueue_transaction(&priv->trans);
316 done:
317 write_unlock_irqrestore(&mlc->lock, flags);
318} 303}
319 304
320static int __init hp_sdc_mlc_init(void) 305static int __init hp_sdc_mlc_init(void)
diff --git a/include/linux/hp_sdc.h b/include/linux/hp_sdc.h
index debd71515312..9db3d454887f 100644
--- a/include/linux/hp_sdc.h
+++ b/include/linux/hp_sdc.h
@@ -71,6 +71,7 @@ typedef struct {
71 struct semaphore *semaphore; /* Semaphore to sleep on. */ 71 struct semaphore *semaphore; /* Semaphore to sleep on. */
72 } act; 72 } act;
73} hp_sdc_transaction; 73} hp_sdc_transaction;
74int __hp_sdc_enqueue_transaction(hp_sdc_transaction *this);
74int hp_sdc_enqueue_transaction(hp_sdc_transaction *this); 75int hp_sdc_enqueue_transaction(hp_sdc_transaction *this);
75int hp_sdc_dequeue_transaction(hp_sdc_transaction *this); 76int hp_sdc_dequeue_transaction(hp_sdc_transaction *this);
76 77