[PATCH 4.9 62/86] netfilter: x_tables: pass xt_counters struct to counter allocator
From: Greg Kroah-Hartman
Date: Fri Mar 16 2018 - 13:02:33 EST
4.9-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <fw@xxxxxxxxx>
commit f28e15bacedd444608e25421c72eb2cf4527c9ca upstream.
Keeps some noise away from a followup patch.
Signed-off-by: Florian Westphal <fw@xxxxxxxxx>
Acked-by: Eric Dumazet <edumazet@xxxxxxxxxx>
Signed-off-by: Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
---
include/linux/netfilter/x_tables.h | 27 +--------------------------
net/ipv4/netfilter/arp_tables.c | 5 +----
net/ipv4/netfilter/ip_tables.c | 5 +----
net/ipv6/netfilter/ip6_tables.c | 5 +----
net/netfilter/x_tables.c | 30 ++++++++++++++++++++++++++++++
5 files changed, 34 insertions(+), 38 deletions(-)
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -376,32 +376,7 @@ static inline unsigned long ifname_compa
}
-/* On SMP, ip(6)t_entry->counters.pcnt holds address of the
- * real (percpu) counter. On !SMP, its just the packet count,
- * so nothing needs to be done there.
- *
- * xt_percpu_counter_alloc returns the address of the percpu
- * counter, or 0 on !SMP. We force an alignment of 16 bytes
- * so that bytes/packets share a common cache line.
- *
- * Hence caller must use IS_ERR_VALUE to check for error, this
- * allows us to return 0 for single core systems without forcing
- * callers to deal with SMP vs. NONSMP issues.
- */
-static inline unsigned long xt_percpu_counter_alloc(void)
-{
- if (nr_cpu_ids > 1) {
- void __percpu *res = __alloc_percpu(sizeof(struct xt_counters),
- sizeof(struct xt_counters));
-
- if (res == NULL)
- return -ENOMEM;
-
- return (__force unsigned long) res;
- }
-
- return 0;
-}
+bool xt_percpu_counter_alloc(struct xt_counters *counters);
void xt_percpu_counter_free(struct xt_counters *cnt);
static inline struct xt_counters *
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -423,13 +423,10 @@ find_check_entry(struct arpt_entry *e, c
{
struct xt_entry_target *t;
struct xt_target *target;
- unsigned long pcnt;
int ret;
- pcnt = xt_percpu_counter_alloc();
- if (IS_ERR_VALUE(pcnt))
+ if (!xt_percpu_counter_alloc(&e->counters))
return -ENOMEM;
- e->counters.pcnt = pcnt;
t = arpt_get_target(e);
target = xt_request_find_target(NFPROTO_ARP, t->u.user.name,
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -548,12 +548,9 @@ find_check_entry(struct ipt_entry *e, st
unsigned int j;
struct xt_mtchk_param mtpar;
struct xt_entry_match *ematch;
- unsigned long pcnt;
- pcnt = xt_percpu_counter_alloc();
- if (IS_ERR_VALUE(pcnt))
+ if (!xt_percpu_counter_alloc(&e->counters))
return -ENOMEM;
- e->counters.pcnt = pcnt;
j = 0;
mtpar.net = net;
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -578,12 +578,9 @@ find_check_entry(struct ip6t_entry *e, s
unsigned int j;
struct xt_mtchk_param mtpar;
struct xt_entry_match *ematch;
- unsigned long pcnt;
- pcnt = xt_percpu_counter_alloc();
- if (IS_ERR_VALUE(pcnt))
+ if (!xt_percpu_counter_alloc(&e->counters))
return -ENOMEM;
- e->counters.pcnt = pcnt;
j = 0;
mtpar.net = net;
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -1619,6 +1619,36 @@ void xt_proto_fini(struct net *net, u_in
}
EXPORT_SYMBOL_GPL(xt_proto_fini);
+/**
+ * xt_percpu_counter_alloc - allocate x_tables rule counter
+ *
+ * @counter: pointer to counter struct inside the ip(6)/arpt_entry struct
+ *
+ * On SMP, the packet counter [ ip(6)t_entry->counters.pcnt ] will then
+ * contain the address of the real (percpu) counter.
+ *
+ * Rule evaluation needs to use xt_get_this_cpu_counter() helper
+ * to fetch the real percpu counter.
+ *
+ * returns false on error.
+ */
+bool xt_percpu_counter_alloc(struct xt_counters *counter)
+{
+ void __percpu *res;
+
+ if (nr_cpu_ids <= 1)
+ return true;
+
+ res = __alloc_percpu(sizeof(struct xt_counters),
+ sizeof(struct xt_counters));
+ if (!res)
+ return false;
+
+ counter->pcnt = (__force unsigned long)res;
+ return true;
+}
+EXPORT_SYMBOL_GPL(xt_percpu_counter_alloc);
+
void xt_percpu_counter_free(struct xt_counters *counters)
{
unsigned long pcnt = counters->pcnt;