sunvnet: Do not spin in an infinite loop when vio_ldc_send() returns EAGAIN
authorSowmini Varadhan <sowmini.varadhan@oracle.com>
Tue, 12 Aug 2014 14:33:10 +0000 (10:33 -0400)
committerDavid S. Miller <davem@davemloft.net>
Thu, 14 Aug 2014 03:04:46 +0000 (20:04 -0700)
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>
drivers/net/ethernet/sun/sunvnet.c

index 238434dcfe02dc65aa86c0edfe071b8f93ac7c2c..a5871791e45243e389a9a84529c72b47ad0fec50 100644 (file)
@@ -32,6 +32,11 @@ MODULE_DESCRIPTION("Sun LDOM virtual network driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_MODULE_VERSION);
 
+/* Heuristic for the number of times to exponentially backoff and
+ * retry sending an LDC trigger when EAGAIN is encountered
+ */
+#define        VNET_MAX_RETRIES        10
+
 /* Ordered from largest major to lowest */
 static struct vio_version vnet_versions[] = {
        { .major = 1, .minor = 0 },
@@ -260,6 +265,7 @@ static int vnet_send_ack(struct vnet_port *port, struct vio_dring_state *dr,
                .state                  = vio_dring_state,
        };
        int err, delay;
+       int retries = 0;
 
        hdr.seq = dr->snd_nxt;
        delay = 1;
@@ -272,6 +278,13 @@ static int vnet_send_ack(struct vnet_port *port, struct vio_dring_state *dr,
                udelay(delay);
                if ((delay <<= 1) > 128)
                        delay = 128;
+               if (retries++ > VNET_MAX_RETRIES) {
+                       pr_info("ECONNRESET %x:%x:%x:%x:%x:%x\n",
+                               port->raddr[0], port->raddr[1],
+                               port->raddr[2], port->raddr[3],
+                               port->raddr[4], port->raddr[5]);
+                       err = -ECONNRESET;
+               }
        } while (err == -EAGAIN);
 
        return err;
@@ -593,6 +606,7 @@ static int __vnet_tx_trigger(struct vnet_port *port)
                .end_idx                = (u32) -1,
        };
        int err, delay;
+       int retries = 0;
 
        hdr.seq = dr->snd_nxt;
        delay = 1;
@@ -605,6 +619,8 @@ static int __vnet_tx_trigger(struct vnet_port *port)
                udelay(delay);
                if ((delay <<= 1) > 128)
                        delay = 128;
+               if (retries++ > VNET_MAX_RETRIES)
+                       break;
        } while (err == -EAGAIN);
 
        return err;