diff options
author | Sowmini Varadhan <sowmini.varadhan@oracle.com> | 2014-08-12 10:33:10 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-08-13 23:04:46 -0400 |
commit | adddc32d6fde82156c779997f928865100542e55 (patch) | |
tree | b7605e8c600203c43768f48256c4382f30e5c390 /drivers/net | |
parent | 1f6394e382f137f07136182c591ca8a7eeba6a06 (diff) |
sunvnet: Do not spin in an infinite loop when vio_ldc_send() returns EAGAIN
ldc_rx -> vnet_rx -> .. -> vnet_walk_rx->vnet_send_ack should not
spin into an infinite loop waiting EAGAIN to lift.
The sender could have sent us a burst, and gone to lunch without
doing any more ldc_read()'s. That should not cause the receiver to
loop infinitely till soft-lockup kicks in.
Similarly __vnet_tx_trigger should only loop on EAGAIN a finite
number of times. The caller (vnet_start_xmit()) already has code
to reset the dring state and bail on errors from __vnet_tx_trigger
Signed-off-by: Sowmini Varadhan <sowmini.varadhan@oracle.com>
Acked-by: Raghuram Kothakota <raghuram.kothakota@oracle.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/ethernet/sun/sunvnet.c | 16 |
1 files changed, 16 insertions, 0 deletions
diff --git a/drivers/net/ethernet/sun/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c index 238434dcfe02..a5871791e452 100644 --- a/drivers/net/ethernet/sun/sunvnet.c +++ b/drivers/net/ethernet/sun/sunvnet.c | |||
@@ -32,6 +32,11 @@ MODULE_DESCRIPTION("Sun LDOM virtual network driver"); | |||
32 | MODULE_LICENSE("GPL"); | 32 | MODULE_LICENSE("GPL"); |
33 | MODULE_VERSION(DRV_MODULE_VERSION); | 33 | MODULE_VERSION(DRV_MODULE_VERSION); |
34 | 34 | ||
35 | /* Heuristic for the number of times to exponentially backoff and | ||
36 | * retry sending an LDC trigger when EAGAIN is encountered | ||
37 | */ | ||
38 | #define VNET_MAX_RETRIES 10 | ||
39 | |||
35 | /* Ordered from largest major to lowest */ | 40 | /* Ordered from largest major to lowest */ |
36 | static struct vio_version vnet_versions[] = { | 41 | static struct vio_version vnet_versions[] = { |
37 | { .major = 1, .minor = 0 }, | 42 | { .major = 1, .minor = 0 }, |
@@ -260,6 +265,7 @@ static int vnet_send_ack(struct vnet_port *port, struct vio_dring_state *dr, | |||
260 | .state = vio_dring_state, | 265 | .state = vio_dring_state, |
261 | }; | 266 | }; |
262 | int err, delay; | 267 | int err, delay; |
268 | int retries = 0; | ||
263 | 269 | ||
264 | hdr.seq = dr->snd_nxt; | 270 | hdr.seq = dr->snd_nxt; |
265 | delay = 1; | 271 | delay = 1; |
@@ -272,6 +278,13 @@ static int vnet_send_ack(struct vnet_port *port, struct vio_dring_state *dr, | |||
272 | udelay(delay); | 278 | udelay(delay); |
273 | if ((delay <<= 1) > 128) | 279 | if ((delay <<= 1) > 128) |
274 | delay = 128; | 280 | delay = 128; |
281 | if (retries++ > VNET_MAX_RETRIES) { | ||
282 | pr_info("ECONNRESET %x:%x:%x:%x:%x:%x\n", | ||
283 | port->raddr[0], port->raddr[1], | ||
284 | port->raddr[2], port->raddr[3], | ||
285 | port->raddr[4], port->raddr[5]); | ||
286 | err = -ECONNRESET; | ||
287 | } | ||
275 | } while (err == -EAGAIN); | 288 | } while (err == -EAGAIN); |
276 | 289 | ||
277 | return err; | 290 | return err; |
@@ -593,6 +606,7 @@ static int __vnet_tx_trigger(struct vnet_port *port) | |||
593 | .end_idx = (u32) -1, | 606 | .end_idx = (u32) -1, |
594 | }; | 607 | }; |
595 | int err, delay; | 608 | int err, delay; |
609 | int retries = 0; | ||
596 | 610 | ||
597 | hdr.seq = dr->snd_nxt; | 611 | hdr.seq = dr->snd_nxt; |
598 | delay = 1; | 612 | delay = 1; |
@@ -605,6 +619,8 @@ static int __vnet_tx_trigger(struct vnet_port *port) | |||
605 | udelay(delay); | 619 | udelay(delay); |
606 | if ((delay <<= 1) > 128) | 620 | if ((delay <<= 1) > 128) |
607 | delay = 128; | 621 | delay = 128; |
622 | if (retries++ > VNET_MAX_RETRIES) | ||
623 | break; | ||
608 | } while (err == -EAGAIN); | 624 | } while (err == -EAGAIN); |
609 | 625 | ||
610 | return err; | 626 | return err; |