summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2015-06-26 11:45:09 +0200
committerJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2015-06-26 11:45:09 +0200
commit5a039f6c87073a79fbcdf31af25c6bd4e19ee32c (patch)
tree5993513b9f850e4fbc1f847675920b6cbebb678c
parentdd4330ede7d3e0b3914cfa6ed05bbcee69f7b490 (diff)
Optimize hash creation routine
Exit as easly as possible on error and use RCU_INIT_POINTER() as set is not seen at creation time. Ported from a patch proposed by Sergey Popovich <popovich_sergei@mail.ua>.
-rw-r--r--kernel/net/netfilter/ipset/ip_set_hash_gen.h63
1 files changed, 29 insertions, 34 deletions
diff --git a/kernel/net/netfilter/ipset/ip_set_hash_gen.h b/kernel/net/netfilter/ipset/ip_set_hash_gen.h
index 8dc18c4..44fd3df 100644
--- a/kernel/net/netfilter/ipset/ip_set_hash_gen.h
+++ b/kernel/net/netfilter/ipset/ip_set_hash_gen.h
@@ -1233,41 +1233,35 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
struct htype *h;
struct htable *t;
+ pr_debug("Create set %s with family %s\n",
+ set->name, set->family == NFPROTO_IPV4 ? "inet" : "inet6");
+
#ifndef IP_SET_PROTO_UNDEF
if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
return -IPSET_ERR_INVALID_FAMILY;
#endif
-#ifdef IP_SET_HASH_WITH_MARKMASK
- markmask = 0xffffffff;
-#endif
-#ifdef IP_SET_HASH_WITH_NETMASK
- netmask = set->family == NFPROTO_IPV4 ? 32 : 128;
- pr_debug("Create set %s with family %s\n",
- set->name, set->family == NFPROTO_IPV4 ? "inet" : "inet6");
-#endif
-
if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
return -IPSET_ERR_PROTOCOL;
+
#ifdef IP_SET_HASH_WITH_MARKMASK
/* Separated condition in order to avoid directive in argument list */
if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_MARKMASK)))
return -IPSET_ERR_PROTOCOL;
-#endif
- if (tb[IPSET_ATTR_HASHSIZE]) {
- hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
- if (hashsize < IPSET_MIMINAL_HASHSIZE)
- hashsize = IPSET_MIMINAL_HASHSIZE;
+ markmask = 0xffffffff;
+ if (tb[IPSET_ATTR_MARKMASK]) {
+ markmask = ntohl(nla_get_be32(tb[IPSET_ATTR_MARKMASK]));
+ if (markmask == 0)
+ return -IPSET_ERR_INVALID_MARKMASK;
}
-
- if (tb[IPSET_ATTR_MAXELEM])
- maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
+#endif
#ifdef IP_SET_HASH_WITH_NETMASK
+ netmask = set->family == NFPROTO_IPV4 ? 32 : 128;
if (tb[IPSET_ATTR_NETMASK]) {
netmask = nla_get_u8(tb[IPSET_ATTR_NETMASK]);
@@ -1277,14 +1271,15 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
return -IPSET_ERR_INVALID_NETMASK;
}
#endif
-#ifdef IP_SET_HASH_WITH_MARKMASK
- if (tb[IPSET_ATTR_MARKMASK]) {
- markmask = ntohl(nla_get_be32(tb[IPSET_ATTR_MARKMASK]));
- if (markmask == 0)
- return -IPSET_ERR_INVALID_MARKMASK;
+ if (tb[IPSET_ATTR_HASHSIZE]) {
+ hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
+ if (hashsize < IPSET_MIMINAL_HASHSIZE)
+ hashsize = IPSET_MIMINAL_HASHSIZE;
}
-#endif
+
+ if (tb[IPSET_ATTR_MAXELEM])
+ maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
hsize = sizeof(*h);
#ifdef IP_SET_HASH_WITH_NETS
@@ -1294,16 +1289,6 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
if (!h)
return -ENOMEM;
- h->maxelem = maxelem;
-#ifdef IP_SET_HASH_WITH_NETMASK
- h->netmask = netmask;
-#endif
-#ifdef IP_SET_HASH_WITH_MARKMASK
- h->markmask = markmask;
-#endif
- get_random_bytes(&h->initval, sizeof(h->initval));
- set->timeout = IPSET_NO_TIMEOUT;
-
hbits = htable_bits(hashsize);
hsize = htable_size(hbits);
if (hsize == 0) {
@@ -1315,8 +1300,17 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
kfree(h);
return -ENOMEM;
}
+ h->maxelem = maxelem;
+#ifdef IP_SET_HASH_WITH_NETMASK
+ h->netmask = netmask;
+#endif
+#ifdef IP_SET_HASH_WITH_MARKMASK
+ h->markmask = markmask;
+#endif
+ get_random_bytes(&h->initval, sizeof(h->initval));
+
t->htable_bits = hbits;
- rcu_assign_pointer(h->table, t);
+ RCU_INIT_POINTER(h->table, t);
set->data = h;
#ifndef IP_SET_PROTO_UNDEF
@@ -1332,6 +1326,7 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
sizeof(struct IPSET_TOKEN(HTYPE, 6_elem)));
}
#endif
+ set->timeout = IPSET_NO_TIMEOUT;
if (tb[IPSET_ATTR_TIMEOUT]) {
set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
#ifndef IP_SET_PROTO_UNDEF