Skip to content

Commit 5ca8cc5

Browse files
committed
rhashtable: add rhashtable_lookup_get_insert_key()
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 <[email protected]> Cc: Thomas Graf <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]> Acked-by: Herbert Xu <[email protected]>
1 parent 6133740 commit 5ca8cc5

File tree

2 files changed

+64
-16
lines changed

2 files changed

+64
-16
lines changed

include/linux/rhashtable.h

Lines changed: 57 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,8 @@ int rhashtable_init(struct rhashtable *ht,
343343
struct bucket_table *rhashtable_insert_slow(struct rhashtable *ht,
344344
const void *key,
345345
struct rhash_head *obj,
346-
struct bucket_table *old_tbl);
346+
struct bucket_table *old_tbl,
347+
void **data);
347348
int rhashtable_insert_rehash(struct rhashtable *ht, struct bucket_table *tbl);
348349

349350
int rhashtable_walk_init(struct rhashtable *ht, struct rhashtable_iter *iter,
@@ -563,8 +564,11 @@ static inline void *rhashtable_lookup_fast(
563564
return NULL;
564565
}
565566

566-
/* Internal function, please use rhashtable_insert_fast() instead */
567-
static inline int __rhashtable_insert_fast(
567+
/* Internal function, please use rhashtable_insert_fast() instead. This
568+
* function returns the existing element already in hashes in there is a clash,
569+
* otherwise it returns an error via ERR_PTR().
570+
*/
571+
static inline void *__rhashtable_insert_fast(
568572
struct rhashtable *ht, const void *key, struct rhash_head *obj,
569573
const struct rhashtable_params params)
570574
{
@@ -577,6 +581,7 @@ static inline int __rhashtable_insert_fast(
577581
spinlock_t *lock;
578582
unsigned int elasticity;
579583
unsigned int hash;
584+
void *data = NULL;
580585
int err;
581586

582587
restart:
@@ -601,11 +606,14 @@ static inline int __rhashtable_insert_fast(
601606

602607
new_tbl = rht_dereference_rcu(tbl->future_tbl, ht);
603608
if (unlikely(new_tbl)) {
604-
tbl = rhashtable_insert_slow(ht, key, obj, new_tbl);
609+
tbl = rhashtable_insert_slow(ht, key, obj, new_tbl, &data);
605610
if (!IS_ERR_OR_NULL(tbl))
606611
goto slow_path;
607612

608613
err = PTR_ERR(tbl);
614+
if (err == -EEXIST)
615+
err = 0;
616+
609617
goto out;
610618
}
611619

@@ -619,25 +627,25 @@ static inline int __rhashtable_insert_fast(
619627
err = rhashtable_insert_rehash(ht, tbl);
620628
rcu_read_unlock();
621629
if (err)
622-
return err;
630+
return ERR_PTR(err);
623631

624632
goto restart;
625633
}
626634

627-
err = -EEXIST;
635+
err = 0;
628636
elasticity = ht->elasticity;
629637
rht_for_each(head, tbl, hash) {
630638
if (key &&
631639
unlikely(!(params.obj_cmpfn ?
632640
params.obj_cmpfn(&arg, rht_obj(ht, head)) :
633-
rhashtable_compare(&arg, rht_obj(ht, head)))))
641+
rhashtable_compare(&arg, rht_obj(ht, head))))) {
642+
data = rht_obj(ht, head);
634643
goto out;
644+
}
635645
if (!--elasticity)
636646
goto slow_path;
637647
}
638648

639-
err = 0;
640-
641649
head = rht_dereference_bucket(tbl->buckets[hash], tbl, hash);
642650

643651
RCU_INIT_POINTER(obj->next, head);
@@ -652,7 +660,7 @@ static inline int __rhashtable_insert_fast(
652660
spin_unlock_bh(lock);
653661
rcu_read_unlock();
654662

655-
return err;
663+
return err ? ERR_PTR(err) : data;
656664
}
657665

658666
/**
@@ -675,7 +683,13 @@ static inline int rhashtable_insert_fast(
675683
struct rhashtable *ht, struct rhash_head *obj,
676684
const struct rhashtable_params params)
677685
{
678-
return __rhashtable_insert_fast(ht, NULL, obj, params);
686+
void *ret;
687+
688+
ret = __rhashtable_insert_fast(ht, NULL, obj, params);
689+
if (IS_ERR(ret))
690+
return PTR_ERR(ret);
691+
692+
return ret == NULL ? 0 : -EEXIST;
679693
}
680694

681695
/**
@@ -704,11 +718,15 @@ static inline int rhashtable_lookup_insert_fast(
704718
const struct rhashtable_params params)
705719
{
706720
const char *key = rht_obj(ht, obj);
721+
void *ret;
707722

708723
BUG_ON(ht->p.obj_hashfn);
709724

710-
return __rhashtable_insert_fast(ht, key + ht->p.key_offset, obj,
711-
params);
725+
ret = __rhashtable_insert_fast(ht, key + ht->p.key_offset, obj, params);
726+
if (IS_ERR(ret))
727+
return PTR_ERR(ret);
728+
729+
return ret == NULL ? 0 : -EEXIST;
712730
}
713731

714732
/**
@@ -736,6 +754,32 @@ static inline int rhashtable_lookup_insert_fast(
736754
static inline int rhashtable_lookup_insert_key(
737755
struct rhashtable *ht, const void *key, struct rhash_head *obj,
738756
const struct rhashtable_params params)
757+
{
758+
void *ret;
759+
760+
BUG_ON(!ht->p.obj_hashfn || !key);
761+
762+
ret = __rhashtable_insert_fast(ht, key, obj, params);
763+
if (IS_ERR(ret))
764+
return PTR_ERR(ret);
765+
766+
return ret == NULL ? 0 : -EEXIST;
767+
}
768+
769+
/**
770+
* rhashtable_lookup_get_insert_key - lookup and insert object into hash table
771+
* @ht: hash table
772+
* @obj: pointer to hash head inside object
773+
* @params: hash table parameters
774+
* @data: pointer to element data already in hashes
775+
*
776+
* Just like rhashtable_lookup_insert_key(), but this function returns the
777+
* object if it exists, NULL if it does not and the insertion was successful,
778+
* and an ERR_PTR otherwise.
779+
*/
780+
static inline void *rhashtable_lookup_get_insert_key(
781+
struct rhashtable *ht, const void *key, struct rhash_head *obj,
782+
const struct rhashtable_params params)
739783
{
740784
BUG_ON(!ht->p.obj_hashfn || !key);
741785

lib/rhashtable.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,8 @@ EXPORT_SYMBOL_GPL(rhashtable_insert_rehash);
438438
struct bucket_table *rhashtable_insert_slow(struct rhashtable *ht,
439439
const void *key,
440440
struct rhash_head *obj,
441-
struct bucket_table *tbl)
441+
struct bucket_table *tbl,
442+
void **data)
442443
{
443444
struct rhash_head *head;
444445
unsigned int hash;
@@ -449,8 +450,11 @@ struct bucket_table *rhashtable_insert_slow(struct rhashtable *ht,
449450
spin_lock_nested(rht_bucket_lock(tbl, hash), SINGLE_DEPTH_NESTING);
450451

451452
err = -EEXIST;
452-
if (key && rhashtable_lookup_fast(ht, key, ht->p))
453-
goto exit;
453+
if (key) {
454+
*data = rhashtable_lookup_fast(ht, key, ht->p);
455+
if (*data)
456+
goto exit;
457+
}
454458

455459
err = -E2BIG;
456460
if (unlikely(rht_grow_above_max(ht, tbl)))

0 commit comments

Comments
 (0)