]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - net/netfilter/nft_set_hash.c
Merge branches 'work.namei', 'work.dcache' and 'work.iov_iter' into for-linus
[mirror_ubuntu-artful-kernel.git] / net / netfilter / nft_set_hash.c
index 3794cb2fc78876ce02eb35992cb0113d498367ba..a3dface3e6e6895e3d778c9378d4579b5723811d 100644 (file)
@@ -98,7 +98,7 @@ static bool nft_hash_update(struct nft_set *set, const u32 *key,
                            const struct nft_set_ext **ext)
 {
        struct nft_hash *priv = nft_set_priv(set);
-       struct nft_hash_elem *he;
+       struct nft_hash_elem *he, *prev;
        struct nft_hash_cmp_arg arg = {
                .genmask = NFT_GENMASK_ANY,
                .set     = set,
@@ -112,15 +112,24 @@ static bool nft_hash_update(struct nft_set *set, const u32 *key,
        he = new(set, expr, regs);
        if (he == NULL)
                goto err1;
-       if (rhashtable_lookup_insert_key(&priv->ht, &arg, &he->node,
-                                        nft_hash_params))
+
+       prev = rhashtable_lookup_get_insert_key(&priv->ht, &arg, &he->node,
+                                               nft_hash_params);
+       if (IS_ERR(prev))
                goto err2;
+
+       /* Another cpu may race to insert the element with the same key */
+       if (prev) {
+               nft_set_elem_destroy(set, he, true);
+               he = prev;
+       }
+
 out:
        *ext = &he->ext;
        return true;
 
 err2:
-       nft_set_elem_destroy(set, he);
+       nft_set_elem_destroy(set, he, true);
 err1:
        return false;
 }
@@ -332,7 +341,7 @@ static int nft_hash_init(const struct nft_set *set,
 
 static void nft_hash_elem_destroy(void *ptr, void *arg)
 {
-       nft_set_elem_destroy((const struct nft_set *)arg, ptr);
+       nft_set_elem_destroy((const struct nft_set *)arg, ptr, true);
 }
 
 static void nft_hash_destroy(const struct nft_set *set)