netconsole: fix deadlock when removing net driver that netconsole is using (v2)

A deadlock was reported to me recently that occured when netconsole was being
used in a virtual guest. If the virtio_net driver was removed while netconsole
was setup to use an interface that was driven by that driver, the guest
deadlocked. No backtrace was provided because netconsole was the only console
configured, but it became clear pretty quickly what the problem was. In
netconsole_netdev_event, if we get an unregister event, we call
__netpoll_cleanup with the target_list_lock held and irqs disabled.
__netpoll_cleanup can, if pending netpoll packets are waiting call
cancel_delayed_work_sync, which is a sleeping path. the might_sleep call in
that path gets triggered, causing a console warning to be issued. The
netconsole write handler of course tries to take the target_list_lock again,
which we already hold, causing deadlock.

The fix is pretty striaghtforward. Simply drop the target_list_lock and
re-enable irqs prior to calling __netpoll_cleanup, the re-acquire the lock, and
restart the loop. Confirmed by myself to fix the problem reported.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
CC: "David S. Miller" <davem@davemloft.net>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by Neil Horman and committed by David S. Miller 13f172ff 1ed3aad1

+8
+8
drivers/net/netconsole.c
··· 671 goto done; 672 673 spin_lock_irqsave(&target_list_lock, flags); 674 list_for_each_entry(nt, &target_list, list) { 675 netconsole_target_get(nt); 676 if (nt->np.dev == dev) { ··· 684 * rtnl_lock already held 685 */ 686 if (nt->np.dev) { 687 __netpoll_cleanup(&nt->np); 688 dev_put(nt->np.dev); 689 nt->np.dev = NULL; 690 } 691 /* Fall through */ 692 case NETDEV_GOING_DOWN:
··· 671 goto done; 672 673 spin_lock_irqsave(&target_list_lock, flags); 674 + restart: 675 list_for_each_entry(nt, &target_list, list) { 676 netconsole_target_get(nt); 677 if (nt->np.dev == dev) { ··· 683 * rtnl_lock already held 684 */ 685 if (nt->np.dev) { 686 + spin_unlock_irqrestore( 687 + &target_list_lock, 688 + flags); 689 __netpoll_cleanup(&nt->np); 690 + spin_lock_irqsave(&target_list_lock, 691 + flags); 692 dev_put(nt->np.dev); 693 nt->np.dev = NULL; 694 + netconsole_target_put(nt); 695 + goto restart; 696 } 697 /* Fall through */ 698 case NETDEV_GOING_DOWN: