ofproto-dpif: Revalidate flows when the group table changes.
[cascardo/ovs.git] / datapath / flow.c
index 9b3d3a7..f4aef71 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2013 Nicira, Inc.
+ * Copyright (c) 2007-2014 Nicira, Inc.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of version 2 of the GNU General Public
@@ -87,17 +87,25 @@ void ovs_flow_stats_update(struct sw_flow *flow, struct sk_buff *skb)
        spin_unlock(&stats->lock);
 }
 
-static void stats_read(struct flow_stats *stats,
+static void stats_read(struct flow_stats *stats, bool lock_bh,
                       struct ovs_flow_stats *ovs_stats,
                       unsigned long *used, __be16 *tcp_flags)
 {
-       spin_lock(&stats->lock);
-       if (time_after(stats->used, *used))
+       if (lock_bh)
+               spin_lock_bh(&stats->lock);
+       else
+               spin_lock(&stats->lock);
+
+       if (!*used || time_after(stats->used, *used))
                *used = stats->used;
        *tcp_flags |= stats->tcp_flags;
        ovs_stats->n_packets += stats->packet_count;
        ovs_stats->n_bytes += stats->byte_count;
-       spin_unlock(&stats->lock);
+
+       if (lock_bh)
+               spin_unlock_bh(&stats->lock);
+       else
+               spin_unlock(&stats->lock);
 }
 
 void ovs_flow_stats_get(struct sw_flow *flow, struct ovs_flow_stats *ovs_stats,
@@ -110,33 +118,38 @@ void ovs_flow_stats_get(struct sw_flow *flow, struct ovs_flow_stats *ovs_stats,
        memset(ovs_stats, 0, sizeof(*ovs_stats));
 
        if (!flow->stats.is_percpu) {
-               stats_read(flow->stats.stat, ovs_stats, used, tcp_flags);
+               stats_read(flow->stats.stat, true, ovs_stats, used, tcp_flags);
        } else {
                cur_cpu = get_cpu();
+
                for_each_possible_cpu(cpu) {
                        struct flow_stats *stats;
-
-                       if (cpu == cur_cpu)
-                               local_bh_disable();
+                       bool lock_bh;
 
                        stats = per_cpu_ptr(flow->stats.cpu_stats, cpu);
-                       stats_read(stats, ovs_stats, used, tcp_flags);
-
-                       if (cpu == cur_cpu)
-                               local_bh_enable();
+                       lock_bh = (cpu == cur_cpu);
+                       stats_read(stats, lock_bh, ovs_stats, used, tcp_flags);
                }
                put_cpu();
        }
 }
 
-static void stats_reset(struct flow_stats *stats)
+static void stats_reset(struct flow_stats *stats, bool lock_bh)
 {
-       spin_lock(&stats->lock);
+       if (lock_bh)
+               spin_lock_bh(&stats->lock);
+       else
+               spin_lock(&stats->lock);
+
        stats->used = 0;
        stats->packet_count = 0;
        stats->byte_count = 0;
        stats->tcp_flags = 0;
-       spin_unlock(&stats->lock);
+
+       if (lock_bh)
+               spin_unlock_bh(&stats->lock);
+       else
+               spin_unlock(&stats->lock);
 }
 
 void ovs_flow_stats_clear(struct sw_flow *flow)
@@ -144,19 +157,15 @@ void ovs_flow_stats_clear(struct sw_flow *flow)
        int cpu, cur_cpu;
 
        if (!flow->stats.is_percpu) {
-               stats_reset(flow->stats.stat);
+               stats_reset(flow->stats.stat, true);
        } else {
                cur_cpu = get_cpu();
 
                for_each_possible_cpu(cpu) {
+                       bool lock_bh;
 
-                       if (cpu == cur_cpu)
-                               local_bh_disable();
-
-                       stats_reset(per_cpu_ptr(flow->stats.cpu_stats, cpu));
-
-                       if (cpu == cur_cpu)
-                               local_bh_enable();
+                       lock_bh = (cpu == cur_cpu);
+                       stats_reset(per_cpu_ptr(flow->stats.cpu_stats, cpu), lock_bh);
                }
                put_cpu();
        }