diff options
| author | Karsten Keil <kkeil@suse.de> | 2007-10-18 06:04:31 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-18 17:37:17 -0400 |
| commit | 9713d9e650045f7f2afd81d58a068827be306993 (patch) | |
| tree | e4913e15b37f9ad5da9a037fac0f53f3a78cef64 /drivers/isdn/hardware | |
| parent | 0c42ea3f93b5684cf60ba0ac6810ad1f865954b0 (diff) | |
i4l: fix random freezes with AVM B1 drivers
This fix the same issue which was debbuged for the C4 controller for the B1
versions.
The capilib_ function modify or traverse a linked list without locking.
This patch extends the existing locking to the calls of these function to
prevent access to a list which is in the middle of a modification.
Signed-off-by: Karsten Keil <kkeil@suse.de>
C: <stable@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/isdn/hardware')
| -rw-r--r-- | drivers/isdn/hardware/avm/b1.c | 28 |
1 files changed, 13 insertions, 15 deletions
diff --git a/drivers/isdn/hardware/avm/b1.c b/drivers/isdn/hardware/avm/b1.c index 7a69a18d07..4484a64172 100644 --- a/drivers/isdn/hardware/avm/b1.c +++ b/drivers/isdn/hardware/avm/b1.c | |||
| @@ -321,12 +321,15 @@ void b1_reset_ctr(struct capi_ctr *ctrl) | |||
| 321 | avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); | 321 | avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); |
| 322 | avmcard *card = cinfo->card; | 322 | avmcard *card = cinfo->card; |
| 323 | unsigned int port = card->port; | 323 | unsigned int port = card->port; |
| 324 | unsigned long flags; | ||
| 324 | 325 | ||
| 325 | b1_reset(port); | 326 | b1_reset(port); |
| 326 | b1_reset(port); | 327 | b1_reset(port); |
| 327 | 328 | ||
| 328 | memset(cinfo->version, 0, sizeof(cinfo->version)); | 329 | memset(cinfo->version, 0, sizeof(cinfo->version)); |
| 330 | spin_lock_irqsave(&card->lock, flags); | ||
| 329 | capilib_release(&cinfo->ncci_head); | 331 | capilib_release(&cinfo->ncci_head); |
| 332 | spin_unlock_irqrestore(&card->lock, flags); | ||
| 330 | capi_ctr_reseted(ctrl); | 333 | capi_ctr_reseted(ctrl); |
| 331 | } | 334 | } |
| 332 | 335 | ||
| @@ -361,9 +364,8 @@ void b1_release_appl(struct capi_ctr *ctrl, u16 appl) | |||
| 361 | unsigned int port = card->port; | 364 | unsigned int port = card->port; |
| 362 | unsigned long flags; | 365 | unsigned long flags; |
| 363 | 366 | ||
| 364 | capilib_release_appl(&cinfo->ncci_head, appl); | ||
| 365 | |||
| 366 | spin_lock_irqsave(&card->lock, flags); | 367 | spin_lock_irqsave(&card->lock, flags); |
| 368 | capilib_release_appl(&cinfo->ncci_head, appl); | ||
| 367 | b1_put_byte(port, SEND_RELEASE); | 369 | b1_put_byte(port, SEND_RELEASE); |
| 368 | b1_put_word(port, appl); | 370 | b1_put_word(port, appl); |
| 369 | spin_unlock_irqrestore(&card->lock, flags); | 371 | spin_unlock_irqrestore(&card->lock, flags); |
| @@ -380,27 +382,27 @@ u16 b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) | |||
| 380 | u8 subcmd = CAPIMSG_SUBCOMMAND(skb->data); | 382 | u8 subcmd = CAPIMSG_SUBCOMMAND(skb->data); |
| 381 | u16 dlen, retval; | 383 | u16 dlen, retval; |
| 382 | 384 | ||
| 385 | spin_lock_irqsave(&card->lock, flags); | ||
| 383 | if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) { | 386 | if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) { |
| 384 | retval = capilib_data_b3_req(&cinfo->ncci_head, | 387 | retval = capilib_data_b3_req(&cinfo->ncci_head, |
| 385 | CAPIMSG_APPID(skb->data), | 388 | CAPIMSG_APPID(skb->data), |
| 386 | CAPIMSG_NCCI(skb->data), | 389 | CAPIMSG_NCCI(skb->data), |
| 387 | CAPIMSG_MSGID(skb->data)); | 390 | CAPIMSG_MSGID(skb->data)); |
| 388 | if (retval != CAPI_NOERROR) | 391 | if (retval != CAPI_NOERROR) { |
| 392 | spin_unlock_irqrestore(&card->lock, flags); | ||
| 389 | return retval; | 393 | return retval; |
| 394 | } | ||
| 390 | 395 | ||
| 391 | dlen = CAPIMSG_DATALEN(skb->data); | 396 | dlen = CAPIMSG_DATALEN(skb->data); |
| 392 | 397 | ||
| 393 | spin_lock_irqsave(&card->lock, flags); | ||
| 394 | b1_put_byte(port, SEND_DATA_B3_REQ); | 398 | b1_put_byte(port, SEND_DATA_B3_REQ); |
| 395 | b1_put_slice(port, skb->data, len); | 399 | b1_put_slice(port, skb->data, len); |
| 396 | b1_put_slice(port, skb->data + len, dlen); | 400 | b1_put_slice(port, skb->data + len, dlen); |
| 397 | spin_unlock_irqrestore(&card->lock, flags); | ||
| 398 | } else { | 401 | } else { |
| 399 | spin_lock_irqsave(&card->lock, flags); | ||
| 400 | b1_put_byte(port, SEND_MESSAGE); | 402 | b1_put_byte(port, SEND_MESSAGE); |
| 401 | b1_put_slice(port, skb->data, len); | 403 | b1_put_slice(port, skb->data, len); |
| 402 | spin_unlock_irqrestore(&card->lock, flags); | ||
| 403 | } | 404 | } |
| 405 | spin_unlock_irqrestore(&card->lock, flags); | ||
| 404 | 406 | ||
| 405 | dev_kfree_skb_any(skb); | 407 | dev_kfree_skb_any(skb); |
| 406 | return CAPI_NOERROR; | 408 | return CAPI_NOERROR; |
| @@ -534,17 +536,17 @@ irqreturn_t b1_interrupt(int interrupt, void *devptr) | |||
| 534 | 536 | ||
| 535 | ApplId = (unsigned) b1_get_word(card->port); | 537 | ApplId = (unsigned) b1_get_word(card->port); |
| 536 | MsgLen = b1_get_slice(card->port, card->msgbuf); | 538 | MsgLen = b1_get_slice(card->port, card->msgbuf); |
| 537 | spin_unlock_irqrestore(&card->lock, flags); | ||
| 538 | if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) { | 539 | if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) { |
| 539 | printk(KERN_ERR "%s: incoming packet dropped\n", | 540 | printk(KERN_ERR "%s: incoming packet dropped\n", |
| 540 | card->name); | 541 | card->name); |
| 542 | spin_unlock_irqrestore(&card->lock, flags); | ||
| 541 | } else { | 543 | } else { |
| 542 | memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); | 544 | memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen); |
| 543 | if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_CONF) | 545 | if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_CONF) |
| 544 | capilib_data_b3_conf(&cinfo->ncci_head, ApplId, | 546 | capilib_data_b3_conf(&cinfo->ncci_head, ApplId, |
| 545 | CAPIMSG_NCCI(skb->data), | 547 | CAPIMSG_NCCI(skb->data), |
| 546 | CAPIMSG_MSGID(skb->data)); | 548 | CAPIMSG_MSGID(skb->data)); |
| 547 | 549 | spin_unlock_irqrestore(&card->lock, flags); | |
| 548 | capi_ctr_handle_message(ctrl, ApplId, skb); | 550 | capi_ctr_handle_message(ctrl, ApplId, skb); |
| 549 | } | 551 | } |
| 550 | break; | 552 | break; |
| @@ -554,21 +556,17 @@ irqreturn_t b1_interrupt(int interrupt, void *devptr) | |||
| 554 | ApplId = b1_get_word(card->port); | 556 | ApplId = b1_get_word(card->port); |
| 555 | NCCI = b1_get_word(card->port); | 557 | NCCI = b1_get_word(card->port); |
| 556 | WindowSize = b1_get_word(card->port); | 558 | WindowSize = b1_get_word(card->port); |
| 557 | spin_unlock_irqrestore(&card->lock, flags); | ||
| 558 | |||
| 559 | capilib_new_ncci(&cinfo->ncci_head, ApplId, NCCI, WindowSize); | 559 | capilib_new_ncci(&cinfo->ncci_head, ApplId, NCCI, WindowSize); |
| 560 | 560 | spin_unlock_irqrestore(&card->lock, flags); | |
| 561 | break; | 561 | break; |
| 562 | 562 | ||
| 563 | case RECEIVE_FREE_NCCI: | 563 | case RECEIVE_FREE_NCCI: |
| 564 | 564 | ||
| 565 | ApplId = b1_get_word(card->port); | 565 | ApplId = b1_get_word(card->port); |
| 566 | NCCI = b1_get_word(card->port); | 566 | NCCI = b1_get_word(card->port); |
| 567 | spin_unlock_irqrestore(&card->lock, flags); | ||
| 568 | |||
| 569 | if (NCCI != 0xffffffff) | 567 | if (NCCI != 0xffffffff) |
| 570 | capilib_free_ncci(&cinfo->ncci_head, ApplId, NCCI); | 568 | capilib_free_ncci(&cinfo->ncci_head, ApplId, NCCI); |
| 571 | 569 | spin_unlock_irqrestore(&card->lock, flags); | |
| 572 | break; | 570 | break; |
| 573 | 571 | ||
| 574 | case RECEIVE_START: | 572 | case RECEIVE_START: |
