diff options
author | Jarno Rajahalme <jrajahalme@nicira.com> | 2014-05-05 14:17:28 -0700 |
---|---|---|
committer | Pravin B Shelar <pshelar@nicira.com> | 2014-05-22 16:27:35 -0700 |
commit | 86ec8dbae27e5fa2b5d54f10f77286d9ef55732a (patch) | |
tree | a7234f03654ede89bb75297de731d79126556daf | |
parent | eb07265904d6ee95497aba0f3cbd2ae6d9c39a97 (diff) | |
download | linux-86ec8dbae27e5fa2b5d54f10f77286d9ef55732a.tar.gz linux-86ec8dbae27e5fa2b5d54f10f77286d9ef55732a.tar.bz2 linux-86ec8dbae27e5fa2b5d54f10f77286d9ef55732a.zip |
openvswitch: Fix ovs_flow_stats_get/clear RCU dereference.
For ovs_flow_stats_get() using ovsl_dereference() was wrong, since
flow dumps call this with RCU read lock.
ovs_flow_stats_clear() is always called with ovs_mutex, so can use
ovsl_dereference().
Also, make the ovs_flow_stats_get() 'flow' argument const to make
later patches cleaner.
Signed-off-by: Jarno Rajahalme <jrajahalme@nicira.com>
Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
-rw-r--r-- | net/openvswitch/flow.c | 10 | ||||
-rw-r--r-- | net/openvswitch/flow.h | 6 |
2 files changed, 9 insertions, 7 deletions
diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c index 1019fc1db06e..334751cb1528 100644 --- a/net/openvswitch/flow.c +++ b/net/openvswitch/flow.c @@ -122,8 +122,9 @@ unlock: spin_unlock(&stats->lock); } -/* Called with ovs_mutex. */ -void ovs_flow_stats_get(struct sw_flow *flow, struct ovs_flow_stats *ovs_stats, +/* Must be called with rcu_read_lock or ovs_mutex. */ +void ovs_flow_stats_get(const struct sw_flow *flow, + struct ovs_flow_stats *ovs_stats, unsigned long *used, __be16 *tcp_flags) { int node; @@ -133,7 +134,7 @@ void ovs_flow_stats_get(struct sw_flow *flow, struct ovs_flow_stats *ovs_stats, memset(ovs_stats, 0, sizeof(*ovs_stats)); for_each_node(node) { - struct flow_stats *stats = ovsl_dereference(flow->stats[node]); + struct flow_stats *stats = rcu_dereference_ovsl(flow->stats[node]); if (stats) { /* Local CPU may write on non-local stats, so we must @@ -150,12 +151,13 @@ void ovs_flow_stats_get(struct sw_flow *flow, struct ovs_flow_stats *ovs_stats, } } +/* Called with ovs_mutex. */ void ovs_flow_stats_clear(struct sw_flow *flow) { int node; for_each_node(node) { - struct flow_stats *stats = rcu_dereference(flow->stats[node]); + struct flow_stats *stats = ovsl_dereference(flow->stats[node]); if (stats) { spin_lock_bh(&stats->lock); diff --git a/net/openvswitch/flow.h b/net/openvswitch/flow.h index a292bf8ad75c..ac395d2cd821 100644 --- a/net/openvswitch/flow.h +++ b/net/openvswitch/flow.h @@ -180,10 +180,10 @@ struct arp_eth_header { unsigned char ar_tip[4]; /* target IP address */ } __packed; -void ovs_flow_stats_update(struct sw_flow *flow, struct sk_buff *skb); -void ovs_flow_stats_get(struct sw_flow *flow, struct ovs_flow_stats *stats, +void ovs_flow_stats_update(struct sw_flow *, struct sk_buff *); +void ovs_flow_stats_get(const struct sw_flow *, struct ovs_flow_stats *, unsigned long *used, __be16 *tcp_flags); -void ovs_flow_stats_clear(struct sw_flow *flow); +void ovs_flow_stats_clear(struct sw_flow *); u64 ovs_flow_used_time(unsigned long flow_jiffies); int ovs_flow_extract(struct sk_buff *, u16 in_port, struct sw_flow_key *); |