mac802154: tx: fix synced xmit deadlock
authorAlexander Aring <alex.aring@gmail.com>
Wed, 9 Dec 2015 22:23:56 +0000 (23:23 +0100)
committerMarcel Holtmann <marcel@holtmann.org>
Thu, 10 Dec 2015 18:17:11 +0000 (19:17 +0100)
This patch reverts 6001d52 ("mac802154: tx: don't allow if down while
sync tx"). This has side effects with stop callback which flush the
transmit workqueue. The stop callback will wait until the workqueue is
flushed and holding the rtnl lock. That means it can happen that the stop
callback waits forever because it try to lock the rtnl mutex which is
already hold by stop callback.

Cc: Michael Hennerich <michael.hennerich@analog.com>
Signed-off-by: Alexander Aring <alex.aring@gmail.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
net/mac802154/driver-ops.h
net/mac802154/tx.c

index 0550f3365e3307325fa10bfc3f4e13b3aa4bd5cd..fd9daf2ecec97a31c375b491739bd241b109b1c5 100644 (file)
@@ -18,9 +18,6 @@ drv_xmit_async(struct ieee802154_local *local, struct sk_buff *skb)
 static inline int
 drv_xmit_sync(struct ieee802154_local *local, struct sk_buff *skb)
 {
-       /* don't allow other operations while sync xmit */
-       ASSERT_RTNL();
-
        might_sleep();
 
        return local->ops->xmit_sync(&local->hw, skb);
index 3827f359b336de356695635401820fc094344faf..7e253455f9dd0ed995186ff3482b39e8679aa75a 100644 (file)
@@ -38,12 +38,6 @@ void ieee802154_xmit_worker(struct work_struct *work)
        struct net_device *dev = skb->dev;
        int res;
 
-       rtnl_lock();
-
-       /* check if ifdown occurred while schedule */
-       if (!netif_running(dev))
-               goto err_tx;
-
        res = drv_xmit_sync(local, skb);
        if (res)
                goto err_tx;
@@ -53,14 +47,11 @@ void ieee802154_xmit_worker(struct work_struct *work)
        dev->stats.tx_packets++;
        dev->stats.tx_bytes += skb->len;
 
-       rtnl_unlock();
-
        return;
 
 err_tx:
        /* Restart the netif queue on each sub_if_data object. */
        ieee802154_wake_queue(&local->hw);
-       rtnl_unlock();
        kfree_skb(skb);
        netdev_dbg(dev, "transmission failed\n");
 }