Skip to content

Commit

Permalink
rhashtable: add rhashtable_lookup_get_insert_key()
Browse files Browse the repository at this point in the history
This patch modifies __rhashtable_insert_fast() so it returns the
existing object that clashes with the one that you want to insert.
In case the object is successfully inserted, NULL is returned.
Otherwise, you get an error via ERR_PTR().

This patch adapts the existing callers of __rhashtable_insert_fast()
so they handle this new logic, and it adds a new
rhashtable_lookup_get_insert_key() interface to fetch this existing
object.

nf_tables needs this change to improve handling of EEXIST cases via
honoring the NLM_F_EXCL flag and by checking if the data part of the
mapping matches what we have.

Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: Thomas Graf <tgraf@suug.ch>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
  • Loading branch information
Pablo Neira Ayuso committed Aug 26, 2016
1 parent 6133740 commit 5ca8cc5
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 16 deletions.
70 changes: 57 additions & 13 deletions include/linux/rhashtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,8 @@ int rhashtable_init(struct rhashtable *ht,
struct bucket_table *rhashtable_insert_slow(struct rhashtable *ht,
const void *key,
struct rhash_head *obj,
struct bucket_table *old_tbl);
struct bucket_table *old_tbl,
void **data);
int rhashtable_insert_rehash(struct rhashtable *ht, struct bucket_table *tbl);

int rhashtable_walk_init(struct rhashtable *ht, struct rhashtable_iter *iter,
Expand Down Expand Up @@ -563,8 +564,11 @@ static inline void *rhashtable_lookup_fast(
return NULL;
}

/* Internal function, please use rhashtable_insert_fast() instead */
static inline int __rhashtable_insert_fast(
/* Internal function, please use rhashtable_insert_fast() instead. This
* function returns the existing element already in hashes in there is a clash,
* otherwise it returns an error via ERR_PTR().
*/
static inline void *__rhashtable_insert_fast(
struct rhashtable *ht, const void *key, struct rhash_head *obj,
const struct rhashtable_params params)
{
Expand All @@ -577,6 +581,7 @@ static inline int __rhashtable_insert_fast(
spinlock_t *lock;
unsigned int elasticity;
unsigned int hash;
void *data = NULL;
int err;

restart:
Expand All @@ -601,11 +606,14 @@ static inline int __rhashtable_insert_fast(

new_tbl = rht_dereference_rcu(tbl->future_tbl, ht);
if (unlikely(new_tbl)) {
tbl = rhashtable_insert_slow(ht, key, obj, new_tbl);
tbl = rhashtable_insert_slow(ht, key, obj, new_tbl, &data);
if (!IS_ERR_OR_NULL(tbl))
goto slow_path;

err = PTR_ERR(tbl);
if (err == -EEXIST)
err = 0;

goto out;
}

Expand All @@ -619,25 +627,25 @@ static inline int __rhashtable_insert_fast(
err = rhashtable_insert_rehash(ht, tbl);
rcu_read_unlock();
if (err)
return err;
return ERR_PTR(err);

goto restart;
}

err = -EEXIST;
err = 0;
elasticity = ht->elasticity;
rht_for_each(head, tbl, hash) {
if (key &&
unlikely(!(params.obj_cmpfn ?
params.obj_cmpfn(&arg, rht_obj(ht, head)) :
rhashtable_compare(&arg, rht_obj(ht, head)))))
rhashtable_compare(&arg, rht_obj(ht, head))))) {
data = rht_obj(ht, head);
goto out;
}
if (!--elasticity)
goto slow_path;
}

err = 0;

head = rht_dereference_bucket(tbl->buckets[hash], tbl, hash);

RCU_INIT_POINTER(obj->next, head);
Expand All @@ -652,7 +660,7 @@ static inline int __rhashtable_insert_fast(
spin_unlock_bh(lock);
rcu_read_unlock();

return err;
return err ? ERR_PTR(err) : data;
}

/**
Expand All @@ -675,7 +683,13 @@ static inline int rhashtable_insert_fast(
struct rhashtable *ht, struct rhash_head *obj,
const struct rhashtable_params params)
{
return __rhashtable_insert_fast(ht, NULL, obj, params);
void *ret;

ret = __rhashtable_insert_fast(ht, NULL, obj, params);
if (IS_ERR(ret))
return PTR_ERR(ret);

return ret == NULL ? 0 : -EEXIST;
}

/**
Expand Down Expand Up @@ -704,11 +718,15 @@ static inline int rhashtable_lookup_insert_fast(
const struct rhashtable_params params)
{
const char *key = rht_obj(ht, obj);
void *ret;

BUG_ON(ht->p.obj_hashfn);

return __rhashtable_insert_fast(ht, key + ht->p.key_offset, obj,
params);
ret = __rhashtable_insert_fast(ht, key + ht->p.key_offset, obj, params);
if (IS_ERR(ret))
return PTR_ERR(ret);

return ret == NULL ? 0 : -EEXIST;
}

/**
Expand Down Expand Up @@ -736,6 +754,32 @@ static inline int rhashtable_lookup_insert_fast(
static inline int rhashtable_lookup_insert_key(
struct rhashtable *ht, const void *key, struct rhash_head *obj,
const struct rhashtable_params params)
{
void *ret;

BUG_ON(!ht->p.obj_hashfn || !key);

ret = __rhashtable_insert_fast(ht, key, obj, params);
if (IS_ERR(ret))
return PTR_ERR(ret);

return ret == NULL ? 0 : -EEXIST;
}

/**
* rhashtable_lookup_get_insert_key - lookup and insert object into hash table
* @ht: hash table
* @obj: pointer to hash head inside object
* @params: hash table parameters
* @data: pointer to element data already in hashes
*
* Just like rhashtable_lookup_insert_key(), but this function returns the
* object if it exists, NULL if it does not and the insertion was successful,
* and an ERR_PTR otherwise.
*/
static inline void *rhashtable_lookup_get_insert_key(
struct rhashtable *ht, const void *key, struct rhash_head *obj,
const struct rhashtable_params params)
{
BUG_ON(!ht->p.obj_hashfn || !key);

Expand Down
10 changes: 7 additions & 3 deletions lib/rhashtable.c
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,8 @@ EXPORT_SYMBOL_GPL(rhashtable_insert_rehash);
struct bucket_table *rhashtable_insert_slow(struct rhashtable *ht,
const void *key,
struct rhash_head *obj,
struct bucket_table *tbl)
struct bucket_table *tbl,
void **data)
{
struct rhash_head *head;
unsigned int hash;
Expand All @@ -449,8 +450,11 @@ struct bucket_table *rhashtable_insert_slow(struct rhashtable *ht,
spin_lock_nested(rht_bucket_lock(tbl, hash), SINGLE_DEPTH_NESTING);

err = -EEXIST;
if (key && rhashtable_lookup_fast(ht, key, ht->p))
goto exit;
if (key) {
*data = rhashtable_lookup_fast(ht, key, ht->p);
if (*data)
goto exit;
}

err = -E2BIG;
if (unlikely(rht_grow_above_max(ht, tbl)))
Expand Down

0 comments on commit 5ca8cc5

Please sign in to comment.