aboutsummaryrefslogtreecommitdiffstats
path: root/net/openvswitch
diff options
context:
space:
mode:
authorJarno Rajahalme <jrajahalme@nicira.com>2014-05-05 17:17:28 -0400
committerPravin B Shelar <pshelar@nicira.com>2014-05-22 19:27:35 -0400
commit86ec8dbae27e5fa2b5d54f10f77286d9ef55732a (patch)
treea7234f03654ede89bb75297de731d79126556daf /net/openvswitch
parenteb07265904d6ee95497aba0f3cbd2ae6d9c39a97 (diff)
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>
Diffstat (limited to 'net/openvswitch')
-rw-r--r--net/openvswitch/flow.c10
-rw-r--r--net/openvswitch/flow.h6
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:
122 spin_unlock(&stats->lock); 122 spin_unlock(&stats->lock);
123} 123}
124 124
125/* Called with ovs_mutex. */ 125/* Must be called with rcu_read_lock or ovs_mutex. */
126void ovs_flow_stats_get(struct sw_flow *flow, struct ovs_flow_stats *ovs_stats, 126void ovs_flow_stats_get(const struct sw_flow *flow,
127 struct ovs_flow_stats *ovs_stats,
127 unsigned long *used, __be16 *tcp_flags) 128 unsigned long *used, __be16 *tcp_flags)
128{ 129{
129 int node; 130 int node;
@@ -133,7 +134,7 @@ void ovs_flow_stats_get(struct sw_flow *flow, struct ovs_flow_stats *ovs_stats,
133 memset(ovs_stats, 0, sizeof(*ovs_stats)); 134 memset(ovs_stats, 0, sizeof(*ovs_stats));
134 135
135 for_each_node(node) { 136 for_each_node(node) {
136 struct flow_stats *stats = ovsl_dereference(flow->stats[node]); 137 struct flow_stats *stats = rcu_dereference_ovsl(flow->stats[node]);
137 138
138 if (stats) { 139 if (stats) {
139 /* Local CPU may write on non-local stats, so we must 140 /* 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,
150 } 151 }
151} 152}
152 153
154/* Called with ovs_mutex. */
153void ovs_flow_stats_clear(struct sw_flow *flow) 155void ovs_flow_stats_clear(struct sw_flow *flow)
154{ 156{
155 int node; 157 int node;
156 158
157 for_each_node(node) { 159 for_each_node(node) {
158 struct flow_stats *stats = rcu_dereference(flow->stats[node]); 160 struct flow_stats *stats = ovsl_dereference(flow->stats[node]);
159 161
160 if (stats) { 162 if (stats) {
161 spin_lock_bh(&stats->lock); 163 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 {
180 unsigned char ar_tip[4]; /* target IP address */ 180 unsigned char ar_tip[4]; /* target IP address */
181} __packed; 181} __packed;
182 182
183void ovs_flow_stats_update(struct sw_flow *flow, struct sk_buff *skb); 183void ovs_flow_stats_update(struct sw_flow *, struct sk_buff *);
184void ovs_flow_stats_get(struct sw_flow *flow, struct ovs_flow_stats *stats, 184void ovs_flow_stats_get(const struct sw_flow *, struct ovs_flow_stats *,
185 unsigned long *used, __be16 *tcp_flags); 185 unsigned long *used, __be16 *tcp_flags);
186void ovs_flow_stats_clear(struct sw_flow *flow); 186void ovs_flow_stats_clear(struct sw_flow *);
187u64 ovs_flow_used_time(unsigned long flow_jiffies); 187u64 ovs_flow_used_time(unsigned long flow_jiffies);
188 188
189int ovs_flow_extract(struct sk_buff *, u16 in_port, struct sw_flow_key *); 189int ovs_flow_extract(struct sk_buff *, u16 in_port, struct sw_flow_key *);