mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 04:34:03 +02:00
netfilter: ipset: switch ext_size to atomic64_t
The hash types do not acquire set->lock, they use 'region locking' where
only part of the hash table is locked. Parallel inserts and deletes are
possible and CPUs can race on ->ext_size update. Switch to atomic64_t.
This leaves another bug unresolved: there still can be a race on
comment extension re-init. This will be handled in a later commit
when converting to rhashtable backend.
Fixes: f66ee0410b ("netfilter: ipset: Fix "INFO: rcu detected stall in hash_xxx" reports")
Signed-off-by: Jozsef Kadlecsik <kadlec@netfilter.org>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
parent
8e5fd2a55e
commit
712a6f545c
|
|
@ -273,7 +273,7 @@ struct ip_set {
|
|||
/* Number of elements (vs timeout) */
|
||||
u32 elements;
|
||||
/* Size of the dynamic extensions (vs timeout) */
|
||||
size_t ext_size;
|
||||
atomic64_t ext_size;
|
||||
/* Element data size */
|
||||
size_t dsize;
|
||||
/* Offsets to extensions in elements */
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ mtype_flush(struct ip_set *set)
|
|||
mtype_ext_cleanup(set);
|
||||
bitmap_zero(map->members, map->elements);
|
||||
set->elements = 0;
|
||||
set->ext_size = 0;
|
||||
atomic64_set(&set->ext_size, 0);
|
||||
}
|
||||
|
||||
/* Calculate the actual memory size of the set data */
|
||||
|
|
@ -93,7 +93,7 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)
|
|||
{
|
||||
const struct mtype *map = set->data;
|
||||
struct nlattr *nested;
|
||||
size_t memsize = mtype_memsize(map, set->dsize) + set->ext_size;
|
||||
size_t memsize = mtype_memsize(map, set->dsize) + atomic64_read(&set->ext_size);
|
||||
|
||||
nested = nla_nest_start(skb, IPSET_ATTR_DATA);
|
||||
if (!nested)
|
||||
|
|
|
|||
|
|
@ -350,7 +350,7 @@ ip_set_init_comment(struct ip_set *set, struct ip_set_comment *comment,
|
|||
size_t len = ext->comment ? strlen(ext->comment) : 0;
|
||||
|
||||
if (unlikely(c)) {
|
||||
set->ext_size -= sizeof(*c) + strlen(c->str) + 1;
|
||||
atomic64_sub(sizeof(*c) + strlen(c->str) + 1, &set->ext_size);
|
||||
rcu_assign_pointer(comment->c, NULL);
|
||||
kfree_rcu(c, rcu);
|
||||
}
|
||||
|
|
@ -362,7 +362,7 @@ ip_set_init_comment(struct ip_set *set, struct ip_set_comment *comment,
|
|||
if (unlikely(!c))
|
||||
return;
|
||||
strscpy(c->str, ext->comment, len + 1);
|
||||
set->ext_size += sizeof(*c) + strlen(c->str) + 1;
|
||||
atomic64_add(sizeof(*c) + strlen(c->str) + 1, &set->ext_size);
|
||||
rcu_assign_pointer(comment->c, c);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ip_set_init_comment);
|
||||
|
|
@ -392,7 +392,7 @@ ip_set_comment_free(struct ip_set *set, void *ptr)
|
|||
c = rcu_dereference_protected(comment->c, 1);
|
||||
if (unlikely(!c))
|
||||
return;
|
||||
set->ext_size -= sizeof(*c) + strlen(c->str) + 1;
|
||||
atomic64_sub(sizeof(*c) + strlen(c->str) + 1, &set->ext_size);
|
||||
rcu_assign_pointer(comment->c, NULL);
|
||||
kfree_rcu(c, rcu);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1373,7 +1373,7 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)
|
|||
rcu_read_lock_bh();
|
||||
t = rcu_dereference_bh(h->table);
|
||||
mtype_ext_size(set, &elements, &ext_size);
|
||||
memsize = mtype_ahash_memsize(h, t) + ext_size + set->ext_size;
|
||||
memsize = mtype_ahash_memsize(h, t) + ext_size + atomic64_read(&set->ext_size);
|
||||
htable_bits = t->htable_bits;
|
||||
rcu_read_unlock_bh();
|
||||
|
||||
|
|
|
|||
|
|
@ -421,7 +421,7 @@ list_set_flush(struct ip_set *set)
|
|||
list_for_each_entry_safe(e, n, &map->members, list)
|
||||
list_set_del(set, e);
|
||||
set->elements = 0;
|
||||
set->ext_size = 0;
|
||||
atomic64_set(&set->ext_size, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -455,7 +455,7 @@ list_set_head(struct ip_set *set, struct sk_buff *skb)
|
|||
{
|
||||
const struct list_set *map = set->data;
|
||||
struct nlattr *nested;
|
||||
size_t memsize = list_set_memsize(map, set->dsize) + set->ext_size;
|
||||
size_t memsize = list_set_memsize(map, set->dsize) + atomic64_read(&set->ext_size);
|
||||
|
||||
nested = nla_nest_start(skb, IPSET_ATTR_DATA);
|
||||
if (!nested)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user