diff options
author | Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | 2015-06-13 21:26:14 +0200 |
---|---|---|
committer | Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | 2015-06-13 21:26:14 +0200 |
commit | 9d211d74380cbf796e10f1bc2af141270aad9e63 (patch) | |
tree | 79b94f4b83ea59b4ad52be825279dde2bd2ad310 | |
parent | 44453813357837ba9e966f6ed861e9954a02f0db (diff) |
Fix error path in mtype_resize() when new hash bucket cannot be allocated
Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
-rw-r--r-- | kernel/net/netfilter/ipset/ip_set_hash_gen.h | 25 |
1 files changed, 15 insertions, 10 deletions
diff --git a/kernel/net/netfilter/ipset/ip_set_hash_gen.h b/kernel/net/netfilter/ipset/ip_set_hash_gen.h index 4094065..f8e82c2 100644 --- a/kernel/net/netfilter/ipset/ip_set_hash_gen.h +++ b/kernel/net/netfilter/ipset/ip_set_hash_gen.h @@ -595,6 +595,7 @@ retry: spin_lock_bh(&set->lock); orig = __ipset_dereference_protected(h->table, 1); + /* There can't be another parallel resizing, but dumping is possible */ atomic_set(&orig->ref, 1); atomic_inc(&orig->uref); pr_debug("attempt to resize set %s from %u to %u, t %p\n", @@ -622,8 +623,10 @@ retry: m = kzalloc(sizeof(*m) + AHASH_INIT_SIZE * dsize, GFP_ATOMIC); - if (!m) + if (!m) { ret = -ENOMEM; + goto cleanup; + } m->size = AHASH_INIT_SIZE; RCU_INIT_POINTER(hbucket(t, key), m); } else if (m->pos >= m->size) { @@ -639,15 +642,8 @@ retry: if (!ht) ret = -ENOMEM; } - if (ret < 0) { - atomic_set(&orig->ref, 0); - atomic_dec(&orig->uref); - spin_unlock_bh(&set->lock); - mtype_ahash_destroy(set, t, false); - if (ret == -EAGAIN) - goto retry; - goto out; - } + if (ret < 0) + goto cleanup; memcpy(ht, m, sizeof(struct hbucket) + m->size * dsize); ht->size = m->size + AHASH_INIT_SIZE; @@ -683,6 +679,15 @@ out: kfree(tmp); #endif return ret; + +cleanup: + atomic_set(&orig->ref, 0); + atomic_dec(&orig->uref); + spin_unlock_bh(&set->lock); + mtype_ahash_destroy(set, t, false); + if (ret == -EAGAIN) + goto retry; + goto out; } /* Add an element to a hash and update the internal counters when succeeded, |