netconsole: don't call __netpoll_cleanup() while atomic

__netpoll_cleanup() is called in netconsole_netdev_event() while holding a
spinlock. Release/acquire the spinlock before/after it and restart the
loop. Also, disable the netconsole completely, because we won't have chance
after the restart of the loop, and might end up in a situation where
nt->enabled == 1 and nt->np.dev == NULL.

Signed-off-by: Veaceslav Falico <[email protected]>
Acked-by: Neil Horman <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
This commit is contained in:
Veaceslav Falico authored and David S. Miller committed 2013-03-12 06:58:55 -04:00
1 parent 3da889b616
commit 3f315bef23
1 file changed
+9 -6
+9 -6
View File
@@ -666,6 +666,7 @@ static int netconsole_netdev_event(struct notifier_block *this,
goto done;
spin_lock_irqsave(&target_list_lock, flags);
restart:
list_for_each_entry(nt, &target_list, list) {
netconsole_target_get(nt);
if (nt->np.dev == dev) {
@@ -678,15 +679,17 @@ static int netconsole_netdev_event(struct notifier_block *this,
case NETDEV_UNREGISTER:
/*
* rtnl_lock already held
* we might sleep in __netpoll_cleanup()
*/
if (nt->np.dev) {
__netpoll_cleanup(&nt->np);
dev_put(nt->np.dev);
nt->np.dev = NULL;
}
spin_unlock_irqrestore(&target_list_lock, flags);
__netpoll_cleanup(&nt->np);
spin_lock_irqsave(&target_list_lock, flags);
dev_put(nt->np.dev);
nt->np.dev = NULL;
nt->enabled = 0;
stopped = true;
break;
netconsole_target_put(nt);
goto restart;
}
}
netconsole_target_put(nt);