From fe47f1250805438fa06580c9ce6d37bc4bc595d2 Mon Sep 17 00:00:00 2001 From: Dmitry Tarnyagin Date: Thu, 13 Oct 2011 11:29:23 +0000 Subject: caif-hsi: Fixing a race condition in the caif_hsi code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cfhsi->tx_state was not protected by a spin lock. TX soft-irq could interrupt cfhsi_tx_done_work work leading to inconsistent state of the driver. Signed-off-by: Sjur Brændeland Signed-off-by: David S. Miller --- drivers/net/caif/caif_hsi.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/caif/caif_hsi.c b/drivers/net/caif/caif_hsi.c index 193781389f73..36da27b50114 100644 --- a/drivers/net/caif/caif_hsi.c +++ b/drivers/net/caif/caif_hsi.c @@ -304,14 +304,22 @@ static void cfhsi_tx_done_work(struct work_struct *work) spin_unlock_bh(&cfhsi->lock); /* Create HSI frame. */ - len = cfhsi_tx_frm(desc, cfhsi); - if (!len) { - cfhsi->tx_state = CFHSI_TX_STATE_IDLE; - /* Start inactivity timer. */ - mod_timer(&cfhsi->timer, + do { + len = cfhsi_tx_frm(desc, cfhsi); + if (!len) { + spin_lock_bh(&cfhsi->lock); + if (unlikely(skb_peek(&cfhsi->qhead))) { + spin_unlock_bh(&cfhsi->lock); + continue; + } + cfhsi->tx_state = CFHSI_TX_STATE_IDLE; + /* Start inactivity timer. */ + mod_timer(&cfhsi->timer, jiffies + CFHSI_INACTIVITY_TOUT); - break; - } + spin_unlock_bh(&cfhsi->lock); + goto done; + } + } while (!len); /* Set up new transfer. */ res = cfhsi->dev->cfhsi_tx(cfhsi->tx_buf, len, cfhsi->dev); @@ -320,6 +328,9 @@ static void cfhsi_tx_done_work(struct work_struct *work) __func__, res); } } while (res < 0); + +done: + return; } static void cfhsi_tx_done_cb(struct cfhsi_drv *drv) -- cgit v1.2.1