diff options
author | Simon Wunderlich <simon.wunderlich@s2003.tu-chemnitz.de> | 2013-01-11 10:19:51 +0100 |
---|---|---|
committer | Antonio Quartulli <ordex@autistici.org> | 2013-01-19 21:18:12 +0800 |
commit | 5bc44dc8458cbac08c664f2f337326bf87cc924b (patch) | |
tree | 05828c0b6a6f00138a539c0ce39e3ea0b109dbce /net/batman-adv/soft-interface.c | |
parent | e76e4320a26ba6301dfd3e9a28a1e3faccd302ab (diff) | |
download | op-kernel-dev-5bc44dc8458cbac08c664f2f337326bf87cc924b.zip op-kernel-dev-5bc44dc8458cbac08c664f2f337326bf87cc924b.tar.gz |
batman-adv: postpone sysfs removal when unregistering
When processing the unregister notify for a hard interface, removing
the sysfs files may lead to a circular deadlock (rtnl mutex <->
s_active).
To overcome this problem, postpone the sysfs removal in a worker.
Reported-by: Sasha Levin <sasha.levin@oracle.com>
Reported-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
Signed-off-by: Antonio Quartulli <ordex@autistici.org>
Diffstat (limited to 'net/batman-adv/soft-interface.c')
-rw-r--r-- | net/batman-adv/soft-interface.c | 32 |
1 files changed, 29 insertions, 3 deletions
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index 3d68166..c9962fe 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -449,6 +449,30 @@ static void batadv_interface_setup(struct net_device *dev) memset(priv, 0, sizeof(*priv)); } +/** + * batadv_softif_destroy_finish - cleans up the remains of a softif + * @work: work queue item + * + * Free the parts of the soft interface which can not be removed under + * rtnl lock (to prevent deadlock situations). + */ +static void batadv_softif_destroy_finish(struct work_struct *work) +{ + struct batadv_priv *bat_priv; + struct net_device *soft_iface; + + bat_priv = container_of(work, struct batadv_priv, + cleanup_work); + soft_iface = bat_priv->soft_iface; + + batadv_debugfs_del_meshif(soft_iface); + batadv_sysfs_del_meshif(soft_iface); + + rtnl_lock(); + unregister_netdevice(soft_iface); + rtnl_unlock(); +} + struct net_device *batadv_softif_create(const char *name) { struct net_device *soft_iface; @@ -463,6 +487,8 @@ struct net_device *batadv_softif_create(const char *name) goto out; bat_priv = netdev_priv(soft_iface); + bat_priv->soft_iface = soft_iface; + INIT_WORK(&bat_priv->cleanup_work, batadv_softif_destroy_finish); /* batadv_interface_stats() needs to be available as soon as * register_netdevice() has been called @@ -551,10 +577,10 @@ out: void batadv_softif_destroy(struct net_device *soft_iface) { - batadv_debugfs_del_meshif(soft_iface); - batadv_sysfs_del_meshif(soft_iface); + struct batadv_priv *bat_priv = netdev_priv(soft_iface); + batadv_mesh_free(soft_iface); - unregister_netdevice(soft_iface); + queue_work(batadv_event_workqueue, &bat_priv->cleanup_work); } int batadv_softif_is_valid(const struct net_device *net_dev) |