aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging
diff options
context:
space:
mode:
authorSven Eckelmann <sven.eckelmann@gmx.de>2010-11-22 06:34:50 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2010-11-29 13:53:14 -0500
commit9ee898739b7e4d292abed911008b3f91b442118a (patch)
treebcc05c7f9cf249b2391989a222e5e5f268886b4d /drivers/staging
parent6df78338e7af7960b67fa00aa2a5c63986a23d3c (diff)
Staging: batman-adv: Don't remove interface with spinlock held
We call a lot of the netdevice code when holding if_list_lock which will spin the whole time. This is not necessary because we only want to protect the access to the list to be serialized. An extra queue can be used which hold all interfaces which should be removed and then use that queue without any locks for netdevice cleanup. We create a "scheduling while atomic" Oops when calling different netdevice related functions inside a spinlock protected area on a preemtible kernel. Reported-by: Rafal Lesniak <lesniak@eresi-project.org> Signed-off-by: Sven Eckelmann <sven.eckelmann@gmx.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging')
-rw-r--r--drivers/staging/batman-adv/hard-interface.c19
1 files changed, 13 insertions, 6 deletions
diff --git a/drivers/staging/batman-adv/hard-interface.c b/drivers/staging/batman-adv/hard-interface.c
index b68a7e5173be..d85de82f941a 100644
--- a/drivers/staging/batman-adv/hard-interface.c
+++ b/drivers/staging/batman-adv/hard-interface.c
@@ -463,9 +463,6 @@ static void hardif_remove_interface(struct batman_if *batman_if)
463 return; 463 return;
464 464
465 batman_if->if_status = IF_TO_BE_REMOVED; 465 batman_if->if_status = IF_TO_BE_REMOVED;
466
467 /* caller must take if_list_lock */
468 list_del_rcu(&batman_if->list);
469 synchronize_rcu(); 466 synchronize_rcu();
470 sysfs_del_hardif(&batman_if->hardif_obj); 467 sysfs_del_hardif(&batman_if->hardif_obj);
471 hardif_put(batman_if); 468 hardif_put(batman_if);
@@ -474,13 +471,21 @@ static void hardif_remove_interface(struct batman_if *batman_if)
474void hardif_remove_interfaces(void) 471void hardif_remove_interfaces(void)
475{ 472{
476 struct batman_if *batman_if, *batman_if_tmp; 473 struct batman_if *batman_if, *batman_if_tmp;
474 struct list_head if_queue;
475
476 INIT_LIST_HEAD(&if_queue);
477 477
478 rtnl_lock();
479 spin_lock(&if_list_lock); 478 spin_lock(&if_list_lock);
480 list_for_each_entry_safe(batman_if, batman_if_tmp, &if_list, list) { 479 list_for_each_entry_safe(batman_if, batman_if_tmp, &if_list, list) {
481 hardif_remove_interface(batman_if); 480 list_del_rcu(&batman_if->list);
481 list_add_tail(&batman_if->list, &if_queue);
482 } 482 }
483 spin_unlock(&if_list_lock); 483 spin_unlock(&if_list_lock);
484
485 rtnl_lock();
486 list_for_each_entry_safe(batman_if, batman_if_tmp, &if_queue, list) {
487 hardif_remove_interface(batman_if);
488 }
484 rtnl_unlock(); 489 rtnl_unlock();
485} 490}
486 491
@@ -507,8 +512,10 @@ static int hard_if_event(struct notifier_block *this,
507 break; 512 break;
508 case NETDEV_UNREGISTER: 513 case NETDEV_UNREGISTER:
509 spin_lock(&if_list_lock); 514 spin_lock(&if_list_lock);
510 hardif_remove_interface(batman_if); 515 list_del_rcu(&batman_if->list);
511 spin_unlock(&if_list_lock); 516 spin_unlock(&if_list_lock);
517
518 hardif_remove_interface(batman_if);
512 break; 519 break;
513 case NETDEV_CHANGEMTU: 520 case NETDEV_CHANGEMTU:
514 if (batman_if->soft_iface) 521 if (batman_if->soft_iface)