aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/isdn/capi
diff options
context:
space:
mode:
authorJan Kiszka <jan.kiszka@web.de>2010-02-08 05:12:15 -0500
committerDavid S. Miller <davem@davemloft.net>2010-02-16 19:01:22 -0500
commit88c896ef87fd0dd4dbf36e8e86e019c74b1f6649 (patch)
tree727de518c111fc1d3d3a3bf49ea292ea414e17c6 /drivers/isdn/capi
parent0ca3a017a7373a4545dd7b345a8a0cecc16bc7e2 (diff)
CAPI: Rework application locking
Drop the application rw-lock in favour of RCU. This synchronizes capi20_release against capi_ctr_handle_message which may dereference an application from (soft-)IRQ context. Any other access to the application list is now protected by the capi_controller_lock as well. This also allows to safely inspect applications for /proc dumping by holding capi_controller_lock. At this chance, drop some useless release_in_progress checks where we obtained the application pointer from the list (which becomes NULL on release_in_progress). Signed-off-by: Jan Kiszka <jan.kiszka@web.de> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/isdn/capi')
-rw-r--r--drivers/isdn/capi/kcapi.c52
-rw-r--r--drivers/isdn/capi/kcapi_proc.c11
2 files changed, 29 insertions, 34 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
38static int showcapimsgs = 0; 39static int showcapimsgs = 0;
39 40
@@ -64,8 +65,6 @@ DEFINE_MUTEX(capi_drivers_lock);
64struct capi_ctr *capi_controller[CAPI_MAXCONTR]; 65struct capi_ctr *capi_controller[CAPI_MAXCONTR];
65DEFINE_MUTEX(capi_controller_lock); 66DEFINE_MUTEX(capi_controller_lock);
66 67
67static DEFINE_RWLOCK(application_lock);
68
69struct capi20_appl *capi_applications[CAPI_MAXAPPL]; 68struct capi20_appl *capi_applications[CAPI_MAXAPPL];
70 69
71static int ncontrollers; 70static 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);
721u16 capi20_release(struct capi20_appl *ap) 714u16 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] ||
diff --git a/drivers/isdn/capi/kcapi_proc.c b/drivers/isdn/capi/kcapi_proc.c
index 3e6e17a24389..ea2dff602e49 100644
--- a/drivers/isdn/capi/kcapi_proc.c
+++ b/drivers/isdn/capi/kcapi_proc.c
@@ -139,9 +139,11 @@ static const struct file_operations proc_contrstats_ops = {
139// applid nrecvctlpkt nrecvdatapkt nsentctlpkt nsentdatapkt 139// applid nrecvctlpkt nrecvdatapkt nsentctlpkt nsentdatapkt
140// --------------------------------------------------------------------------- 140// ---------------------------------------------------------------------------
141 141
142static void * 142static void *applications_start(struct seq_file *seq, loff_t *pos)
143applications_start(struct seq_file *seq, loff_t *pos) 143 __acquires(capi_controller_lock)
144{ 144{
145 mutex_lock(&capi_controller_lock);
146
145 if (*pos < CAPI_MAXAPPL) 147 if (*pos < CAPI_MAXAPPL)
146 return &capi_applications[*pos]; 148 return &capi_applications[*pos];
147 149
@@ -158,9 +160,10 @@ applications_next(struct seq_file *seq, void *v, loff_t *pos)
158 return NULL; 160 return NULL;
159} 161}
160 162
161static void 163static void applications_stop(struct seq_file *seq, void *v)
162applications_stop(struct seq_file *seq, void *v) 164 __releases(capi_controller_lock)
163{ 165{
166 mutex_unlock(&capi_controller_lock);
164} 167}
165 168
166static int 169static int