Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: xt_statistic: remove nth_lock spinlock

Use atomic_cmpxchg() to avoid dirtying a shared location.

xt_statistic_priv smp aligned to avoid sharing same cache line with
other stuff.

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Patrick McHardy <kaber@trash.net>

authored by

Eric Dumazet and committed by
Patrick McHardy
fabf3a85 a8b56389

+9 -10
+9 -10
net/netfilter/xt_statistic.c
··· 18 18 #include <linux/netfilter/x_tables.h> 19 19 20 20 struct xt_statistic_priv { 21 - uint32_t count; 22 - }; 21 + atomic_t count; 22 + } ____cacheline_aligned_in_smp; 23 23 24 24 MODULE_LICENSE("GPL"); 25 25 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); ··· 27 27 MODULE_ALIAS("ipt_statistic"); 28 28 MODULE_ALIAS("ip6t_statistic"); 29 29 30 - static DEFINE_SPINLOCK(nth_lock); 31 - 32 30 static bool 33 31 statistic_mt(const struct sk_buff *skb, struct xt_action_param *par) 34 32 { 35 33 const struct xt_statistic_info *info = par->matchinfo; 36 34 bool ret = info->flags & XT_STATISTIC_INVERT; 35 + int nval, oval; 37 36 38 37 switch (info->mode) { 39 38 case XT_STATISTIC_MODE_RANDOM: ··· 40 41 ret = !ret; 41 42 break; 42 43 case XT_STATISTIC_MODE_NTH: 43 - spin_lock_bh(&nth_lock); 44 - if (info->master->count++ == info->u.nth.every) { 45 - info->master->count = 0; 44 + do { 45 + oval = atomic_read(&info->master->count); 46 + nval = (oval == info->u.nth.every) ? 0 : oval + 1; 47 + } while (atomic_cmpxchg(&info->master->count, oval, nval) != oval); 48 + if (nval == 0) 46 49 ret = !ret; 47 - } 48 - spin_unlock_bh(&nth_lock); 49 50 break; 50 51 } 51 52 ··· 63 64 info->master = kzalloc(sizeof(*info->master), GFP_KERNEL); 64 65 if (info->master == NULL) 65 66 return -ENOMEM; 66 - info->master->count = info->u.nth.count; 67 + atomic_set(&info->master->count, info->u.nth.count); 67 68 68 69 return 0; 69 70 }