Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

caif-shm: Bugfixes for caif_shmcore.c

Various bugfixes for caif_shmcore.c:
- fix deadlocks due to improper usage of spin-lock
- add missing spin-lock init
- don't call dev_kfree_skb() with irqs disabled,
use dev_kfree_skb_irq() instead.
- fix potential skb null pointer de-reference.

Squashed original patches from:
Rabin Vincent <rabin.vincent@stericsson.com>
Durga Prasada Rao BATHINA <durgaprasadarao.b@stericcson.com>
Arun Murthy <arun.murthy@stericsson.com>
Bibek Basu <bibek.basu@stericsson.com>

Signed-off-by: Sjur Brændeland <sjur.brandeland@stericsson.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

sjur.brandeland@stericsson.com and committed by
David S. Miller
095d2a71 005b0b07

+11 -10
+11 -10
drivers/net/caif/caif_shmcore.c
··· 238 238 if ((avail_emptybuff > HIGH_WATERMARK) && 239 239 (!pshm_drv->tx_empty_available)) { 240 240 pshm_drv->tx_empty_available = 1; 241 + spin_unlock_irqrestore(&pshm_drv->lock, flags); 241 242 pshm_drv->cfdev.flowctrl 242 243 (pshm_drv->pshm_dev->pshm_netdev, 243 244 CAIF_FLOW_ON); 244 245 245 - spin_unlock_irqrestore(&pshm_drv->lock, flags); 246 246 247 247 /* Schedule the work queue. if required */ 248 248 if (!work_pending(&pshm_drv->shm_tx_work)) ··· 285 285 list_entry(pshm_drv->rx_full_list.next, struct buf_list, 286 286 list); 287 287 list_del_init(&pbuf->list); 288 + spin_unlock_irqrestore(&pshm_drv->lock, flags); 288 289 289 290 /* Retrieve pointer to start of the packet descriptor area. */ 290 291 pck_desc = (struct shm_pck_desc *) pbuf->desc_vptr; ··· 361 360 pck_desc++; 362 361 } 363 362 363 + spin_lock_irqsave(&pshm_drv->lock, flags); 364 364 list_add_tail(&pbuf->list, &pshm_drv->rx_pend_list); 365 365 366 366 spin_unlock_irqrestore(&pshm_drv->lock, flags); ··· 414 412 415 413 if (skb == NULL) 416 414 goto send_msg; 417 - 418 415 /* Check the available no. of buffers in the empty list */ 419 416 list_for_each(pos, &pshm_drv->tx_empty_list) 420 417 avail_emptybuff++; ··· 422 421 pshm_drv->tx_empty_available) { 423 422 /* Update blocking condition. */ 424 423 pshm_drv->tx_empty_available = 0; 424 + spin_unlock_irqrestore(&pshm_drv->lock, flags); 425 425 pshm_drv->cfdev.flowctrl 426 426 (pshm_drv->pshm_dev->pshm_netdev, 427 427 CAIF_FLOW_OFF); 428 + spin_lock_irqsave(&pshm_drv->lock, flags); 428 429 } 429 430 /* 430 431 * We simply return back to the caller if we do not have space ··· 472 469 } 473 470 474 471 skb = skb_dequeue(&pshm_drv->sk_qhead); 472 + if (skb == NULL) 473 + break; 475 474 /* Copy in CAIF frame. */ 476 475 skb_copy_bits(skb, 0, pbuf->desc_vptr + 477 476 pbuf->frm_ofs + SHM_HDR_LEN + ··· 482 477 pshm_drv->pshm_dev->pshm_netdev->stats.tx_packets++; 483 478 pshm_drv->pshm_dev->pshm_netdev->stats.tx_bytes += 484 479 frmlen; 485 - dev_kfree_skb(skb); 480 + dev_kfree_skb_irq(skb); 486 481 487 482 /* Fill in the shared memory packet descriptor area. */ 488 483 pck_desc = (struct shm_pck_desc *) (pbuf->desc_vptr); ··· 517 512 static int shm_netdev_tx(struct sk_buff *skb, struct net_device *shm_netdev) 518 513 { 519 514 struct shmdrv_layer *pshm_drv; 520 - unsigned long flags = 0; 521 515 522 516 pshm_drv = netdev_priv(shm_netdev); 523 517 524 - spin_lock_irqsave(&pshm_drv->lock, flags); 525 - 526 518 skb_queue_tail(&pshm_drv->sk_qhead, skb); 527 - 528 - spin_unlock_irqrestore(&pshm_drv->lock, flags); 529 519 530 520 /* Schedule Tx work queue. for deferred processing of skbs*/ 531 521 if (!work_pending(&pshm_drv->shm_tx_work)) ··· 606 606 pshm_drv->shm_rx_addr = pshm_dev->shm_base_addr + 607 607 (NR_TX_BUF * TX_BUF_SZ); 608 608 609 + spin_lock_init(&pshm_drv->lock); 609 610 INIT_LIST_HEAD(&pshm_drv->tx_empty_list); 610 611 INIT_LIST_HEAD(&pshm_drv->tx_pend_list); 611 612 INIT_LIST_HEAD(&pshm_drv->tx_full_list); ··· 641 640 tx_buf->frm_ofs = SHM_CAIF_FRM_OFS; 642 641 643 642 if (pshm_dev->shm_loopback) 644 - tx_buf->desc_vptr = (char *)tx_buf->phy_addr; 643 + tx_buf->desc_vptr = (unsigned char *)tx_buf->phy_addr; 645 644 else 646 645 tx_buf->desc_vptr = 647 646 ioremap(tx_buf->phy_addr, TX_BUF_SZ); ··· 665 664 rx_buf->len = RX_BUF_SZ; 666 665 667 666 if (pshm_dev->shm_loopback) 668 - rx_buf->desc_vptr = (char *)rx_buf->phy_addr; 667 + rx_buf->desc_vptr = (unsigned char *)rx_buf->phy_addr; 669 668 else 670 669 rx_buf->desc_vptr = 671 670 ioremap(rx_buf->phy_addr, RX_BUF_SZ);