diff options
author | Pravin B Shelar <pshelar@nicira.com> | 2015-10-02 21:56:34 (GMT) |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-10-05 14:06:35 (GMT) |
commit | 83ffe99f52b8f269b31b21524adcd13b165f7703 (patch) | |
tree | d9be5a66df6daf04dc7800ba8eab75c2d30e39c4 | |
parent | 8690f47d6e76d4300eeb316ba4773f7de3da63f7 (diff) | |
download | linux-83ffe99f52b8f269b31b21524adcd13b165f7703.tar.xz |
openvswitch: Fix ovs_vport_get_stats()
Not every device has dev->tstats set. So when OVS tries to calculate
vport stats it causes kernel panic. Following patch fixes it by
using standard API to get net-device stats.
---8<---
Unable to handle kernel paging request at virtual address 766b4008
Internal error: Oops: 96000005 [#1] PREEMPT SMP
Modules linked in: vport_vxlan vxlan ip6_udp_tunnel udp_tunnel tun bridge stp llc openvswitch ipv6
CPU: 7 PID: 1108 Comm: ovs-vswitchd Not tainted 4.3.0-rc3+ #82
PC is at ovs_vport_get_stats+0x150/0x1f8 [openvswitch]
<snip>
Call trace:
[<ffffffbffc0859f8>] ovs_vport_get_stats+0x150/0x1f8 [openvswitch]
[<ffffffbffc07cdb0>] ovs_vport_cmd_fill_info+0x140/0x1e0 [openvswitch]
[<ffffffbffc07cf0c>] ovs_vport_cmd_dump+0xbc/0x138 [openvswitch]
[<ffffffc00045a5ac>] netlink_dump+0xb8/0x258
[<ffffffc00045ace0>] __netlink_dump_start+0x120/0x178
[<ffffffc00045dd9c>] genl_family_rcv_msg+0x2d4/0x308
[<ffffffc00045de58>] genl_rcv_msg+0x88/0xc4
[<ffffffc00045cf24>] netlink_rcv_skb+0xd4/0x100
[<ffffffc00045dab0>] genl_rcv+0x30/0x48
[<ffffffc00045c830>] netlink_unicast+0x154/0x200
[<ffffffc00045cc9c>] netlink_sendmsg+0x308/0x364
[<ffffffc00041e10c>] sock_sendmsg+0x14/0x2c
[<ffffffc000420d58>] SyS_sendto+0xbc/0xf0
Code: aa1603e1 f94037a4 aa1303e2 aa1703e0 (f9400465)
Reported-by: Tomasz Sawicki <tomasz.sawicki@objectiveintegration.uk>
Fixes: 8c876639c98 ("openvswitch: Remove vport stats.")
Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/openvswitch/vport.c | 42 |
1 files changed, 13 insertions, 29 deletions
diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c index dc81dc6..fc5c0b9 100644 --- a/net/openvswitch/vport.c +++ b/net/openvswitch/vport.c @@ -280,35 +280,19 @@ void ovs_vport_del(struct vport *vport) */ void ovs_vport_get_stats(struct vport *vport, struct ovs_vport_stats *stats) { - struct net_device *dev = vport->dev; - int i; - - memset(stats, 0, sizeof(*stats)); - stats->rx_errors = dev->stats.rx_errors; - stats->tx_errors = dev->stats.tx_errors; - stats->tx_dropped = dev->stats.tx_dropped; - stats->rx_dropped = dev->stats.rx_dropped; - - stats->rx_dropped += atomic_long_read(&dev->rx_dropped); - stats->tx_dropped += atomic_long_read(&dev->tx_dropped); - - for_each_possible_cpu(i) { - const struct pcpu_sw_netstats *percpu_stats; - struct pcpu_sw_netstats local_stats; - unsigned int start; - - percpu_stats = per_cpu_ptr(dev->tstats, i); - - do { - start = u64_stats_fetch_begin_irq(&percpu_stats->syncp); - local_stats = *percpu_stats; - } while (u64_stats_fetch_retry_irq(&percpu_stats->syncp, start)); - - stats->rx_bytes += local_stats.rx_bytes; - stats->rx_packets += local_stats.rx_packets; - stats->tx_bytes += local_stats.tx_bytes; - stats->tx_packets += local_stats.tx_packets; - } + const struct rtnl_link_stats64 *dev_stats; + struct rtnl_link_stats64 temp; + + dev_stats = dev_get_stats(vport->dev, &temp); + stats->rx_errors = dev_stats->rx_errors; + stats->tx_errors = dev_stats->tx_errors; + stats->tx_dropped = dev_stats->tx_dropped; + stats->rx_dropped = dev_stats->rx_dropped; + + stats->rx_bytes = dev_stats->rx_bytes; + stats->rx_packets = dev_stats->rx_packets; + stats->tx_bytes = dev_stats->tx_bytes; + stats->tx_packets = dev_stats->tx_packets; } /** |