| From 740f825d8a83fcf430093e6ee7606f4380c66a3c Mon Sep 17 00:00:00 2001 |
| From: David Vrabel <david.vrabel@citrix.com> |
| Date: Thu, 14 Feb 2013 03:18:58 +0000 |
| Subject: xen-netback: cancel the credit timer when taking the vif down |
| |
| |
| From: David Vrabel <david.vrabel@citrix.com> |
| |
| [ Upstream commit 3e55f8b306cf305832a4ac78aa82e1b40e818ece ] |
| |
| If the credit timer is left armed after calling |
| xen_netbk_remove_xenvif(), then it may fire and attempt to schedule |
| the vif which will then oops as vif->netbk == NULL. |
| |
| This may happen both in the fatal error path and during normal |
| disconnection from the front end. |
| |
| The sequencing during shutdown is critical to ensure that: a) |
| vif->netbk doesn't become unexpectedly NULL; and b) the net device/vif |
| is not freed. |
| |
| 1. Mark as unschedulable (netif_carrier_off()). |
| 2. Synchronously cancel the timer. |
| 3. Remove the vif from the schedule list. |
| 4. Remove it from it netback thread group. |
| 5. Wait for vif->refcnt to become 0. |
| |
| Signed-off-by: David Vrabel <david.vrabel@citrix.com> |
| Acked-by: Ian Campbell <ian.campbell@citrix.com> |
| Reported-by: Christopher S. Aker <caker@theshore.net> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/net/xen-netback/interface.c | 3 +-- |
| 1 file changed, 1 insertion(+), 2 deletions(-) |
| |
| --- a/drivers/net/xen-netback/interface.c |
| +++ b/drivers/net/xen-netback/interface.c |
| @@ -132,6 +132,7 @@ static void xenvif_up(struct xenvif *vif |
| static void xenvif_down(struct xenvif *vif) |
| { |
| disable_irq(vif->irq); |
| + del_timer_sync(&vif->credit_timeout); |
| xen_netbk_deschedule_xenvif(vif); |
| xen_netbk_remove_xenvif(vif); |
| } |
| @@ -363,8 +364,6 @@ void xenvif_disconnect(struct xenvif *vi |
| atomic_dec(&vif->refcnt); |
| wait_event(vif->waiting_to_free, atomic_read(&vif->refcnt) == 0); |
| |
| - del_timer_sync(&vif->credit_timeout); |
| - |
| if (vif->irq) |
| unbind_from_irqhandler(vif->irq, vif); |
| |