diff options
author | Karsten Keil <isdn@linux-pingi.de> | 2012-05-04 00:15:31 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-05-04 11:53:59 -0400 |
commit | 7ed80fe45d42678fb234bf9d18de6a98cfa9830d (patch) | |
tree | 0967e3bf027d4c90c41c7f841d520f978fca82a0 /drivers | |
parent | 82107b73eae812d8c089832b14b24ffe20a5c241 (diff) |
mISDN: Fix refcounting bug
Under some configs it was still not possible to unload the driver,
because the module use count was srewed up.
Signed-off-by: Karsten Keil <keil@b1-systems.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/isdn/mISDN/tei.c | 53 |
1 files changed, 39 insertions, 14 deletions
diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c index 969766f5f82b..109276a0d1a0 100644 --- a/drivers/isdn/mISDN/tei.c +++ b/drivers/isdn/mISDN/tei.c | |||
@@ -790,18 +790,23 @@ tei_ph_data_ind(struct teimgr *tm, u_int mt, u_char *dp, int len) | |||
790 | static struct layer2 * | 790 | static struct layer2 * |
791 | create_new_tei(struct manager *mgr, int tei, int sapi) | 791 | create_new_tei(struct manager *mgr, int tei, int sapi) |
792 | { | 792 | { |
793 | u_long opt = 0; | 793 | unsigned long opt = 0; |
794 | u_long flags; | 794 | unsigned long flags; |
795 | int id; | 795 | int id; |
796 | struct layer2 *l2; | 796 | struct layer2 *l2; |
797 | struct channel_req rq; | ||
797 | 798 | ||
798 | if (!mgr->up) | 799 | if (!mgr->up) |
799 | return NULL; | 800 | return NULL; |
800 | if ((tei >= 0) && (tei < 64)) | 801 | if ((tei >= 0) && (tei < 64)) |
801 | test_and_set_bit(OPTION_L2_FIXEDTEI, &opt); | 802 | test_and_set_bit(OPTION_L2_FIXEDTEI, &opt); |
802 | if (mgr->ch.st->dev->Dprotocols | 803 | if (mgr->ch.st->dev->Dprotocols & ((1 << ISDN_P_TE_E1) | |
803 | & ((1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1))) | 804 | (1 << ISDN_P_NT_E1))) { |
804 | test_and_set_bit(OPTION_L2_PMX, &opt); | 805 | test_and_set_bit(OPTION_L2_PMX, &opt); |
806 | rq.protocol = ISDN_P_NT_E1; | ||
807 | } else { | ||
808 | rq.protocol = ISDN_P_NT_S0; | ||
809 | } | ||
805 | l2 = create_l2(mgr->up, ISDN_P_LAPD_NT, opt, tei, sapi); | 810 | l2 = create_l2(mgr->up, ISDN_P_LAPD_NT, opt, tei, sapi); |
806 | if (!l2) { | 811 | if (!l2) { |
807 | printk(KERN_WARNING "%s:no memory for layer2\n", __func__); | 812 | printk(KERN_WARNING "%s:no memory for layer2\n", __func__); |
@@ -836,6 +841,14 @@ create_new_tei(struct manager *mgr, int tei, int sapi) | |||
836 | l2->ch.recv = mgr->ch.recv; | 841 | l2->ch.recv = mgr->ch.recv; |
837 | l2->ch.peer = mgr->ch.peer; | 842 | l2->ch.peer = mgr->ch.peer; |
838 | l2->ch.ctrl(&l2->ch, OPEN_CHANNEL, NULL); | 843 | l2->ch.ctrl(&l2->ch, OPEN_CHANNEL, NULL); |
844 | /* We need open here L1 for the manager as well (refcounting) */ | ||
845 | rq.adr.dev = mgr->ch.st->dev->id; | ||
846 | id = mgr->ch.st->own.ctrl(&mgr->ch.st->own, OPEN_CHANNEL, &rq); | ||
847 | if (id < 0) { | ||
848 | printk(KERN_WARNING "%s: cannot open L1\n", __func__); | ||
849 | l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); | ||
850 | l2 = NULL; | ||
851 | } | ||
839 | } | 852 | } |
840 | return l2; | 853 | return l2; |
841 | } | 854 | } |
@@ -978,10 +991,11 @@ TEIrelease(struct layer2 *l2) | |||
978 | static int | 991 | static int |
979 | create_teimgr(struct manager *mgr, struct channel_req *crq) | 992 | create_teimgr(struct manager *mgr, struct channel_req *crq) |
980 | { | 993 | { |
981 | struct layer2 *l2; | 994 | struct layer2 *l2; |
982 | u_long opt = 0; | 995 | unsigned long opt = 0; |
983 | u_long flags; | 996 | unsigned long flags; |
984 | int id; | 997 | int id; |
998 | struct channel_req l1rq; | ||
985 | 999 | ||
986 | if (*debug & DEBUG_L2_TEI) | 1000 | if (*debug & DEBUG_L2_TEI) |
987 | printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", | 1001 | printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", |
@@ -1016,6 +1030,7 @@ create_teimgr(struct manager *mgr, struct channel_req *crq) | |||
1016 | if (crq->protocol == ISDN_P_LAPD_TE) | 1030 | if (crq->protocol == ISDN_P_LAPD_TE) |
1017 | test_and_set_bit(MGR_OPT_USER, &mgr->options); | 1031 | test_and_set_bit(MGR_OPT_USER, &mgr->options); |
1018 | } | 1032 | } |
1033 | l1rq.adr = crq->adr; | ||
1019 | if (mgr->ch.st->dev->Dprotocols | 1034 | if (mgr->ch.st->dev->Dprotocols |
1020 | & ((1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1))) | 1035 | & ((1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1))) |
1021 | test_and_set_bit(OPTION_L2_PMX, &opt); | 1036 | test_and_set_bit(OPTION_L2_PMX, &opt); |
@@ -1055,24 +1070,34 @@ create_teimgr(struct manager *mgr, struct channel_req *crq) | |||
1055 | l2->tm->tei_m.fsm = &teifsmu; | 1070 | l2->tm->tei_m.fsm = &teifsmu; |
1056 | l2->tm->tei_m.state = ST_TEI_NOP; | 1071 | l2->tm->tei_m.state = ST_TEI_NOP; |
1057 | l2->tm->tval = 1000; /* T201 1 sec */ | 1072 | l2->tm->tval = 1000; /* T201 1 sec */ |
1073 | if (test_bit(OPTION_L2_PMX, &opt)) | ||
1074 | l1rq.protocol = ISDN_P_TE_E1; | ||
1075 | else | ||
1076 | l1rq.protocol = ISDN_P_TE_S0; | ||
1058 | } else { | 1077 | } else { |
1059 | l2->tm->tei_m.fsm = &teifsmn; | 1078 | l2->tm->tei_m.fsm = &teifsmn; |
1060 | l2->tm->tei_m.state = ST_TEI_NOP; | 1079 | l2->tm->tei_m.state = ST_TEI_NOP; |
1061 | l2->tm->tval = 2000; /* T202 2 sec */ | 1080 | l2->tm->tval = 2000; /* T202 2 sec */ |
1081 | if (test_bit(OPTION_L2_PMX, &opt)) | ||
1082 | l1rq.protocol = ISDN_P_NT_E1; | ||
1083 | else | ||
1084 | l1rq.protocol = ISDN_P_NT_S0; | ||
1062 | } | 1085 | } |
1063 | mISDN_FsmInitTimer(&l2->tm->tei_m, &l2->tm->timer); | 1086 | mISDN_FsmInitTimer(&l2->tm->tei_m, &l2->tm->timer); |
1064 | write_lock_irqsave(&mgr->lock, flags); | 1087 | write_lock_irqsave(&mgr->lock, flags); |
1065 | id = get_free_id(mgr); | 1088 | id = get_free_id(mgr); |
1066 | list_add_tail(&l2->list, &mgr->layer2); | 1089 | list_add_tail(&l2->list, &mgr->layer2); |
1067 | write_unlock_irqrestore(&mgr->lock, flags); | 1090 | write_unlock_irqrestore(&mgr->lock, flags); |
1068 | if (id < 0) { | 1091 | if (id >= 0) { |
1069 | l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); | ||
1070 | } else { | ||
1071 | l2->ch.nr = id; | 1092 | l2->ch.nr = id; |
1072 | l2->up->nr = id; | 1093 | l2->up->nr = id; |
1073 | crq->ch = &l2->ch; | 1094 | crq->ch = &l2->ch; |
1074 | id = 0; | 1095 | /* We need open here L1 for the manager as well (refcounting) */ |
1096 | id = mgr->ch.st->own.ctrl(&mgr->ch.st->own, OPEN_CHANNEL, | ||
1097 | &l1rq); | ||
1075 | } | 1098 | } |
1099 | if (id < 0) | ||
1100 | l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); | ||
1076 | return id; | 1101 | return id; |
1077 | } | 1102 | } |
1078 | 1103 | ||