Commit d47761db authored by Anton Ivanov's avatar Anton Ivanov Committed by Richard Weinberger

um: Error handling fixes in vector drivers

With the addition of bess support which uses connection
oriented SEQPACKET sockets the vector routines can now
encounter a "remote end closed the connection" scenario.

This adds handling code to detect it in the TX path and
the legacy RX path. There is no way to detect it in the
vector RX path because that can legitimately return 0
even if the remote end has not closed the connection. As
a result the detection is delayed until the first TX
event after the close.
Signed-off-by: default avatarAnton Ivanov <anton.ivanov@cambridgegreys.com>
Signed-off-by: default avatarRichard Weinberger <richard@nod.at>
parent 58531931
...@@ -76,6 +76,7 @@ static void vector_eth_configure(int n, struct arglist *def); ...@@ -76,6 +76,7 @@ static void vector_eth_configure(int n, struct arglist *def);
#define DEFAULT_VECTOR_SIZE 64 #define DEFAULT_VECTOR_SIZE 64
#define TX_SMALL_PACKET 128 #define TX_SMALL_PACKET 128
#define MAX_IOV_SIZE (MAX_SKB_FRAGS + 1) #define MAX_IOV_SIZE (MAX_SKB_FRAGS + 1)
#define MAX_ITERATIONS 64
static const struct { static const struct {
const char string[ETH_GSTRING_LEN]; const char string[ETH_GSTRING_LEN];
...@@ -418,6 +419,7 @@ static int vector_send(struct vector_queue *qi) ...@@ -418,6 +419,7 @@ static int vector_send(struct vector_queue *qi)
if (net_ratelimit()) if (net_ratelimit())
netdev_err(vp->dev, "sendmmsg err=%i\n", netdev_err(vp->dev, "sendmmsg err=%i\n",
result); result);
vp->in_error = true;
result = send_len; result = send_len;
} }
if (result > 0) { if (result > 0) {
...@@ -845,6 +847,10 @@ static int vector_legacy_rx(struct vector_private *vp) ...@@ -845,6 +847,10 @@ static int vector_legacy_rx(struct vector_private *vp)
} }
pkt_len = uml_vector_recvmsg(vp->fds->rx_fd, &hdr, 0); pkt_len = uml_vector_recvmsg(vp->fds->rx_fd, &hdr, 0);
if (pkt_len < 0) {
vp->in_error = true;
return pkt_len;
}
if (skb != NULL) { if (skb != NULL) {
if (pkt_len > vp->header_size) { if (pkt_len > vp->header_size) {
...@@ -891,12 +897,16 @@ static int writev_tx(struct vector_private *vp, struct sk_buff *skb) ...@@ -891,12 +897,16 @@ static int writev_tx(struct vector_private *vp, struct sk_buff *skb)
if (iov_count < 1) if (iov_count < 1)
goto drop; goto drop;
pkt_len = uml_vector_writev( pkt_len = uml_vector_writev(
vp->fds->tx_fd, vp->fds->tx_fd,
(struct iovec *) &iov, (struct iovec *) &iov,
iov_count iov_count
); );
if (pkt_len < 0)
goto drop;
netif_trans_update(vp->dev); netif_trans_update(vp->dev);
netif_wake_queue(vp->dev); netif_wake_queue(vp->dev);
...@@ -911,6 +921,8 @@ static int writev_tx(struct vector_private *vp, struct sk_buff *skb) ...@@ -911,6 +921,8 @@ static int writev_tx(struct vector_private *vp, struct sk_buff *skb)
drop: drop:
vp->dev->stats.tx_dropped++; vp->dev->stats.tx_dropped++;
consume_skb(skb); consume_skb(skb);
if (pkt_len < 0)
vp->in_error = true;
return pkt_len; return pkt_len;
} }
...@@ -939,6 +951,9 @@ static int vector_mmsg_rx(struct vector_private *vp) ...@@ -939,6 +951,9 @@ static int vector_mmsg_rx(struct vector_private *vp)
packet_count = uml_vector_recvmmsg( packet_count = uml_vector_recvmmsg(
vp->fds->rx_fd, qi->mmsg_vector, qi->max_depth, 0); vp->fds->rx_fd, qi->mmsg_vector, qi->max_depth, 0);
if (packet_count < 0)
vp->in_error = true;
if (packet_count <= 0) if (packet_count <= 0)
return packet_count; return packet_count;
...@@ -1008,15 +1023,18 @@ static int vector_mmsg_rx(struct vector_private *vp) ...@@ -1008,15 +1023,18 @@ static int vector_mmsg_rx(struct vector_private *vp)
static void vector_rx(struct vector_private *vp) static void vector_rx(struct vector_private *vp)
{ {
int err; int err;
int iter = 0;
if ((vp->options & VECTOR_RX) > 0) if ((vp->options & VECTOR_RX) > 0)
while ((err = vector_mmsg_rx(vp)) > 0) while (((err = vector_mmsg_rx(vp)) > 0) && (iter < MAX_ITERATIONS))
; iter++;
else else
while ((err = vector_legacy_rx(vp)) > 0) while (((err = vector_legacy_rx(vp)) > 0) && (iter < MAX_ITERATIONS))
; iter++;
if ((err != 0) && net_ratelimit()) if ((err != 0) && net_ratelimit())
netdev_err(vp->dev, "vector_rx: error(%d)\n", err); netdev_err(vp->dev, "vector_rx: error(%d)\n", err);
if (iter == MAX_ITERATIONS)
netdev_err(vp->dev, "vector_rx: device stuck, remote end may have closed the connection\n");
} }
static int vector_net_start_xmit(struct sk_buff *skb, struct net_device *dev) static int vector_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
...@@ -1024,6 +1042,13 @@ static int vector_net_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -1024,6 +1042,13 @@ static int vector_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct vector_private *vp = netdev_priv(dev); struct vector_private *vp = netdev_priv(dev);
int queue_depth = 0; int queue_depth = 0;
if (vp->in_error) {
deactivate_fd(vp->fds->rx_fd, vp->rx_irq);
if ((vp->fds->rx_fd != vp->fds->tx_fd) && (vp->tx_irq != 0))
deactivate_fd(vp->fds->tx_fd, vp->tx_irq);
return NETDEV_TX_BUSY;
}
if ((vp->options & VECTOR_TX) == 0) { if ((vp->options & VECTOR_TX) == 0) {
writev_tx(vp, skb); writev_tx(vp, skb);
return NETDEV_TX_OK; return NETDEV_TX_OK;
...@@ -1134,6 +1159,7 @@ static int vector_net_close(struct net_device *dev) ...@@ -1134,6 +1159,7 @@ static int vector_net_close(struct net_device *dev)
vp->fds = NULL; vp->fds = NULL;
spin_lock_irqsave(&vp->lock, flags); spin_lock_irqsave(&vp->lock, flags);
vp->opened = false; vp->opened = false;
vp->in_error = false;
spin_unlock_irqrestore(&vp->lock, flags); spin_unlock_irqrestore(&vp->lock, flags);
return 0; return 0;
} }
...@@ -1501,7 +1527,8 @@ static void vector_eth_configure( ...@@ -1501,7 +1527,8 @@ static void vector_eth_configure(
.transport_data = NULL, .transport_data = NULL,
.in_write_poll = false, .in_write_poll = false,
.coalesce = 2, .coalesce = 2,
.req_size = get_req_size(def) .req_size = get_req_size(def),
.in_error = false
}); });
dev->features = dev->hw_features = (NETIF_F_SG | NETIF_F_FRAGLIST); dev->features = dev->hw_features = (NETIF_F_SG | NETIF_F_FRAGLIST);
......
...@@ -116,6 +116,7 @@ struct vector_private { ...@@ -116,6 +116,7 @@ struct vector_private {
bool rexmit_scheduled; bool rexmit_scheduled;
bool opened; bool opened;
bool in_write_poll; bool in_write_poll;
bool in_error;
/* ethtool stats */ /* ethtool stats */
......
...@@ -618,7 +618,7 @@ int uml_vector_writev(int fd, void *hdr, int iovcount) ...@@ -618,7 +618,7 @@ int uml_vector_writev(int fd, void *hdr, int iovcount)
int n; int n;
CATCH_EINTR(n = writev(fd, (struct iovec *) hdr, iovcount)); CATCH_EINTR(n = writev(fd, (struct iovec *) hdr, iovcount));
if ((n < 0) && (errno == EAGAIN)) if ((n < 0) && ((errno == EAGAIN) || (errno == ENOBUFS)))
return 0; return 0;
if (n >= 0) if (n >= 0)
return n; return n;
...@@ -635,7 +635,7 @@ int uml_vector_sendmmsg( ...@@ -635,7 +635,7 @@ int uml_vector_sendmmsg(
int n; int n;
CATCH_EINTR(n = sendmmsg(fd, (struct mmsghdr *) msgvec, vlen, flags)); CATCH_EINTR(n = sendmmsg(fd, (struct mmsghdr *) msgvec, vlen, flags));
if ((n < 0) && (errno == EAGAIN)) if ((n < 0) && ((errno == EAGAIN) || (errno == ENOBUFS)))
return 0; return 0;
if (n >= 0) if (n >= 0)
return n; return n;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment