check the result of dereferencing base_chain->stats, instead of result of this_cpu_ptr with NULL base_chain->stats maybe be changed to NULL when a chain is updated and a new NULL counter can be attached and we do not need to check returning of this_cpu_ptr since base_chain->stats is from percpu allocator if it is non-NULL, this_cpu_ptr returns a valid value and fix two sparse error by replacing rcu_access_pointer and rcu_dereference with READ_ONCE under rcu_read_lock Thanks for Eric's help to finish this patch Fixes: 009240940e84c1 ("netfilter: nf_tables: don't assume chain stats are set when jumplabel is set") Signed-off-by: Eric Dumazet <eric.dumazet@xxxxxxxxx> Signed-off-by: Zhang Yu <zhangyu31@xxxxxxxxx> Signed-off-by: Li RongQing <lirongqing@xxxxxxxxx> --- v1 -->v2: move the dereferencing under bh disable context, and fix two sparse net/netfilter/nf_tables_core.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c index 2a00aef7b6d4..7dfbc6746846 100644 --- a/net/netfilter/nf_tables_core.c +++ b/net/netfilter/nf_tables_core.c @@ -98,21 +98,23 @@ static noinline void nft_update_chain_stats(const struct nft_chain *chain, const struct nft_pktinfo *pkt) { struct nft_base_chain *base_chain; + struct nft_stats __percpu *pstats; struct nft_stats *stats; base_chain = nft_base_chain(chain); - if (!rcu_access_pointer(base_chain->stats)) - return; - local_bh_disable(); - stats = this_cpu_ptr(rcu_dereference(base_chain->stats)); - if (stats) { + rcu_read_lock(); + pstats = READ_ONCE(base_chain->stats); + if (pstats) { + local_bh_disable(); + stats = this_cpu_ptr(pstats); u64_stats_update_begin(&stats->syncp); stats->pkts++; stats->bytes += pkt->skb->len; u64_stats_update_end(&stats->syncp); + local_bh_enable(); } - local_bh_enable(); + rcu_read_unlock(); } struct nft_jumpstack { -- 2.16.2