On Sat, Dec 10, 2016 at 03:05:41PM +0100, Pablo Neira Ayuso wrote: [...] > -static void nft_counter_reset(struct nft_counter_percpu __percpu *counter, > - struct nft_counter *total) > -{ > - struct nft_counter_percpu *cpu_stats; > - u64 bytes, packets; > - unsigned int seq; > - int cpu; > - > - memset(total, 0, sizeof(*total)); > - for_each_possible_cpu(cpu) { > - bytes = packets = 0; > - > - cpu_stats = per_cpu_ptr(counter, cpu); > - do { > - seq = u64_stats_fetch_begin_irq(&cpu_stats->syncp); > - packets += > __nft_counter_reset(&cpu_stats->counter.packets); > - bytes += > __nft_counter_reset(&cpu_stats->counter.bytes); > - } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, seq)); > - > - total->packets += packets; > - total->bytes += bytes; > + seq = read_seqcount_begin(myseq); > + bytes = this_cpu->bytes; > + packets = this_cpu->packets; > + } while (read_seqcount_retry(myseq, seq)); > + > + total->bytes += bytes; > + total->packets += packets; > + > + if (reset) { > + local_bh_disable(); > + this_cpu->packets -= packets; > + this_cpu->bytes -= bytes; > + local_bh_enable(); > + }
Actually this is not right either, Eric proposed this instead: static void nft_counter_reset(struct nft_counter_percpu __percpu *counter, struct nft_counter *total) { struct nft_counter_percpu *cpu_stats; local_bh_disable(); cpu_stats = this_cpu_ptr(counter); cpu_stats->counter.packets -= total->packets; cpu_stats->counter.bytes -= total->bytes; local_bh_enable(); } The cpu that running over the reset code is guaranteed to own this stats exclusively, but this is not guaranteed by my patch. I'm going to send a v2. I think I need to turn packet and byte counters into s64, otherwise a sufficient large total->packets may underflow and confuse stats.