]> granicus.if.org Git - ipset/commitdiff
netfilter: ipset: add resched points during set listing
authorFlorian Westphal <fw@strlen.de>
Thu, 4 Jan 2018 12:24:44 +0000 (13:24 +0100)
committerJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Thu, 4 Jan 2018 12:24:44 +0000 (13:24 +0100)
When sets are extremely large we can get softlockup during ipset -L.
We could fix this by adding cond_resched_rcu() at the right location
during iteration, but this only works if RCU nesting depth is 1.

At this time entire variant->list() is called under under rcu_read_lock_bh.
This used to be a read_lock_bh() but as rcu doesn't really lock anything,
it does not appear to be needed, so remove it (ipset increments set
reference count before this, so a set deletion should not be possible).

Reported-by: Li Shuang <shuali@redhat.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
kernel/net/netfilter/ipset/ip_set_bitmap_gen.h
kernel/net/netfilter/ipset/ip_set_core.c
kernel/net/netfilter/ipset/ip_set_hash_gen.h

index 0c9db1937eb4cb767677ca6be27f3edfcb9a11db..4c42e92f7d43eab65466b5cafef8b129ff8f2381 100644 (file)
@@ -222,6 +222,7 @@ mtype_list(const struct ip_set *set,
        rcu_read_lock();
        for (; cb->args[IPSET_CB_ARG0] < map->elements;
             cb->args[IPSET_CB_ARG0]++) {
+               cond_resched_rcu();
                id = cb->args[IPSET_CB_ARG0];
                x = get_ext(set, map, id);
                if (!test_bit(id, map->members) ||
index 134e708e224c6299cc4456ce195ed303e13fe6ac..d25dd463a63261e57060b392c08f300dbb3d17f9 100644 (file)
@@ -1425,9 +1425,7 @@ dump_last:
                                set->variant->uref(set, cb, true);
                        /* Fall through and add elements */
                default:
-                       rcu_read_lock_bh();
                        ret = set->variant->list(set, skb, cb);
-                       rcu_read_unlock_bh();
                        if (!cb->args[IPSET_CB_ARG0])
                                /* Set is done, proceed with next one */
                                goto next_set;
index 291c7d4fb0b1564ecb28fe870df97ede16985a7d..49a59583478e1c0a40e0a191a53e0c6ea60e36f2 100644 (file)
@@ -1136,6 +1136,7 @@ mtype_list(const struct ip_set *set,
        rcu_read_lock();
        for (; cb->args[IPSET_CB_ARG0] < jhash_size(t->htable_bits);
             cb->args[IPSET_CB_ARG0]++) {
+               cond_resched_rcu();
                incomplete = skb_tail_pointer(skb);
                n = rcu_dereference(hbucket(t, cb->args[IPSET_CB_ARG0]));
                pr_debug("cb->arg bucket: %lu, t %p n %p\n",