mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-15 15:04:27 +08:00
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: Li Shuang <shuali@redhat.com> Signed-off-by: Florian Westphal <fw@strlen.de> Acked-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
parent
49971b8853
commit
a778a15fa5
@ -227,6 +227,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) ||
|
||||
|
@ -1388,9 +1388,7 @@ dump_last:
|
||||
set->variant->uref(set, cb, true);
|
||||
/* fall through */
|
||||
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;
|
||||
|
@ -1143,6 +1143,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",
|
||||
|
Loading…
Reference in New Issue
Block a user