diff options
Diffstat (limited to 'drivers/net/virtio_net.c')
| -rw-r--r-- | drivers/net/virtio_net.c | 31 | 
1 files changed, 21 insertions, 10 deletions
| diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 9320d96a1632..2e69bcdc5b07 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -305,7 +305,7 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,  	copy = len;  	if (copy > skb_tailroom(skb))  		copy = skb_tailroom(skb); -	memcpy(skb_put(skb, copy), p, copy); +	skb_put_data(skb, p, copy);  	len -= copy;  	offset += copy; @@ -869,7 +869,7 @@ static unsigned int get_mergeable_buf_len(struct receive_queue *rq,  	unsigned int len;  	len = hdr_len + clamp_t(unsigned int, ewma_pkt_len_read(avg_pkt_len), -				rq->min_buf_len - hdr_len, PAGE_SIZE - hdr_len); +				rq->min_buf_len, PAGE_SIZE - hdr_len);  	return ALIGN(len, L1_CACHE_BYTES);  } @@ -1150,7 +1150,7 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)  	struct virtio_net_hdr_mrg_rxbuf *hdr;  	const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;  	struct virtnet_info *vi = sq->vq->vdev->priv; -	unsigned num_sg; +	int num_sg;  	unsigned hdr_len = vi->hdr_len;  	bool can_push; @@ -1177,11 +1177,16 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)  	if (can_push) {  		__skb_push(skb, hdr_len);  		num_sg = skb_to_sgvec(skb, sq->sg, 0, skb->len); +		if (unlikely(num_sg < 0)) +			return num_sg;  		/* Pull header back to avoid skew in tx bytes calculations. */  		__skb_pull(skb, hdr_len);  	} else {  		sg_set_buf(sq->sg, hdr, hdr_len); -		num_sg = skb_to_sgvec(skb, sq->sg + 1, 0, skb->len) + 1; +		num_sg = skb_to_sgvec(skb, sq->sg + 1, 0, skb->len); +		if (unlikely(num_sg < 0)) +			return num_sg; +		num_sg++;  	}  	return virtqueue_add_outbuf(sq->vq, sq->sg, num_sg, skb, GFP_ATOMIC);  } @@ -1797,6 +1802,7 @@ static void virtnet_freeze_down(struct virtio_device *vdev)  	flush_work(&vi->config_work);  	netif_device_detach(vi->dev); +	netif_tx_disable(vi->dev);  	cancel_delayed_work_sync(&vi->refill);  	if (netif_running(vi->dev)) { @@ -1950,16 +1956,18 @@ virtio_reset_err:  	return err;  } -static bool virtnet_xdp_query(struct net_device *dev) +static u32 virtnet_xdp_query(struct net_device *dev)  {  	struct virtnet_info *vi = netdev_priv(dev); +	const struct bpf_prog *xdp_prog;  	int i;  	for (i = 0; i < vi->max_queue_pairs; i++) { -		if (vi->rq[i].xdp_prog) -			return true; +		xdp_prog = rtnl_dereference(vi->rq[i].xdp_prog); +		if (xdp_prog) +			return xdp_prog->aux->id;  	} -	return false; +	return 0;  }  static int virtnet_xdp(struct net_device *dev, struct netdev_xdp *xdp) @@ -1968,7 +1976,8 @@ static int virtnet_xdp(struct net_device *dev, struct netdev_xdp *xdp)  	case XDP_SETUP_PROG:  		return virtnet_xdp_set(dev, xdp->prog, xdp->extack);  	case XDP_QUERY_PROG: -		xdp->prog_attached = virtnet_xdp_query(dev); +		xdp->prog_id = virtnet_xdp_query(dev); +		xdp->prog_attached = !!xdp->prog_id;  		return 0;  	default:  		return -EINVAL; @@ -1989,6 +1998,7 @@ static const struct net_device_ops virtnet_netdev = {  	.ndo_poll_controller = virtnet_netpoll,  #endif  	.ndo_xdp		= virtnet_xdp, +	.ndo_features_check	= passthru_features_check,  };  static void virtnet_config_changed_work(struct work_struct *work) @@ -2143,7 +2153,8 @@ static unsigned int mergeable_min_buf_len(struct virtnet_info *vi, struct virtqu  	unsigned int buf_len = hdr_len + ETH_HLEN + VLAN_HLEN + packet_len;  	unsigned int min_buf_len = DIV_ROUND_UP(buf_len, rq_size); -	return max(min_buf_len, hdr_len); +	return max(max(min_buf_len, hdr_len) - hdr_len, +		   (unsigned int)GOOD_PACKET_LEN);  }  static int virtnet_find_vqs(struct virtnet_info *vi) | 
