Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

nft_hash: Remove rhashtable_remove_pprev()

The removal function of nft_hash currently stores a reference to the
previous element during lookup which is used to optimize removal later
on. This was possible because a lock is held throughout calling
rhashtable_lookup() and rhashtable_remove().

With the introdution of deferred table resizing in parallel to lookups
and insertions, the nftables lock will no longer synchronize all
table mutations and the stored pprev may become invalid.

Removing this optimization makes removal slightly more expensive on
average but allows taking the resize cost out of the insert and
remove path.

Signed-off-by: Thomas Graf <tgraf@suug.ch>
Cc: netfilter-devel@vger.kernel.org
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Thomas Graf and committed by
David S. Miller
897362e4 b8e1943e

+10 -37
-2
include/linux/rhashtable.h
··· 105 105 106 106 void rhashtable_insert(struct rhashtable *ht, struct rhash_head *node); 107 107 bool rhashtable_remove(struct rhashtable *ht, struct rhash_head *node); 108 - void rhashtable_remove_pprev(struct rhashtable *ht, struct rhash_head *obj, 109 - struct rhash_head __rcu **pprev); 110 108 111 109 bool rht_grow_above_75(const struct rhashtable *ht, size_t new_size); 112 110 bool rht_shrink_below_30(const struct rhashtable *ht, size_t new_size);
+7 -27
lib/rhashtable.c
··· 345 345 EXPORT_SYMBOL_GPL(rhashtable_insert); 346 346 347 347 /** 348 - * rhashtable_remove_pprev - remove object from hash table given previous element 349 - * @ht: hash table 350 - * @obj: pointer to hash head inside object 351 - * @pprev: pointer to previous element 352 - * 353 - * Identical to rhashtable_remove() but caller is alreayd aware of the element 354 - * in front of the element to be deleted. This is in particular useful for 355 - * deletion when combined with walking or lookup. 356 - */ 357 - void rhashtable_remove_pprev(struct rhashtable *ht, struct rhash_head *obj, 358 - struct rhash_head __rcu **pprev) 359 - { 360 - struct bucket_table *tbl = rht_dereference(ht->tbl, ht); 361 - 362 - ASSERT_RHT_MUTEX(ht); 363 - 364 - RCU_INIT_POINTER(*pprev, obj->next); 365 - ht->nelems--; 366 - 367 - if (ht->p.shrink_decision && 368 - ht->p.shrink_decision(ht, tbl->size)) 369 - rhashtable_shrink(ht); 370 - } 371 - EXPORT_SYMBOL_GPL(rhashtable_remove_pprev); 372 - 373 - /** 374 348 * rhashtable_remove - remove object from hash table 375 349 * @ht: hash table 376 350 * @obj: pointer to hash head inside object ··· 377 403 continue; 378 404 } 379 405 380 - rhashtable_remove_pprev(ht, he, pprev); 406 + RCU_INIT_POINTER(*pprev, he->next); 407 + ht->nelems--; 408 + 409 + if (ht->p.shrink_decision && 410 + ht->p.shrink_decision(ht, tbl->size)) 411 + rhashtable_shrink(ht); 412 + 381 413 return true; 382 414 } 383 415
+3 -8
net/netfilter/nft_hash.c
··· 83 83 const struct nft_set_elem *elem) 84 84 { 85 85 struct rhashtable *priv = nft_set_priv(set); 86 - struct rhash_head *he, __rcu **pprev; 87 86 88 - pprev = elem->cookie; 89 - he = rht_dereference((*pprev), priv); 90 - 91 - rhashtable_remove_pprev(priv, he, pprev); 92 - 87 + rhashtable_remove(priv, elem->cookie); 93 88 synchronize_rcu(); 94 - kfree(he); 89 + kfree(elem->cookie); 95 90 } 96 91 97 92 struct nft_compare_arg { ··· 100 105 struct nft_compare_arg *x = arg; 101 106 102 107 if (!nft_data_cmp(&he->key, &x->elem->key, x->set->klen)) { 103 - x->elem->cookie = &he->node; 108 + x->elem->cookie = he; 104 109 x->elem->flags = 0; 105 110 if (x->set->flags & NFT_SET_MAP) 106 111 nft_data_copy(&x->elem->data, he->data);