aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/uwb/neh.c
diff options
context:
space:
mode:
authorDavid Vrabel <david.vrabel@csr.com>2008-11-07 13:19:19 -0500
committerDavid Vrabel <david.vrabel@csr.com>2008-11-07 13:19:19 -0500
commit58be81ed301d96045bca2b85f3b838910efcfde4 (patch)
treed65d13f757652cd2126b43449727c2a1f40ab551 /drivers/uwb/neh.c
parent307ba6dd73254fe7d2ce27db64ffd90e1bb3c6c0 (diff)
uwb: fix races between events and neh timers
Always use del_timer_sync() before freeing nehs. Destroy all nehs after stopping the radio controller and before cleaning up the reservation manager. Handle the timer running after an event has removed the neh. This fixes various oopses that may occur if a radio controller is removed while a neh timer is still active. Signed-off-by: David Vrabel <david.vrabel@csr.com>
Diffstat (limited to 'drivers/uwb/neh.c')
-rw-r--r--drivers/uwb/neh.c46
1 files changed, 32 insertions, 14 deletions
diff --git a/drivers/uwb/neh.c b/drivers/uwb/neh.c
index 9b4eb64327ac..48b4ece1a627 100644
--- a/drivers/uwb/neh.c
+++ b/drivers/uwb/neh.c
@@ -254,7 +254,6 @@ error_kzalloc:
254 254
255static void __uwb_rc_neh_rm(struct uwb_rc *rc, struct uwb_rc_neh *neh) 255static void __uwb_rc_neh_rm(struct uwb_rc *rc, struct uwb_rc_neh *neh)
256{ 256{
257 del_timer(&neh->timer);
258 __uwb_rc_ctx_put(rc, neh); 257 __uwb_rc_ctx_put(rc, neh);
259 list_del(&neh->list_node); 258 list_del(&neh->list_node);
260} 259}
@@ -275,6 +274,7 @@ void uwb_rc_neh_rm(struct uwb_rc *rc, struct uwb_rc_neh *neh)
275 __uwb_rc_neh_rm(rc, neh); 274 __uwb_rc_neh_rm(rc, neh);
276 spin_unlock_irqrestore(&rc->neh_lock, flags); 275 spin_unlock_irqrestore(&rc->neh_lock, flags);
277 276
277 del_timer_sync(&neh->timer);
278 uwb_rc_neh_put(neh); 278 uwb_rc_neh_put(neh);
279} 279}
280 280
@@ -438,9 +438,10 @@ static void uwb_rc_neh_grok_event(struct uwb_rc *rc, struct uwb_rceb *rceb, size
438 rceb->bEventContext, size); 438 rceb->bEventContext, size);
439 } else { 439 } else {
440 neh = uwb_rc_neh_lookup(rc, rceb); 440 neh = uwb_rc_neh_lookup(rc, rceb);
441 if (neh) 441 if (neh) {
442 del_timer_sync(&neh->timer);
442 uwb_rc_neh_cb(neh, rceb, size); 443 uwb_rc_neh_cb(neh, rceb, size);
443 else 444 } else
444 dev_warn(dev, "event 0x%02x/%04x/%02x (%zu bytes): nobody cared\n", 445 dev_warn(dev, "event 0x%02x/%04x/%02x (%zu bytes): nobody cared\n",
445 rceb->bEventType, le16_to_cpu(rceb->wEvent), 446 rceb->bEventType, le16_to_cpu(rceb->wEvent),
446 rceb->bEventContext, size); 447 rceb->bEventContext, size);
@@ -562,16 +563,22 @@ EXPORT_SYMBOL_GPL(uwb_rc_neh_grok);
562 */ 563 */
563void uwb_rc_neh_error(struct uwb_rc *rc, int error) 564void uwb_rc_neh_error(struct uwb_rc *rc, int error)
564{ 565{
565 struct uwb_rc_neh *neh, *next; 566 struct uwb_rc_neh *neh;
566 unsigned long flags; 567 unsigned long flags;
567 568
568 BUG_ON(error >= 0); 569 for (;;) {
569 spin_lock_irqsave(&rc->neh_lock, flags); 570 spin_lock_irqsave(&rc->neh_lock, flags);
570 list_for_each_entry_safe(neh, next, &rc->neh_list, list_node) { 571 if (list_empty(&rc->neh_list)) {
572 spin_unlock_irqrestore(&rc->neh_lock, flags);
573 break;
574 }
575 neh = list_first_entry(&rc->neh_list, struct uwb_rc_neh, list_node);
571 __uwb_rc_neh_rm(rc, neh); 576 __uwb_rc_neh_rm(rc, neh);
577 spin_unlock_irqrestore(&rc->neh_lock, flags);
578
579 del_timer_sync(&neh->timer);
572 uwb_rc_neh_cb(neh, NULL, error); 580 uwb_rc_neh_cb(neh, NULL, error);
573 } 581 }
574 spin_unlock_irqrestore(&rc->neh_lock, flags);
575} 582}
576EXPORT_SYMBOL_GPL(uwb_rc_neh_error); 583EXPORT_SYMBOL_GPL(uwb_rc_neh_error);
577 584
@@ -583,10 +590,14 @@ static void uwb_rc_neh_timer(unsigned long arg)
583 unsigned long flags; 590 unsigned long flags;
584 591
585 spin_lock_irqsave(&rc->neh_lock, flags); 592 spin_lock_irqsave(&rc->neh_lock, flags);
586 __uwb_rc_neh_rm(rc, neh); 593 if (neh->context)
594 __uwb_rc_neh_rm(rc, neh);
595 else
596 neh = NULL;
587 spin_unlock_irqrestore(&rc->neh_lock, flags); 597 spin_unlock_irqrestore(&rc->neh_lock, flags);
588 598
589 uwb_rc_neh_cb(neh, NULL, -ETIMEDOUT); 599 if (neh)
600 uwb_rc_neh_cb(neh, NULL, -ETIMEDOUT);
590} 601}
591 602
592/** Initializes the @rc's neh subsystem 603/** Initializes the @rc's neh subsystem
@@ -605,12 +616,19 @@ void uwb_rc_neh_create(struct uwb_rc *rc)
605void uwb_rc_neh_destroy(struct uwb_rc *rc) 616void uwb_rc_neh_destroy(struct uwb_rc *rc)
606{ 617{
607 unsigned long flags; 618 unsigned long flags;
608 struct uwb_rc_neh *neh, *next; 619 struct uwb_rc_neh *neh;
609 620
610 spin_lock_irqsave(&rc->neh_lock, flags); 621 for (;;) {
611 list_for_each_entry_safe(neh, next, &rc->neh_list, list_node) { 622 spin_lock_irqsave(&rc->neh_lock, flags);
623 if (list_empty(&rc->neh_list)) {
624 spin_unlock_irqrestore(&rc->neh_lock, flags);
625 break;
626 }
627 neh = list_first_entry(&rc->neh_list, struct uwb_rc_neh, list_node);
612 __uwb_rc_neh_rm(rc, neh); 628 __uwb_rc_neh_rm(rc, neh);
629 spin_unlock_irqrestore(&rc->neh_lock, flags);
630
631 del_timer_sync(&neh->timer);
613 uwb_rc_neh_put(neh); 632 uwb_rc_neh_put(neh);
614 } 633 }
615 spin_unlock_irqrestore(&rc->neh_lock, flags);
616} 634}