netconsole: don't call __netpoll_cleanup() while atomic
[ Upstream commit 3f315bef23075ea8a98a6fe4221a83b83456d970 ] __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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
7436bcf615
commit
b52f06719c
|
@ -626,6 +626,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) {
|
||||
|
@ -637,21 +638,18 @@ static int netconsole_netdev_event(struct notifier_block *this,
|
|||
case NETDEV_JOIN:
|
||||
case NETDEV_UNREGISTER:
|
||||
/*
|
||||
* we might sleep in __netpoll_cleanup()
|
||||
* rtnl_lock already held
|
||||
*/
|
||||
if (nt->np.dev) {
|
||||
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;
|
||||
}
|
||||
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