]> granicus.if.org Git - ipset/commitdiff
Optimize hash creation routine
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Fri, 26 Jun 2015 09:45:09 +0000 (11:45 +0200)
committerJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Fri, 26 Jun 2015 09:45:09 +0000 (11:45 +0200)
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>.

kernel/net/netfilter/ipset/ip_set_hash_gen.h

index 8dc18c4209e0be96733dcd2cf7ff11829565c563..44fd3dfc359b7cb438399d94a679123787800e62 100644 (file)
@@ -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