Commit 3fa2a1df authored by stephen hemminger's avatar stephen hemminger Committed by David S. Miller

virtio-net: per cpu 64 bit stats (v2)

Use per-cpu variables to maintain 64 bit statistics.
Signed-off-by: default avatarStephen Hemminger <shemminger@vyatta.com>
Signed-off-by: default avatarDavid S. Miller <davem@conan.davemloft.net>
parent f984cec6
...@@ -40,6 +40,15 @@ module_param(gso, bool, 0444); ...@@ -40,6 +40,15 @@ module_param(gso, bool, 0444);
#define VIRTNET_SEND_COMMAND_SG_MAX 2 #define VIRTNET_SEND_COMMAND_SG_MAX 2
struct virtnet_stats {
struct u64_stats_sync syncp;
u64 tx_bytes;
u64 tx_packets;
u64 rx_bytes;
u64 rx_packets;
};
struct virtnet_info { struct virtnet_info {
struct virtio_device *vdev; struct virtio_device *vdev;
struct virtqueue *rvq, *svq, *cvq; struct virtqueue *rvq, *svq, *cvq;
...@@ -56,6 +65,9 @@ struct virtnet_info { ...@@ -56,6 +65,9 @@ struct virtnet_info {
/* Host will merge rx buffers for big packets (shake it! shake it!) */ /* Host will merge rx buffers for big packets (shake it! shake it!) */
bool mergeable_rx_bufs; bool mergeable_rx_bufs;
/* Active statistics */
struct virtnet_stats __percpu *stats;
/* Work struct for refilling if we run low on memory. */ /* Work struct for refilling if we run low on memory. */
struct delayed_work refill; struct delayed_work refill;
...@@ -209,7 +221,6 @@ static int receive_mergeable(struct virtnet_info *vi, struct sk_buff *skb) ...@@ -209,7 +221,6 @@ static int receive_mergeable(struct virtnet_info *vi, struct sk_buff *skb)
skb->dev->stats.rx_length_errors++; skb->dev->stats.rx_length_errors++;
return -EINVAL; return -EINVAL;
} }
page = virtqueue_get_buf(vi->rvq, &len); page = virtqueue_get_buf(vi->rvq, &len);
if (!page) { if (!page) {
pr_debug("%s: rx error: %d buffers missing\n", pr_debug("%s: rx error: %d buffers missing\n",
...@@ -217,6 +228,7 @@ static int receive_mergeable(struct virtnet_info *vi, struct sk_buff *skb) ...@@ -217,6 +228,7 @@ static int receive_mergeable(struct virtnet_info *vi, struct sk_buff *skb)
skb->dev->stats.rx_length_errors++; skb->dev->stats.rx_length_errors++;
return -EINVAL; return -EINVAL;
} }
if (len > PAGE_SIZE) if (len > PAGE_SIZE)
len = PAGE_SIZE; len = PAGE_SIZE;
...@@ -230,6 +242,7 @@ static int receive_mergeable(struct virtnet_info *vi, struct sk_buff *skb) ...@@ -230,6 +242,7 @@ static int receive_mergeable(struct virtnet_info *vi, struct sk_buff *skb)
static void receive_buf(struct net_device *dev, void *buf, unsigned int len) static void receive_buf(struct net_device *dev, void *buf, unsigned int len)
{ {
struct virtnet_info *vi = netdev_priv(dev); struct virtnet_info *vi = netdev_priv(dev);
struct virtnet_stats __percpu *stats = this_cpu_ptr(vi->stats);
struct sk_buff *skb; struct sk_buff *skb;
struct page *page; struct page *page;
struct skb_vnet_hdr *hdr; struct skb_vnet_hdr *hdr;
...@@ -265,8 +278,11 @@ static void receive_buf(struct net_device *dev, void *buf, unsigned int len) ...@@ -265,8 +278,11 @@ static void receive_buf(struct net_device *dev, void *buf, unsigned int len)
hdr = skb_vnet_hdr(skb); hdr = skb_vnet_hdr(skb);
skb->truesize += skb->data_len; skb->truesize += skb->data_len;
dev->stats.rx_bytes += skb->len;
dev->stats.rx_packets++; u64_stats_update_begin(&stats->syncp);
stats->rx_bytes += skb->len;
stats->rx_packets++;
u64_stats_update_end(&stats->syncp);
if (hdr->hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) { if (hdr->hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
pr_debug("Needs csum!\n"); pr_debug("Needs csum!\n");
...@@ -515,11 +531,16 @@ static unsigned int free_old_xmit_skbs(struct virtnet_info *vi) ...@@ -515,11 +531,16 @@ static unsigned int free_old_xmit_skbs(struct virtnet_info *vi)
{ {
struct sk_buff *skb; struct sk_buff *skb;
unsigned int len, tot_sgs = 0; unsigned int len, tot_sgs = 0;
struct virtnet_stats __percpu *stats = this_cpu_ptr(vi->stats);
while ((skb = virtqueue_get_buf(vi->svq, &len)) != NULL) { while ((skb = virtqueue_get_buf(vi->svq, &len)) != NULL) {
pr_debug("Sent skb %p\n", skb); pr_debug("Sent skb %p\n", skb);
vi->dev->stats.tx_bytes += skb->len;
vi->dev->stats.tx_packets++; u64_stats_update_begin(&stats->syncp);
stats->tx_bytes += skb->len;
stats->tx_packets++;
u64_stats_update_end(&stats->syncp);
tot_sgs += skb_vnet_hdr(skb)->num_sg; tot_sgs += skb_vnet_hdr(skb)->num_sg;
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
} }
...@@ -641,6 +662,40 @@ static int virtnet_set_mac_address(struct net_device *dev, void *p) ...@@ -641,6 +662,40 @@ static int virtnet_set_mac_address(struct net_device *dev, void *p)
return 0; return 0;
} }
static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
struct rtnl_link_stats64 *tot)
{
struct virtnet_info *vi = netdev_priv(dev);
int cpu;
unsigned int start;
for_each_possible_cpu(cpu) {
struct virtnet_stats __percpu *stats
= per_cpu_ptr(vi->stats, cpu);
u64 tpackets, tbytes, rpackets, rbytes;
do {
start = u64_stats_fetch_begin(&stats->syncp);
tpackets = stats->tx_packets;
tbytes = stats->tx_bytes;
rpackets = stats->rx_packets;
rbytes = stats->rx_bytes;
} while (u64_stats_fetch_retry(&stats->syncp, start));
tot->rx_packets += rpackets;
tot->tx_packets += tpackets;
tot->rx_bytes += rbytes;
tot->tx_bytes += tbytes;
}
tot->tx_dropped = dev->stats.tx_dropped;
tot->rx_dropped = dev->stats.rx_dropped;
tot->rx_length_errors = dev->stats.rx_length_errors;
tot->rx_frame_errors = dev->stats.rx_frame_errors;
return tot;
}
#ifdef CONFIG_NET_POLL_CONTROLLER #ifdef CONFIG_NET_POLL_CONTROLLER
static void virtnet_netpoll(struct net_device *dev) static void virtnet_netpoll(struct net_device *dev)
{ {
...@@ -650,6 +705,14 @@ static void virtnet_netpoll(struct net_device *dev) ...@@ -650,6 +705,14 @@ static void virtnet_netpoll(struct net_device *dev)
} }
#endif #endif
static void virtnet_free(struct net_device *dev)
{
struct virtnet_info *vi = netdev_priv(dev);
free_percpu(vi->stats);
free_netdev(dev);
}
static int virtnet_open(struct net_device *dev) static int virtnet_open(struct net_device *dev)
{ {
struct virtnet_info *vi = netdev_priv(dev); struct virtnet_info *vi = netdev_priv(dev);
...@@ -835,6 +898,7 @@ static const struct net_device_ops virtnet_netdev = { ...@@ -835,6 +898,7 @@ static const struct net_device_ops virtnet_netdev = {
.ndo_set_mac_address = virtnet_set_mac_address, .ndo_set_mac_address = virtnet_set_mac_address,
.ndo_set_rx_mode = virtnet_set_rx_mode, .ndo_set_rx_mode = virtnet_set_rx_mode,
.ndo_change_mtu = virtnet_change_mtu, .ndo_change_mtu = virtnet_change_mtu,
.ndo_get_stats64 = virtnet_stats,
.ndo_vlan_rx_add_vid = virtnet_vlan_rx_add_vid, .ndo_vlan_rx_add_vid = virtnet_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = virtnet_vlan_rx_kill_vid, .ndo_vlan_rx_kill_vid = virtnet_vlan_rx_kill_vid,
#ifdef CONFIG_NET_POLL_CONTROLLER #ifdef CONFIG_NET_POLL_CONTROLLER
...@@ -895,6 +959,8 @@ static int virtnet_probe(struct virtio_device *vdev) ...@@ -895,6 +959,8 @@ static int virtnet_probe(struct virtio_device *vdev)
/* Set up network device as normal. */ /* Set up network device as normal. */
dev->netdev_ops = &virtnet_netdev; dev->netdev_ops = &virtnet_netdev;
dev->features = NETIF_F_HIGHDMA; dev->features = NETIF_F_HIGHDMA;
dev->destructor = virtnet_free;
SET_ETHTOOL_OPS(dev, &virtnet_ethtool_ops); SET_ETHTOOL_OPS(dev, &virtnet_ethtool_ops);
SET_NETDEV_DEV(dev, &vdev->dev); SET_NETDEV_DEV(dev, &vdev->dev);
...@@ -939,6 +1005,11 @@ static int virtnet_probe(struct virtio_device *vdev) ...@@ -939,6 +1005,11 @@ static int virtnet_probe(struct virtio_device *vdev)
vi->vdev = vdev; vi->vdev = vdev;
vdev->priv = vi; vdev->priv = vi;
vi->pages = NULL; vi->pages = NULL;
vi->stats = alloc_percpu(struct virtnet_stats);
err = -ENOMEM;
if (vi->stats == NULL)
goto free;
INIT_DELAYED_WORK(&vi->refill, refill_work); INIT_DELAYED_WORK(&vi->refill, refill_work);
sg_init_table(vi->rx_sg, ARRAY_SIZE(vi->rx_sg)); sg_init_table(vi->rx_sg, ARRAY_SIZE(vi->rx_sg));
sg_init_table(vi->tx_sg, ARRAY_SIZE(vi->tx_sg)); sg_init_table(vi->tx_sg, ARRAY_SIZE(vi->tx_sg));
...@@ -958,7 +1029,7 @@ static int virtnet_probe(struct virtio_device *vdev) ...@@ -958,7 +1029,7 @@ static int virtnet_probe(struct virtio_device *vdev)
err = vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names); err = vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names);
if (err) if (err)
goto free; goto free_stats;
vi->rvq = vqs[0]; vi->rvq = vqs[0];
vi->svq = vqs[1]; vi->svq = vqs[1];
...@@ -1003,6 +1074,8 @@ static int virtnet_probe(struct virtio_device *vdev) ...@@ -1003,6 +1074,8 @@ static int virtnet_probe(struct virtio_device *vdev)
cancel_delayed_work_sync(&vi->refill); cancel_delayed_work_sync(&vi->refill);
free_vqs: free_vqs:
vdev->config->del_vqs(vdev); vdev->config->del_vqs(vdev);
free_stats:
free_percpu(vi->stats);
free: free:
free_netdev(dev); free_netdev(dev);
return err; return err;
......
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