diff options
Diffstat (limited to 'arch/um/drivers/vector_kern.c')
| -rw-r--r-- | arch/um/drivers/vector_kern.c | 44 | 
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 ([email protected]) and   * James Leu ([email protected]).   * 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);  |