diff options
author | Simon Wunderlich <simon.wunderlich@s2003.tu-chemnitz.de> | 2013-01-11 04:19:51 -0500 |
---|---|---|
committer | Antonio Quartulli <ordex@autistici.org> | 2013-01-19 08:18:12 -0500 |
commit | 5bc44dc8458cbac08c664f2f337326bf87cc924b (patch) | |
tree | 05828c0b6a6f00138a539c0ce39e3ea0b109dbce /net/batman-adv/soft-interface.c | |
parent | e76e4320a26ba6301dfd3e9a28a1e3faccd302ab (diff) |
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 3d6816667bfc..c9962fee44b1 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) | |||
449 | memset(priv, 0, sizeof(*priv)); | 449 | memset(priv, 0, sizeof(*priv)); |
450 | } | 450 | } |
451 | 451 | ||
452 | /** | ||
453 | * batadv_softif_destroy_finish - cleans up the remains of a softif | ||
454 | * @work: work queue item | ||
455 | * | ||
456 | * Free the parts of the soft interface which can not be removed under | ||
457 | * rtnl lock (to prevent deadlock situations). | ||
458 | */ | ||
459 | static void batadv_softif_destroy_finish(struct work_struct *work) | ||
460 | { | ||
461 | struct batadv_priv *bat_priv; | ||
462 | struct net_device *soft_iface; | ||
463 | |||
464 | bat_priv = container_of(work, struct batadv_priv, | ||
465 | cleanup_work); | ||
466 | soft_iface = bat_priv->soft_iface; | ||
467 | |||
468 | batadv_debugfs_del_meshif(soft_iface); | ||
469 | batadv_sysfs_del_meshif(soft_iface); | ||
470 | |||
471 | rtnl_lock(); | ||
472 | unregister_netdevice(soft_iface); | ||
473 | rtnl_unlock(); | ||
474 | } | ||
475 | |||
452 | struct net_device *batadv_softif_create(const char *name) | 476 | struct net_device *batadv_softif_create(const char *name) |
453 | { | 477 | { |
454 | struct net_device *soft_iface; | 478 | struct net_device *soft_iface; |
@@ -463,6 +487,8 @@ struct net_device *batadv_softif_create(const char *name) | |||
463 | goto out; | 487 | goto out; |
464 | 488 | ||
465 | bat_priv = netdev_priv(soft_iface); | 489 | bat_priv = netdev_priv(soft_iface); |
490 | bat_priv->soft_iface = soft_iface; | ||
491 | INIT_WORK(&bat_priv->cleanup_work, batadv_softif_destroy_finish); | ||
466 | 492 | ||
467 | /* batadv_interface_stats() needs to be available as soon as | 493 | /* batadv_interface_stats() needs to be available as soon as |
468 | * register_netdevice() has been called | 494 | * register_netdevice() has been called |
@@ -551,10 +577,10 @@ out: | |||
551 | 577 | ||
552 | void batadv_softif_destroy(struct net_device *soft_iface) | 578 | void batadv_softif_destroy(struct net_device *soft_iface) |
553 | { | 579 | { |
554 | batadv_debugfs_del_meshif(soft_iface); | 580 | struct batadv_priv *bat_priv = netdev_priv(soft_iface); |
555 | batadv_sysfs_del_meshif(soft_iface); | 581 | |
556 | batadv_mesh_free(soft_iface); | 582 | batadv_mesh_free(soft_iface); |
557 | unregister_netdevice(soft_iface); | 583 | queue_work(batadv_event_workqueue, &bat_priv->cleanup_work); |
558 | } | 584 | } |
559 | 585 | ||
560 | int batadv_softif_is_valid(const struct net_device *net_dev) | 586 | int batadv_softif_is_valid(const struct net_device *net_dev) |