Subject: [PATCH 5/6] netfilter: use sequence number synchronization for counters

From: Stephen Hemminger <[email-masked]>
Date: Fri, 30 Jan 2009 13:57:05 -0800

Change how synchronization is done on the iptables counters. Use seqcount
wrapper instead of depending on reader/writer lock.

Signed-off-by: Stephen Hemminger <[email-masked]>

--- a/net/netfilter/x_tables.c	2009-01-30 09:15:52.648542116 -0800
+++ b/net/netfilter/x_tables.c	2009-01-30 09:17:03.669061821 -0800
@@ -577,18 +577,36 @@ int xt_compat_target_to_user(struct xt_e
 EXPORT_SYMBOL_GPL(xt_compat_target_to_user);
 #endif
 
+static DEFINE_PER_CPU(seqcount_t, xt_counter_sequence);
+
+/* Update the counters on the current CPU. preempt must be disabled. */
 void xt_add_counter(struct xt_counters *c, unsigned b, unsigned p)
 {
+	seqcount_t *seq = &__get_cpu_var(xt_counter_sequence);
+
+	write_seqcount_begin(seq);
 	c->bcnt += b;
 	c->pcnt += p;
+	write_seqcount_end(seq);
 }
 EXPORT_SYMBOL_GPL(xt_add_counter);
 
+/* Fetch counters on other CPU. */
 void xt_sum_counter(struct xt_counters *t, int cpu,
 		    const struct xt_counters *c)
 {
-	t->pcnt += c->pcnt;
-	t->bcnt += c->bcnt;
+	seqcount_t *seq = &per_cpu(xt_counter_sequence, cpu);
+	unsigned start;
+	struct xt_counters v;
+
+	/* Atomic fetch of counter value */
+	do {
+		start = read_seqcount_begin(seq);
+		v = *c;
+	} while (read_seqcount_retry(seq, start));
+
+	t->pcnt += v.pcnt;
+	t->bcnt += v.bcnt;
 }
 EXPORT_SYMBOL_GPL(xt_sum_counter);

--