Skip to content

Commit

Permalink
mISDN: Fix refcounting bug
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
Karsten Keil authored and davem330 committed May 4, 2012
1 parent 82107b7 commit 7ed80fe
Showing 1 changed file with 39 additions and 14 deletions.
53 changes: 39 additions & 14 deletions drivers/isdn/mISDN/tei.c
Original file line number Diff line number Diff line change
Expand Up @@ -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__);
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}

Expand Down

0 comments on commit 7ed80fe

Please sign in to comment.