summaryrefslogtreecommitdiff
path: root/arch/um/drivers/vector_kern.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/um/drivers/vector_kern.c')
-rw-r--r--arch/um/drivers/vector_kern.c44
1 files changed, 37 insertions, 7 deletions
diff --git a/arch/um/drivers/vector_kern.c b/arch/um/drivers/vector_kern.c
index e190e4ca52e1..769ffbd9e9a6 100644
--- a/arch/um/drivers/vector_kern.c
+++ b/arch/um/drivers/vector_kern.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2017 - Cambridge Greys Limited
* Copyright (C) 2011 - 2014 Cisco Systems Inc
@@ -5,7 +6,6 @@
* Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
* James Leu (jleu@mindspring.net).
* Copyright (C) 2001 by various other people who didn't put their name here.
- * Licensed under the GPL.
*/
#include <linux/version.h>
@@ -76,6 +76,7 @@ static void vector_eth_configure(int n, struct arglist *def);
#define DEFAULT_VECTOR_SIZE 64
#define TX_SMALL_PACKET 128
#define MAX_IOV_SIZE (MAX_SKB_FRAGS + 1)
+#define MAX_ITERATIONS 64
static const struct {
const char string[ETH_GSTRING_LEN];
@@ -121,7 +122,8 @@ static int get_mtu(struct arglist *def)
if (mtu != NULL) {
if (kstrtoul(mtu, 10, &result) == 0)
- return result;
+ if ((result < (1 << 16) - 1) && (result >= 576))
+ return result;
}
return ETH_MAX_PACKET;
}
@@ -186,6 +188,8 @@ static int get_transport_options(struct arglist *def)
if (strncmp(transport, TRANS_TAP, TRANS_TAP_LEN) == 0)
+ return 0;
+ if (strncmp(transport, TRANS_HYBRID, TRANS_HYBRID_LEN) == 0)
return (vec_rx | VECTOR_BPF);
if (strncmp(transport, TRANS_RAW, TRANS_RAW_LEN) == 0)
return (vec_rx | vec_tx | VECTOR_QDISC_BYPASS);
@@ -415,6 +419,7 @@ static int vector_send(struct vector_queue *qi)
if (net_ratelimit())
netdev_err(vp->dev, "sendmmsg err=%i\n",
result);
+ vp->in_error = true;
result = send_len;
}
if (result > 0) {
@@ -842,6 +847,10 @@ static int vector_legacy_rx(struct vector_private *vp)
}
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 (pkt_len > vp->header_size) {
@@ -888,12 +897,16 @@ static int writev_tx(struct vector_private *vp, struct sk_buff *skb)
if (iov_count < 1)
goto drop;
+
pkt_len = uml_vector_writev(
vp->fds->tx_fd,
(struct iovec *) &iov,
iov_count
);
+ if (pkt_len < 0)
+ goto drop;
+
netif_trans_update(vp->dev);
netif_wake_queue(vp->dev);
@@ -908,6 +921,8 @@ static int writev_tx(struct vector_private *vp, struct sk_buff *skb)
drop:
vp->dev->stats.tx_dropped++;
consume_skb(skb);
+ if (pkt_len < 0)
+ vp->in_error = true;
return pkt_len;
}
@@ -936,6 +951,9 @@ static int vector_mmsg_rx(struct vector_private *vp)
packet_count = uml_vector_recvmmsg(
vp->fds->rx_fd, qi->mmsg_vector, qi->max_depth, 0);
+ if (packet_count < 0)
+ vp->in_error = true;
+
if (packet_count <= 0)
return packet_count;
@@ -1005,15 +1023,18 @@ static int vector_mmsg_rx(struct vector_private *vp)
static void vector_rx(struct vector_private *vp)
{
int err;
+ int iter = 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
- while ((err = vector_legacy_rx(vp)) > 0)
- ;
+ while (((err = vector_legacy_rx(vp)) > 0) && (iter < MAX_ITERATIONS))
+ iter++;
if ((err != 0) && net_ratelimit())
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)
@@ -1021,6 +1042,13 @@ static int vector_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct vector_private *vp = netdev_priv(dev);
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) {
writev_tx(vp, skb);
return NETDEV_TX_OK;
@@ -1131,6 +1159,7 @@ static int vector_net_close(struct net_device *dev)
vp->fds = NULL;
spin_lock_irqsave(&vp->lock, flags);
vp->opened = false;
+ vp->in_error = false;
spin_unlock_irqrestore(&vp->lock, flags);
return 0;
}
@@ -1498,7 +1527,8 @@ static void vector_eth_configure(
.transport_data = NULL,
.in_write_poll = false,
.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);