diff options
Diffstat (limited to 'drivers/isdn/capi/kcapi.c')
-rw-r--r-- | drivers/isdn/capi/kcapi.c | 52 |
1 files changed, 22 insertions, 30 deletions
diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c index a99f7e3f8f51..0b4c8a7396bc 100644 --- a/drivers/isdn/capi/kcapi.c +++ b/drivers/isdn/capi/kcapi.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/b1lli.h> | 34 | #include <linux/b1lli.h> |
35 | #endif | 35 | #endif |
36 | #include <linux/mutex.h> | 36 | #include <linux/mutex.h> |
37 | #include <linux/rcupdate.h> | ||
37 | 38 | ||
38 | static int showcapimsgs = 0; | 39 | static int showcapimsgs = 0; |
39 | 40 | ||
@@ -64,8 +65,6 @@ DEFINE_MUTEX(capi_drivers_lock); | |||
64 | struct capi_ctr *capi_controller[CAPI_MAXCONTR]; | 65 | struct capi_ctr *capi_controller[CAPI_MAXCONTR]; |
65 | DEFINE_MUTEX(capi_controller_lock); | 66 | DEFINE_MUTEX(capi_controller_lock); |
66 | 67 | ||
67 | static DEFINE_RWLOCK(application_lock); | ||
68 | |||
69 | struct capi20_appl *capi_applications[CAPI_MAXAPPL]; | 68 | struct capi20_appl *capi_applications[CAPI_MAXAPPL]; |
70 | 69 | ||
71 | static int ncontrollers; | 70 | static int ncontrollers; |
@@ -103,7 +102,7 @@ static inline struct capi20_appl *get_capi_appl_by_nr(u16 applid) | |||
103 | if (applid - 1 >= CAPI_MAXAPPL) | 102 | if (applid - 1 >= CAPI_MAXAPPL) |
104 | return NULL; | 103 | return NULL; |
105 | 104 | ||
106 | return capi_applications[applid - 1]; | 105 | return rcu_dereference(capi_applications[applid - 1]); |
107 | } | 106 | } |
108 | 107 | ||
109 | /* -------- util functions ------------------------------------ */ | 108 | /* -------- util functions ------------------------------------ */ |
@@ -186,7 +185,7 @@ static void notify_up(u32 contr) | |||
186 | 185 | ||
187 | for (applid = 1; applid <= CAPI_MAXAPPL; applid++) { | 186 | for (applid = 1; applid <= CAPI_MAXAPPL; applid++) { |
188 | ap = get_capi_appl_by_nr(applid); | 187 | ap = get_capi_appl_by_nr(applid); |
189 | if (!ap || ap->release_in_progress) | 188 | if (!ap) |
190 | continue; | 189 | continue; |
191 | register_appl(ctr, applid, &ap->rparam); | 190 | register_appl(ctr, applid, &ap->rparam); |
192 | } | 191 | } |
@@ -216,7 +215,7 @@ static void ctr_down(struct capi_ctr *ctr, int new_state) | |||
216 | 215 | ||
217 | for (applid = 1; applid <= CAPI_MAXAPPL; applid++) { | 216 | for (applid = 1; applid <= CAPI_MAXAPPL; applid++) { |
218 | ap = get_capi_appl_by_nr(applid); | 217 | ap = get_capi_appl_by_nr(applid); |
219 | if (ap && !ap->release_in_progress) | 218 | if (ap) |
220 | capi_ctr_put(ctr); | 219 | capi_ctr_put(ctr); |
221 | } | 220 | } |
222 | 221 | ||
@@ -336,7 +335,6 @@ void capi_ctr_handle_message(struct capi_ctr *ctr, u16 appl, | |||
336 | struct capi20_appl *ap; | 335 | struct capi20_appl *ap; |
337 | int showctl = 0; | 336 | int showctl = 0; |
338 | u8 cmd, subcmd; | 337 | u8 cmd, subcmd; |
339 | unsigned long flags; | ||
340 | _cdebbuf *cdb; | 338 | _cdebbuf *cdb; |
341 | 339 | ||
342 | if (ctr->state != CAPI_CTR_RUNNING) { | 340 | if (ctr->state != CAPI_CTR_RUNNING) { |
@@ -384,10 +382,10 @@ void capi_ctr_handle_message(struct capi_ctr *ctr, u16 appl, | |||
384 | 382 | ||
385 | } | 383 | } |
386 | 384 | ||
387 | read_lock_irqsave(&application_lock, flags); | 385 | rcu_read_lock(); |
388 | ap = get_capi_appl_by_nr(CAPIMSG_APPID(skb->data)); | 386 | ap = get_capi_appl_by_nr(CAPIMSG_APPID(skb->data)); |
389 | if ((!ap) || (ap->release_in_progress)) { | 387 | if (!ap) { |
390 | read_unlock_irqrestore(&application_lock, flags); | 388 | rcu_read_unlock(); |
391 | cdb = capi_message2str(skb->data); | 389 | cdb = capi_message2str(skb->data); |
392 | if (cdb) { | 390 | if (cdb) { |
393 | printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s)\n", | 391 | printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s)\n", |
@@ -401,7 +399,7 @@ void capi_ctr_handle_message(struct capi_ctr *ctr, u16 appl, | |||
401 | } | 399 | } |
402 | skb_queue_tail(&ap->recv_queue, skb); | 400 | skb_queue_tail(&ap->recv_queue, skb); |
403 | schedule_work(&ap->recv_work); | 401 | schedule_work(&ap->recv_work); |
404 | read_unlock_irqrestore(&application_lock, flags); | 402 | rcu_read_unlock(); |
405 | 403 | ||
406 | return; | 404 | return; |
407 | 405 | ||
@@ -656,40 +654,35 @@ u16 capi20_register(struct capi20_appl *ap) | |||
656 | { | 654 | { |
657 | int i; | 655 | int i; |
658 | u16 applid; | 656 | u16 applid; |
659 | unsigned long flags; | ||
660 | 657 | ||
661 | DBG(""); | 658 | DBG(""); |
662 | 659 | ||
663 | if (ap->rparam.datablklen < 128) | 660 | if (ap->rparam.datablklen < 128) |
664 | return CAPI_LOGBLKSIZETOSMALL; | 661 | return CAPI_LOGBLKSIZETOSMALL; |
665 | 662 | ||
666 | write_lock_irqsave(&application_lock, flags); | 663 | ap->nrecvctlpkt = 0; |
664 | ap->nrecvdatapkt = 0; | ||
665 | ap->nsentctlpkt = 0; | ||
666 | ap->nsentdatapkt = 0; | ||
667 | mutex_init(&ap->recv_mtx); | ||
668 | skb_queue_head_init(&ap->recv_queue); | ||
669 | INIT_WORK(&ap->recv_work, recv_handler); | ||
670 | ap->release_in_progress = 0; | ||
671 | |||
672 | mutex_lock(&capi_controller_lock); | ||
667 | 673 | ||
668 | for (applid = 1; applid <= CAPI_MAXAPPL; applid++) { | 674 | for (applid = 1; applid <= CAPI_MAXAPPL; applid++) { |
669 | if (capi_applications[applid - 1] == NULL) | 675 | if (capi_applications[applid - 1] == NULL) |
670 | break; | 676 | break; |
671 | } | 677 | } |
672 | if (applid > CAPI_MAXAPPL) { | 678 | if (applid > CAPI_MAXAPPL) { |
673 | write_unlock_irqrestore(&application_lock, flags); | 679 | mutex_unlock(&capi_controller_lock); |
674 | return CAPI_TOOMANYAPPLS; | 680 | return CAPI_TOOMANYAPPLS; |
675 | } | 681 | } |
676 | 682 | ||
677 | ap->applid = applid; | 683 | ap->applid = applid; |
678 | capi_applications[applid - 1] = ap; | 684 | capi_applications[applid - 1] = ap; |
679 | 685 | ||
680 | ap->nrecvctlpkt = 0; | ||
681 | ap->nrecvdatapkt = 0; | ||
682 | ap->nsentctlpkt = 0; | ||
683 | ap->nsentdatapkt = 0; | ||
684 | mutex_init(&ap->recv_mtx); | ||
685 | skb_queue_head_init(&ap->recv_queue); | ||
686 | INIT_WORK(&ap->recv_work, recv_handler); | ||
687 | ap->release_in_progress = 0; | ||
688 | |||
689 | write_unlock_irqrestore(&application_lock, flags); | ||
690 | |||
691 | mutex_lock(&capi_controller_lock); | ||
692 | |||
693 | for (i = 0; i < CAPI_MAXCONTR; i++) { | 686 | for (i = 0; i < CAPI_MAXCONTR; i++) { |
694 | if (!capi_controller[i] || | 687 | if (!capi_controller[i] || |
695 | capi_controller[i]->state != CAPI_CTR_RUNNING) | 688 | capi_controller[i]->state != CAPI_CTR_RUNNING) |
@@ -721,16 +714,15 @@ EXPORT_SYMBOL(capi20_register); | |||
721 | u16 capi20_release(struct capi20_appl *ap) | 714 | u16 capi20_release(struct capi20_appl *ap) |
722 | { | 715 | { |
723 | int i; | 716 | int i; |
724 | unsigned long flags; | ||
725 | 717 | ||
726 | DBG("applid %#x", ap->applid); | 718 | DBG("applid %#x", ap->applid); |
727 | 719 | ||
728 | write_lock_irqsave(&application_lock, flags); | 720 | mutex_lock(&capi_controller_lock); |
721 | |||
729 | ap->release_in_progress = 1; | 722 | ap->release_in_progress = 1; |
730 | capi_applications[ap->applid - 1] = NULL; | 723 | capi_applications[ap->applid - 1] = NULL; |
731 | write_unlock_irqrestore(&application_lock, flags); | ||
732 | 724 | ||
733 | mutex_lock(&capi_controller_lock); | 725 | synchronize_rcu(); |
734 | 726 | ||
735 | for (i = 0; i < CAPI_MAXCONTR; i++) { | 727 | for (i = 0; i < CAPI_MAXCONTR; i++) { |
736 | if (!capi_controller[i] || | 728 | if (!capi_controller[i] || |