From 44f9b3d8c11ff71fd599827643a323e6f5a3b6d2 Mon Sep 17 00:00:00 2001 From: Arun Murthy Date: Fri, 9 Sep 2011 18:49:22 +0530 Subject: caif-shm: Fix deadlock caused due to improper locking Improper usage of spin lock, which leads to deadlock. Tx: acquire_lock1 -> trying to acquire lock2 Rx: acquire_lock2 -> trying to acquire lock1 Fix: locking was done through out the function which is not required. Only in placed where list has be accessed or modified locking is required. ST-Ericsson Linux next: NA ST-Ericsson ID: 360284 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I962fcb35f44b6030d6f1151f118d35e328b69156 Signed-off-by: Arun Murthy Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/30980 Reviewed-by: Hemant-vilas RAMDASI Tested-by: Hemant-vilas RAMDASI Reviewed-by: Durga Prasada Rao BATHINA --- drivers/net/caif/caif_shmcore.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/net/caif/caif_shmcore.c b/drivers/net/caif/caif_shmcore.c index d4b26fb24ed..27392cd05fd 100644 --- a/drivers/net/caif/caif_shmcore.c +++ b/drivers/net/caif/caif_shmcore.c @@ -238,11 +238,11 @@ int caif_shmdrv_rx_cb(u32 mbx_msg, void *priv) if ((avail_emptybuff > HIGH_WATERMARK) && (!pshm_drv->tx_empty_available)) { pshm_drv->tx_empty_available = 1; + spin_unlock_irqrestore(&pshm_drv->lock, flags); pshm_drv->cfdev.flowctrl (pshm_drv->pshm_dev->pshm_netdev, CAIF_FLOW_ON); - spin_unlock_irqrestore(&pshm_drv->lock, flags); /* Schedule the work queue. if required */ if (!work_pending(&pshm_drv->shm_tx_work)) @@ -285,6 +285,7 @@ static void shm_rx_work_func(struct work_struct *rx_work) list_entry(pshm_drv->rx_full_list.next, struct buf_list, list); list_del_init(&pbuf->list); + spin_unlock_irqrestore(&pshm_drv->lock, flags); /* Retrieve pointer to start of the packet descriptor area. */ pck_desc = (struct shm_pck_desc *) pbuf->desc_vptr; @@ -360,6 +361,7 @@ static void shm_rx_work_func(struct work_struct *rx_work) pck_desc++; } + spin_lock_irqsave(&pshm_drv->lock, flags); list_add_tail(&pbuf->list, &pshm_drv->rx_pend_list); spin_unlock_irqrestore(&pshm_drv->lock, flags); @@ -412,7 +414,6 @@ static void shm_tx_work_func(struct work_struct *tx_work) if (skb == NULL) goto send_msg; - /* Check the available no. of buffers in the empty list */ list_for_each(pos, &pshm_drv->tx_empty_list) avail_emptybuff++; @@ -421,9 +422,11 @@ static void shm_tx_work_func(struct work_struct *tx_work) pshm_drv->tx_empty_available) { /* Update blocking condition. */ pshm_drv->tx_empty_available = 0; + spin_unlock_irqrestore(&pshm_drv->lock, flags); pshm_drv->cfdev.flowctrl (pshm_drv->pshm_dev->pshm_netdev, CAIF_FLOW_OFF); + spin_lock_irqsave(&pshm_drv->lock, flags); } /* * We simply return back to the caller if we do not have space @@ -512,16 +515,11 @@ send_msg: static int shm_netdev_tx(struct sk_buff *skb, struct net_device *shm_netdev) { struct shmdrv_layer *pshm_drv; - unsigned long flags = 0; pshm_drv = netdev_priv(shm_netdev); - spin_lock_irqsave(&pshm_drv->lock, flags); - skb_queue_tail(&pshm_drv->sk_qhead, skb); - spin_unlock_irqrestore(&pshm_drv->lock, flags); - /* Schedule Tx work queue. for deferred processing of skbs*/ if (!work_pending(&pshm_drv->shm_tx_work)) queue_work(pshm_drv->pshm_tx_workqueue, &pshm_drv->shm_tx_work); -- cgit v1.2.3