forked from Minki/linux
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 <vfalico@redhat.com> Acked-by: Neil Horman <nhorman@tuxdriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
3da889b616
commit
3f315bef23
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user