summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2015-06-13 21:26:14 +0200
committerJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2015-06-13 21:26:14 +0200
commit9d211d74380cbf796e10f1bc2af141270aad9e63 (patch)
tree79b94f4b83ea59b4ad52be825279dde2bd2ad310 /kernel
parent44453813357837ba9e966f6ed861e9954a02f0db (diff)
Fix error path in mtype_resize() when new hash bucket cannot be allocated
Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/net/netfilter/ipset/ip_set_hash_gen.h25
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,