diff options
author | David Vrabel <david.vrabel@citrix.com> | 2014-05-16 07:26:04 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-05-16 16:27:23 -0400 |
commit | 0d08fceb2e21c30ca3e1e462e678723f806acf18 (patch) | |
tree | 4a890dcf919f80ffb067351bfc45cc63dab35791 /drivers/net/xen-netback/interface.c | |
parent | 202630b445d2618d94e4f099567fcee5618dab27 (diff) |
xen-netback: fix race between napi_complete() and interrupt handler
When the NAPI budget was not all used, xenvif_poll() would call
napi_complete() /after/ enabling the interrupt. This resulted in a
race between the napi_complete() and the napi_schedule() in the
interrupt handler. The use of local_irq_save/restore() avoided by
race iff the handler is running on the same CPU but not if it was
running on a different CPU.
Fix this properly by calling napi_complete() before reenabling
interrupts (in the xenvif_napi_schedule_or_enable_irq() call).
Signed-off-by: David Vrabel <david.vrabel@citrix.com>
Acked-by: Wei Liu <wei.liu2@citrix.com>
Acked-by: Ian Campbell <ian.campbell@citrix.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/xen-netback/interface.c')
-rw-r--r-- | drivers/net/xen-netback/interface.c | 30 |
1 files changed, 3 insertions, 27 deletions
diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index ef05c5c49d41..20e9defa1060 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c | |||
@@ -75,32 +75,8 @@ static int xenvif_poll(struct napi_struct *napi, int budget) | |||
75 | work_done = xenvif_tx_action(vif, budget); | 75 | work_done = xenvif_tx_action(vif, budget); |
76 | 76 | ||
77 | if (work_done < budget) { | 77 | if (work_done < budget) { |
78 | int more_to_do = 0; | 78 | napi_complete(napi); |
79 | unsigned long flags; | 79 | xenvif_napi_schedule_or_enable_events(vif); |
80 | |||
81 | /* It is necessary to disable IRQ before calling | ||
82 | * RING_HAS_UNCONSUMED_REQUESTS. Otherwise we might | ||
83 | * lose event from the frontend. | ||
84 | * | ||
85 | * Consider: | ||
86 | * RING_HAS_UNCONSUMED_REQUESTS | ||
87 | * <frontend generates event to trigger napi_schedule> | ||
88 | * __napi_complete | ||
89 | * | ||
90 | * This handler is still in scheduled state so the | ||
91 | * event has no effect at all. After __napi_complete | ||
92 | * this handler is descheduled and cannot get | ||
93 | * scheduled again. We lose event in this case and the ring | ||
94 | * will be completely stalled. | ||
95 | */ | ||
96 | |||
97 | local_irq_save(flags); | ||
98 | |||
99 | RING_FINAL_CHECK_FOR_REQUESTS(&vif->tx, more_to_do); | ||
100 | if (!more_to_do) | ||
101 | __napi_complete(napi); | ||
102 | |||
103 | local_irq_restore(flags); | ||
104 | } | 80 | } |
105 | 81 | ||
106 | return work_done; | 82 | return work_done; |
@@ -194,7 +170,7 @@ static void xenvif_up(struct xenvif *vif) | |||
194 | enable_irq(vif->tx_irq); | 170 | enable_irq(vif->tx_irq); |
195 | if (vif->tx_irq != vif->rx_irq) | 171 | if (vif->tx_irq != vif->rx_irq) |
196 | enable_irq(vif->rx_irq); | 172 | enable_irq(vif->rx_irq); |
197 | xenvif_check_rx_xenvif(vif); | 173 | xenvif_napi_schedule_or_enable_events(vif); |
198 | } | 174 | } |
199 | 175 | ||
200 | static void xenvif_down(struct xenvif *vif) | 176 | static void xenvif_down(struct xenvif *vif) |