Patch "can: dev: fix deadlock reported after bus-off" has been added to the 4.4-stable tree
Subsystems (2)
This is a note to let you know that I've just added the patch titled
can: dev: fix deadlock reported after bus-off
to the 4.4-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
can-dev-fix-deadlock-reported-after-bus-off.patch
and it can be found in the queue-4.4 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
9abefcb1aaa58b9d5aa40a8bb12c87d02415e4c8Mon Sep 17 00:00:00 2001
From: Sergei Miroshnichenko <[email protected]>
Date: Wed, 7 Sep 2016 16:51:12 +0300
Subject: can: dev: fix deadlock reported after bus-off
From: Sergei Miroshnichenko <[email protected]>
commit 9abefcb1aaa58b9d5aa40a8bb12c87d02415e4c8 upstream.
A timer was used to restart after the bus-off state, leading to a relatively large can_restart() executed in an interrupt context, which in turn sets up pinctrl. When this happens during system boot, there is a high probability of grabbing the pinctrl_list_mutex, which is locked already by the probe() of other device, making the kernel suspect a deadlock condition [1].
To resolve this issue, the restart_timer is replaced by a delayed work.
[1] https://github.com/victronenergy/venus/issues/24
--- drivers/net/can/dev.c | 27 +++++++++++++++++---------- include/linux/can/dev.h | 3 ++- 2 files changed, 19 insertions(+), 11 deletions(-)
drivers/net/can/dev.c +17 -10
@@ -21,6 +21,7 @@#include <linux/slab.h> #include <linux/netdevice.h> #include <linux/if_arp.h> +#include <linux/workqueue.h> #include <linux/can.h> #include <linux/can/dev.h> #include <linux/can/skb.h>
@@ -471,9 +472,8 @@ EXPORT_SYMBOL_GPL(can_free_echo_skb);/* * CAN device restart for bus-off recovery */ -static void can_restart (unsigned long data) +static void can_restart (struct net_device *dev) { -struct net_device *dev = (struct net_device *)data;struct can_priv *priv =netdev_priv (dev);struct net_device_stats *stats = &dev->stats;struct sk_buff *skb;
@@ -513,6 +513,14 @@ restart:netdev_err (dev,"Error %d during restart" , err); } +static void can_restart_work (struct work_struct *work) +{ +struct delayed_work *dwork =to_delayed_work (work); + struct can_priv *priv = container_of(dwork, struct can_priv, restart_work); + +can_restart (priv->dev); +} +int can_restart_now (struct net_device *dev) {struct can_priv *priv =netdev_priv (dev);
@@ -526,8 +534,8 @@ int can_restart_now(struct net_device *dif (priv->state !=CAN_STATE_BUS_OFF )return -EBUSY ; -/* Runs as soon as possible in the timer context */ -mod_timer (&priv->restart_timer, jiffies); +cancel_delayed_work_sync (&priv->restart_work); +can_restart (dev);return 0 ; }
@@ -548,8 +556,8 @@ void can_bus_off(struct net_device *dev)netif_carrier_off (dev);if (priv->restart_ms) -mod_timer (&priv->restart_timer, - jiffies + (priv->restart_ms *HZ ) /1000 ); +schedule_delayed_work (&priv->restart_work, +msecs_to_jiffies (priv->restart_ms)); }EXPORT_SYMBOL_GPL (can_bus_off);
@@ -658,6 +666,7 @@ struct net_device *alloc_candev(int sizereturn NULL ; priv =netdev_priv (dev); + priv->dev = dev;if (echo_skb_max) { priv->echo_skb_max = echo_skb_max;
@@ -667,7 +676,7 @@ struct net_device *alloc_candev(int size priv->state =CAN_STATE_STOPPED ; -init_timer (&priv->restart_timer); +INIT_DELAYED_WORK (&priv->restart_work, can_restart_work);return dev; }
@@ -748,8 +757,6 @@ int open_candev(struct net_device *dev)if (!netif_carrier_ok (dev))netif_carrier_on (dev); -setup_timer (&priv->restart_timer, can_restart, (unsigned long )dev); -return 0 ; }EXPORT_SYMBOL_GPL (open_candev);
@@ -764,7 +771,7 @@ void close_candev(struct net_device *dev {struct can_priv *priv =netdev_priv (dev); -del_timer_sync (&priv->restart_timer); +cancel_delayed_work_sync (&priv->restart_work);can_flush_echo_skb (dev); }EXPORT_SYMBOL_GPL (close_candev);
include/linux/can/dev.h +2 -1
@@ -32,6 +32,7 @@ enum can_mode {* CAN common private data */ struct can_priv { +struct net_device *dev;struct can_device_stats can_stats;struct can_bittiming bittiming, data_bittiming;
@@ -47,7 +48,7 @@ struct can_priv {u32 ctrlmode_static;/* static enabled options for driver/hardware */ int restart_ms; -struct timer_list restart_timer; +struct delayed_work restart_work;int (*do_set_bittiming)(struct net_device *dev);int (*do_set_data_bittiming)(struct net_device *dev);
Patches currently in stable-queue which might be from [email protected] are
queue-4.4/can-dev-fix-deadlock-reported-after-bus-off.patch