@@ -343,7 +343,8 @@ int rhashtable_init(struct rhashtable *ht,
343343struct 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 );
347348int rhashtable_insert_rehash (struct rhashtable * ht , struct bucket_table * tbl );
348349
349350int 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
582587restart :
@@ -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(
736754static 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
0 commit comments