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>
This commit is contained in:
parent
82107b73ea
commit
7ed80fe45d
|
@ -790,18 +790,23 @@ tei_ph_data_ind(struct teimgr *tm, u_int mt, u_char *dp, int len)
|
|||
static struct layer2 *
|
||||
create_new_tei(struct manager *mgr, int tei, int sapi)
|
||||
{
|
||||
u_long opt = 0;
|
||||
u_long flags;
|
||||
int id;
|
||||
struct layer2 *l2;
|
||||
unsigned long opt = 0;
|
||||
unsigned long flags;
|
||||
int id;
|
||||
struct layer2 *l2;
|
||||
struct channel_req rq;
|
||||
|
||||
if (!mgr->up)
|
||||
return NULL;
|
||||
if ((tei >= 0) && (tei < 64))
|
||||
test_and_set_bit(OPTION_L2_FIXEDTEI, &opt);
|
||||
if (mgr->ch.st->dev->Dprotocols
|
||||
& ((1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1)))
|
||||
if (mgr->ch.st->dev->Dprotocols & ((1 << ISDN_P_TE_E1) |
|
||||
(1 << ISDN_P_NT_E1))) {
|
||||
test_and_set_bit(OPTION_L2_PMX, &opt);
|
||||
rq.protocol = ISDN_P_NT_E1;
|
||||
} else {
|
||||
rq.protocol = ISDN_P_NT_S0;
|
||||
}
|
||||
l2 = create_l2(mgr->up, ISDN_P_LAPD_NT, opt, tei, sapi);
|
||||
if (!l2) {
|
||||
printk(KERN_WARNING "%s:no memory for layer2\n", __func__);
|
||||
|
@ -836,6 +841,14 @@ create_new_tei(struct manager *mgr, int tei, int sapi)
|
|||
l2->ch.recv = mgr->ch.recv;
|
||||
l2->ch.peer = mgr->ch.peer;
|
||||
l2->ch.ctrl(&l2->ch, OPEN_CHANNEL, NULL);
|
||||
/* We need open here L1 for the manager as well (refcounting) */
|
||||
rq.adr.dev = mgr->ch.st->dev->id;
|
||||
id = mgr->ch.st->own.ctrl(&mgr->ch.st->own, OPEN_CHANNEL, &rq);
|
||||
if (id < 0) {
|
||||
printk(KERN_WARNING "%s: cannot open L1\n", __func__);
|
||||
l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL);
|
||||
l2 = NULL;
|
||||
}
|
||||
}
|
||||
return l2;
|
||||
}
|
||||
|
@ -978,10 +991,11 @@ TEIrelease(struct layer2 *l2)
|
|||
static int
|
||||
create_teimgr(struct manager *mgr, struct channel_req *crq)
|
||||
{
|
||||
struct layer2 *l2;
|
||||
u_long opt = 0;
|
||||
u_long flags;
|
||||
int id;
|
||||
struct layer2 *l2;
|
||||
unsigned long opt = 0;
|
||||
unsigned long flags;
|
||||
int id;
|
||||
struct channel_req l1rq;
|
||||
|
||||
if (*debug & DEBUG_L2_TEI)
|
||||
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)
|
|||
if (crq->protocol == ISDN_P_LAPD_TE)
|
||||
test_and_set_bit(MGR_OPT_USER, &mgr->options);
|
||||
}
|
||||
l1rq.adr = crq->adr;
|
||||
if (mgr->ch.st->dev->Dprotocols
|
||||
& ((1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1)))
|
||||
test_and_set_bit(OPTION_L2_PMX, &opt);
|
||||
|
@ -1055,24 +1070,34 @@ create_teimgr(struct manager *mgr, struct channel_req *crq)
|
|||
l2->tm->tei_m.fsm = &teifsmu;
|
||||
l2->tm->tei_m.state = ST_TEI_NOP;
|
||||
l2->tm->tval = 1000; /* T201 1 sec */
|
||||
if (test_bit(OPTION_L2_PMX, &opt))
|
||||
l1rq.protocol = ISDN_P_TE_E1;
|
||||
else
|
||||
l1rq.protocol = ISDN_P_TE_S0;
|
||||
} else {
|
||||
l2->tm->tei_m.fsm = &teifsmn;
|
||||
l2->tm->tei_m.state = ST_TEI_NOP;
|
||||
l2->tm->tval = 2000; /* T202 2 sec */
|
||||
if (test_bit(OPTION_L2_PMX, &opt))
|
||||
l1rq.protocol = ISDN_P_NT_E1;
|
||||
else
|
||||
l1rq.protocol = ISDN_P_NT_S0;
|
||||
}
|
||||
mISDN_FsmInitTimer(&l2->tm->tei_m, &l2->tm->timer);
|
||||
write_lock_irqsave(&mgr->lock, flags);
|
||||
id = get_free_id(mgr);
|
||||
list_add_tail(&l2->list, &mgr->layer2);
|
||||
write_unlock_irqrestore(&mgr->lock, flags);
|
||||
if (id < 0) {
|
||||
l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL);
|
||||
} else {
|
||||
if (id >= 0) {
|
||||
l2->ch.nr = id;
|
||||
l2->up->nr = id;
|
||||
crq->ch = &l2->ch;
|
||||
id = 0;
|
||||
/* We need open here L1 for the manager as well (refcounting) */
|
||||
id = mgr->ch.st->own.ctrl(&mgr->ch.st->own, OPEN_CHANNEL,
|
||||
&l1rq);
|
||||
}
|
||||
if (id < 0)
|
||||
l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL);
|
||||
return id;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue