Commit a778a15f authored by Florian Westphal's avatar Florian Westphal Committed by Pablo Neira Ayuso

netfilter: ipset: add resched points during set listing

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: default avatarLi Shuang <shuali@redhat.com>
Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Acked-by: default avatarJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 49971b88
...@@ -227,6 +227,7 @@ mtype_list(const struct ip_set *set, ...@@ -227,6 +227,7 @@ mtype_list(const struct ip_set *set,
rcu_read_lock(); rcu_read_lock();
for (; cb->args[IPSET_CB_ARG0] < map->elements; for (; cb->args[IPSET_CB_ARG0] < map->elements;
cb->args[IPSET_CB_ARG0]++) { cb->args[IPSET_CB_ARG0]++) {
cond_resched_rcu();
id = cb->args[IPSET_CB_ARG0]; id = cb->args[IPSET_CB_ARG0];
x = get_ext(set, map, id); x = get_ext(set, map, id);
if (!test_bit(id, map->members) || if (!test_bit(id, map->members) ||
......
...@@ -1388,9 +1388,7 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -1388,9 +1388,7 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
set->variant->uref(set, cb, true); set->variant->uref(set, cb, true);
/* fall through */ /* fall through */
default: default:
rcu_read_lock_bh();
ret = set->variant->list(set, skb, cb); ret = set->variant->list(set, skb, cb);
rcu_read_unlock_bh();
if (!cb->args[IPSET_CB_ARG0]) if (!cb->args[IPSET_CB_ARG0])
/* Set is done, proceed with next one */ /* Set is done, proceed with next one */
goto next_set; goto next_set;
......
...@@ -1143,6 +1143,7 @@ mtype_list(const struct ip_set *set, ...@@ -1143,6 +1143,7 @@ mtype_list(const struct ip_set *set,
rcu_read_lock(); rcu_read_lock();
for (; cb->args[IPSET_CB_ARG0] < jhash_size(t->htable_bits); for (; cb->args[IPSET_CB_ARG0] < jhash_size(t->htable_bits);
cb->args[IPSET_CB_ARG0]++) { cb->args[IPSET_CB_ARG0]++) {
cond_resched_rcu();
incomplete = skb_tail_pointer(skb); incomplete = skb_tail_pointer(skb);
n = rcu_dereference(hbucket(t, cb->args[IPSET_CB_ARG0])); n = rcu_dereference(hbucket(t, cb->args[IPSET_CB_ARG0]));
pr_debug("cb->arg bucket: %lu, t %p n %p\n", pr_debug("cb->arg bucket: %lu, t %p n %p\n",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment