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 | |
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')
-rw-r--r-- | drivers/net/xen-netback/common.h | 2 | ||||
-rw-r--r-- | drivers/net/xen-netback/interface.c | 30 | ||||
-rw-r--r-- | drivers/net/xen-netback/netback.c | 4 |
3 files changed, 6 insertions, 30 deletions
diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 630a3fcf65bc..0d4a285cbd7e 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h | |||
@@ -226,7 +226,7 @@ int xenvif_map_frontend_rings(struct xenvif *vif, | |||
226 | grant_ref_t rx_ring_ref); | 226 | grant_ref_t rx_ring_ref); |
227 | 227 | ||
228 | /* Check for SKBs from frontend and schedule backend processing */ | 228 | /* Check for SKBs from frontend and schedule backend processing */ |
229 | void xenvif_check_rx_xenvif(struct xenvif *vif); | 229 | void xenvif_napi_schedule_or_enable_events(struct xenvif *vif); |
230 | 230 | ||
231 | /* Prevent the device from generating any further traffic. */ | 231 | /* Prevent the device from generating any further traffic. */ |
232 | void xenvif_carrier_off(struct xenvif *vif); | 232 | void xenvif_carrier_off(struct xenvif *vif); |
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) |
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 64ab1d141f1c..7367208ee8cd 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c | |||
@@ -716,7 +716,7 @@ done: | |||
716 | notify_remote_via_irq(vif->rx_irq); | 716 | notify_remote_via_irq(vif->rx_irq); |
717 | } | 717 | } |
718 | 718 | ||
719 | void xenvif_check_rx_xenvif(struct xenvif *vif) | 719 | void xenvif_napi_schedule_or_enable_events(struct xenvif *vif) |
720 | { | 720 | { |
721 | int more_to_do; | 721 | int more_to_do; |
722 | 722 | ||
@@ -750,7 +750,7 @@ static void tx_credit_callback(unsigned long data) | |||
750 | { | 750 | { |
751 | struct xenvif *vif = (struct xenvif *)data; | 751 | struct xenvif *vif = (struct xenvif *)data; |
752 | tx_add_credit(vif); | 752 | tx_add_credit(vif); |
753 | xenvif_check_rx_xenvif(vif); | 753 | xenvif_napi_schedule_or_enable_events(vif); |
754 | } | 754 | } |
755 | 755 | ||
756 | static void xenvif_tx_err(struct xenvif *vif, | 756 | static void xenvif_tx_err(struct xenvif *vif, |