Author: marek Date: 2010-08-29 02:02:13 +0200 (Sun, 29 Aug 2010) New Revision: 1779
Modified: trunk/batman-adv/bat_sysfs.c trunk/batman-adv/hard-interface.c trunk/batman-adv/soft-interface.c Log: batman-adv: Don't call unregister_netdev with locked rtnl semaphore
We currently try to call unregister_netdev when we can destroy a softif after all corresponding hard-interfaces announced that they will be removed.
This will be done when we receive a hard_if_event which already takes the rtnl semaphore and thus we try to get it again in unregister_netdev. This results in a deadlock. This call to unregister_netdev cannot easily replaced by unregister_netdevice, because other parts of the batman-adv module still call that code indirectly without holding the rtnl semaphore.
(needs rtln_unlocked) unregister_netdev ^ | softif_destroy ^ | hardif_disable_interface ^ ^ / | store_mesh_iface hardif_remove_interface (rtln_unlocked) ^ ^ | \ hardif_remove_interfaces hard_if_event ^ (rtln_locked) | batman_exit (rtln_unlocked)
A consistent workaround is to change store_mesh_iface and hardif_remove_interfaces to call rtnl_lock before they call the mentioned child function, release the semaphore afterwards and change unregister_netdev in softif_destroy to unregister_netdevice.
Reported-by: Kazuki Shimada zukky@bb.banban.jp Signed-off-by: Sven Eckelmann sven.eckelmann@gmx.de
Modified: trunk/batman-adv/bat_sysfs.c =================================================================== --- trunk/batman-adv/bat_sysfs.c 2010-08-23 17:45:22 UTC (rev 1778) +++ trunk/batman-adv/bat_sysfs.c 2010-08-29 00:02:13 UTC (rev 1779) @@ -492,13 +492,18 @@ return count;
if (status_tmp == IF_NOT_IN_USE) { + rtnl_lock(); hardif_disable_interface(batman_if); + rtnl_unlock(); return count; }
/* if the interface already is in use */ - if (batman_if->if_status != IF_NOT_IN_USE) + if (batman_if->if_status != IF_NOT_IN_USE) { + rtnl_lock(); hardif_disable_interface(batman_if); + rtnl_unlock(); + }
return hardif_enable_interface(batman_if, buff); }
Modified: trunk/batman-adv/hard-interface.c =================================================================== --- trunk/batman-adv/hard-interface.c 2010-08-23 17:45:22 UTC (rev 1778) +++ trunk/batman-adv/hard-interface.c 2010-08-29 00:02:13 UTC (rev 1779) @@ -441,8 +441,11 @@ { struct batman_if *batman_if, *batman_if_tmp;
- list_for_each_entry_safe(batman_if, batman_if_tmp, &if_list, list) + list_for_each_entry_safe(batman_if, batman_if_tmp, &if_list, list) { + rtnl_lock(); hardif_remove_interface(batman_if); + rtnl_unlock(); + } }
static int hard_if_event(struct notifier_block *this,
Modified: trunk/batman-adv/soft-interface.c =================================================================== --- trunk/batman-adv/soft-interface.c 2010-08-23 17:45:22 UTC (rev 1778) +++ trunk/batman-adv/soft-interface.c 2010-08-29 00:02:13 UTC (rev 1779) @@ -351,7 +351,7 @@ debugfs_del_meshif(soft_iface); sysfs_del_meshif(soft_iface); mesh_free(soft_iface); - unregister_netdev(soft_iface); + unregister_netdevice(soft_iface); }
/* ethtool */