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 7a69a18d07e2..4484a6417235 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: |