aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorVeaceslav Falico <vfalico@redhat.com>2013-03-11 00:21:48 +0000
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-03-28 12:11:52 -0700
commitb52f06719c794cc8df5ea871a4fd498ff252210a (patch)
treeb11aa21e96450bafdd90bfa0fcddb28de5911e87 /drivers
parent7436bcf6158d70346928b9b26568f5bb3213a36f (diff)
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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/netconsole.c20
1 files changed, 9 insertions, 11 deletions
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 63ffbdfe36c..dfffe8d8d69 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -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);