diff options
| author | David S. Miller <davem@davemloft.net> | 2015-03-20 16:16:32 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2015-03-20 16:16:32 -0400 |
| commit | ebd6af092a221fc38e28fbb7995c0c7e3f0df875 (patch) | |
| tree | a06b2334d07b4a9177963cb34ff2455cf224c83b /net/netfilter | |
| parent | 0b8c707ddf37171413fe67350263e5b6ffeedf7c (diff) | |
| parent | dc0ee268d85026530720d8c874716287b7ede25b (diff) | |
Merge branch 'rhashtable-inlined-interface'
Herbert Xu says:
====================
rhashtable: Introduce inlined interface
This series of patches introduces the inlined rhashtable interface.
The idea is to make all the function pointers visible to the compiler
by providing the rhashtable_params structure explicitly to each
inline rhashtable function. For example, instead of doing
obj = rhashtable_lookup(ht, key);
you would now do
obj = rhashtable_lookup_fast(ht, key, params);
Where params is the same data that you would give to rhashtable_init.
In particular, within rhashtable.c itself we would simply supply
ht->p.
So to convert users over, you simply have to make params globally
accessible, e.g., by placing it in a static const variable, which
can then be used at each inlined call site, as well as by the
rhashtable_init call.
The only ticky bit is that some users (i.e., netfilter) has a
dynamic key length. This is dealt with by using params.key_len
in the inline functions when it is non-zero, and otherwise falling
back on ht->p.key_len.
Note that I've only tested this on one compiler, gcc 4.7.2. So
please test this with your compilers as well and make sure that
the code is actually inlined without indirect function calls.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/netfilter')
| -rw-r--r-- | net/netfilter/nft_hash.c | 70 |
1 files changed, 29 insertions, 41 deletions
diff --git a/net/netfilter/nft_hash.c b/net/netfilter/nft_hash.c index c82df0a48fcd..4585c5724391 100644 --- a/net/netfilter/nft_hash.c +++ b/net/netfilter/nft_hash.c @@ -29,6 +29,8 @@ struct nft_hash_elem { struct nft_data data[]; }; +static const struct rhashtable_params nft_hash_params; + static bool nft_hash_lookup(const struct nft_set *set, const struct nft_data *key, struct nft_data *data) @@ -36,7 +38,7 @@ static bool nft_hash_lookup(const struct nft_set *set, struct rhashtable *priv = nft_set_priv(set); const struct nft_hash_elem *he; - he = rhashtable_lookup(priv, key); + he = rhashtable_lookup_fast(priv, key, nft_hash_params); if (he && set->flags & NFT_SET_MAP) nft_data_copy(data, he->data); @@ -49,6 +51,7 @@ static int nft_hash_insert(const struct nft_set *set, struct rhashtable *priv = nft_set_priv(set); struct nft_hash_elem *he; unsigned int size; + int err; if (elem->flags != 0) return -EINVAL; @@ -65,9 +68,11 @@ static int nft_hash_insert(const struct nft_set *set, if (set->flags & NFT_SET_MAP) nft_data_copy(he->data, &elem->data); - rhashtable_insert(priv, &he->node); + err = rhashtable_insert_fast(priv, &he->node, nft_hash_params); + if (err) + kfree(he); - return 0; + return err; } static void nft_hash_elem_destroy(const struct nft_set *set, @@ -84,46 +89,26 @@ static void nft_hash_remove(const struct nft_set *set, { struct rhashtable *priv = nft_set_priv(set); - rhashtable_remove(priv, elem->cookie); + rhashtable_remove_fast(priv, elem->cookie, nft_hash_params); synchronize_rcu(); kfree(elem->cookie); } -struct nft_compare_arg { - const struct nft_set *set; - struct nft_set_elem *elem; -}; - -static bool nft_hash_compare(void *ptr, void *arg) -{ - struct nft_hash_elem *he = ptr; - struct nft_compare_arg *x = arg; - - if (!nft_data_cmp(&he->key, &x->elem->key, x->set->klen)) { - x->elem->cookie = he; - x->elem->flags = 0; - if (x->set->flags & NFT_SET_MAP) - nft_data_copy(&x->elem->data, he->data); - - return true; - } - - return false; -} - static int nft_hash_get(const struct nft_set *set, struct nft_set_elem *elem) { struct rhashtable *priv = nft_set_priv(set); - struct nft_compare_arg arg = { - .set = set, - .elem = elem, - }; + struct nft_hash_elem *he; + + he = rhashtable_lookup_fast(priv, &elem->key, nft_hash_params); + if (!he) + return -ENOENT; - if (rhashtable_lookup_compare(priv, &elem->key, - &nft_hash_compare, &arg)) - return 0; + elem->cookie = he; + elem->flags = 0; + if (set->flags & NFT_SET_MAP) + nft_data_copy(&elem->data, he->data); - return -ENOENT; + return 0; } static void nft_hash_walk(const struct nft_ctx *ctx, const struct nft_set *set, @@ -181,18 +166,21 @@ static unsigned int nft_hash_privsize(const struct nlattr * const nla[]) return sizeof(struct rhashtable); } +static const struct rhashtable_params nft_hash_params = { + .head_offset = offsetof(struct nft_hash_elem, node), + .key_offset = offsetof(struct nft_hash_elem, key), + .hashfn = jhash, +}; + static int nft_hash_init(const struct nft_set *set, const struct nft_set_desc *desc, const struct nlattr * const tb[]) { struct rhashtable *priv = nft_set_priv(set); - struct rhashtable_params params = { - .nelem_hint = desc->size ? : NFT_HASH_ELEMENT_HINT, - .head_offset = offsetof(struct nft_hash_elem, node), - .key_offset = offsetof(struct nft_hash_elem, key), - .key_len = set->klen, - .hashfn = jhash, - }; + struct rhashtable_params params = nft_hash_params; + + params.nelem_hint = desc->size ?: NFT_HASH_ELEMENT_HINT; + params.key_len = set->klen; return rhashtable_init(priv, ¶ms); } |
