|
@@ -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,9 +112,18 @@ 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;
|