Commit d12a26b7 authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller
Browse files

virtio_net: avoid data-races on dev->stats fields



Use DEV_STATS_INC() and DEV_STATS_READ() which provide
atomicity on paths that can be used concurrently.

Reported-by: default avatarsyzbot <syzkaller@googlegroups.com>
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Reviewed-by: default avatarXuan Zhuo <xuanzhuo@linux.alibaba.com>
Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Jason Wang <jasowang@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0b068c71
Loading
Loading
Loading
Loading
+15 −15
Original line number Diff line number Diff line
@@ -1258,7 +1258,7 @@ static struct sk_buff *receive_small(struct net_device *dev,
	if (unlikely(len > GOOD_PACKET_LEN)) {
		pr_debug("%s: rx error: len %u exceeds max size %d\n",
			 dev->name, len, GOOD_PACKET_LEN);
		dev->stats.rx_length_errors++;
		DEV_STATS_INC(dev, rx_length_errors);
		goto err;
	}

@@ -1323,7 +1323,7 @@ static void mergeable_buf_free(struct receive_queue *rq, int num_buf,
		if (unlikely(!buf)) {
			pr_debug("%s: rx error: %d buffers missing\n",
				 dev->name, num_buf);
			dev->stats.rx_length_errors++;
			DEV_STATS_INC(dev, rx_length_errors);
			break;
		}
		stats->bytes += len;
@@ -1432,7 +1432,7 @@ static int virtnet_build_xdp_buff_mrg(struct net_device *dev,
			pr_debug("%s: rx error: %d buffers out of %d missing\n",
				 dev->name, *num_buf,
				 virtio16_to_cpu(vi->vdev, hdr->num_buffers));
			dev->stats.rx_length_errors++;
			DEV_STATS_INC(dev, rx_length_errors);
			goto err;
		}

@@ -1451,7 +1451,7 @@ static int virtnet_build_xdp_buff_mrg(struct net_device *dev,
			put_page(page);
			pr_debug("%s: rx error: len %u exceeds truesize %lu\n",
				 dev->name, len, (unsigned long)(truesize - room));
			dev->stats.rx_length_errors++;
			DEV_STATS_INC(dev, rx_length_errors);
			goto err;
		}

@@ -1630,7 +1630,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
	if (unlikely(len > truesize - room)) {
		pr_debug("%s: rx error: len %u exceeds truesize %lu\n",
			 dev->name, len, (unsigned long)(truesize - room));
		dev->stats.rx_length_errors++;
		DEV_STATS_INC(dev, rx_length_errors);
		goto err_skb;
	}

@@ -1662,7 +1662,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
				 dev->name, num_buf,
				 virtio16_to_cpu(vi->vdev,
						 hdr->num_buffers));
			dev->stats.rx_length_errors++;
			DEV_STATS_INC(dev, rx_length_errors);
			goto err_buf;
		}

@@ -1676,7 +1676,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
		if (unlikely(len > truesize - room)) {
			pr_debug("%s: rx error: len %u exceeds truesize %lu\n",
				 dev->name, len, (unsigned long)(truesize - room));
			dev->stats.rx_length_errors++;
			DEV_STATS_INC(dev, rx_length_errors);
			goto err_skb;
		}

@@ -1763,7 +1763,7 @@ static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq,

	if (unlikely(len < vi->hdr_len + ETH_HLEN)) {
		pr_debug("%s: short packet %i\n", dev->name, len);
		dev->stats.rx_length_errors++;
		DEV_STATS_INC(dev, rx_length_errors);
		virtnet_rq_free_unused_buf(rq->vq, buf);
		return;
	}
@@ -1803,7 +1803,7 @@ static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
	return;

frame_err:
	dev->stats.rx_frame_errors++;
	DEV_STATS_INC(dev, rx_frame_errors);
	dev_kfree_skb(skb);
}

@@ -2349,12 +2349,12 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)

	/* This should not happen! */
	if (unlikely(err)) {
		dev->stats.tx_fifo_errors++;
		DEV_STATS_INC(dev, tx_fifo_errors);
		if (net_ratelimit())
			dev_warn(&dev->dev,
				 "Unexpected TXQ (%d) queue failure: %d\n",
				 qnum, err);
		dev->stats.tx_dropped++;
		DEV_STATS_INC(dev, tx_dropped);
		dev_kfree_skb_any(skb);
		return NETDEV_TX_OK;
	}
@@ -2573,10 +2573,10 @@ static void virtnet_stats(struct net_device *dev,
		tot->tx_errors  += terrors;
	}

	tot->tx_dropped = dev->stats.tx_dropped;
	tot->tx_fifo_errors = dev->stats.tx_fifo_errors;
	tot->rx_length_errors = dev->stats.rx_length_errors;
	tot->rx_frame_errors = dev->stats.rx_frame_errors;
	tot->tx_dropped = DEV_STATS_READ(dev, tx_dropped);
	tot->tx_fifo_errors = DEV_STATS_READ(dev, tx_fifo_errors);
	tot->rx_length_errors = DEV_STATS_READ(dev, rx_length_errors);
	tot->rx_frame_errors = DEV_STATS_READ(dev, rx_frame_errors);
}

static void virtnet_ack_link_announce(struct virtnet_info *vi)