mirror of https://gitee.com/openkylin/linux.git
rhashtable: add function to replace an element
Add the rhashtable_replace_fast function. This replaces one object in the table with another atomically. The hashes of the new and old objects must be equal. Signed-off-by: Tom Herbert <tom@herbertland.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
33f11d1614
commit
3502cad73c
|
@ -819,4 +819,86 @@ static inline int rhashtable_remove_fast(
|
|||
return err;
|
||||
}
|
||||
|
||||
/* Internal function, please use rhashtable_replace_fast() instead */
|
||||
static inline int __rhashtable_replace_fast(
|
||||
struct rhashtable *ht, struct bucket_table *tbl,
|
||||
struct rhash_head *obj_old, struct rhash_head *obj_new,
|
||||
const struct rhashtable_params params)
|
||||
{
|
||||
struct rhash_head __rcu **pprev;
|
||||
struct rhash_head *he;
|
||||
spinlock_t *lock;
|
||||
unsigned int hash;
|
||||
int err = -ENOENT;
|
||||
|
||||
/* Minimally, the old and new objects must have same hash
|
||||
* (which should mean identifiers are the same).
|
||||
*/
|
||||
hash = rht_head_hashfn(ht, tbl, obj_old, params);
|
||||
if (hash != rht_head_hashfn(ht, tbl, obj_new, params))
|
||||
return -EINVAL;
|
||||
|
||||
lock = rht_bucket_lock(tbl, hash);
|
||||
|
||||
spin_lock_bh(lock);
|
||||
|
||||
pprev = &tbl->buckets[hash];
|
||||
rht_for_each(he, tbl, hash) {
|
||||
if (he != obj_old) {
|
||||
pprev = &he->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
rcu_assign_pointer(obj_new->next, obj_old->next);
|
||||
rcu_assign_pointer(*pprev, obj_new);
|
||||
err = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
spin_unlock_bh(lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* rhashtable_replace_fast - replace an object in hash table
|
||||
* @ht: hash table
|
||||
* @obj_old: pointer to hash head inside object being replaced
|
||||
* @obj_new: pointer to hash head inside object which is new
|
||||
* @params: hash table parameters
|
||||
*
|
||||
* Replacing an object doesn't affect the number of elements in the hash table
|
||||
* or bucket, so we don't need to worry about shrinking or expanding the
|
||||
* table here.
|
||||
*
|
||||
* Returns zero on success, -ENOENT if the entry could not be found,
|
||||
* -EINVAL if hash is not the same for the old and new objects.
|
||||
*/
|
||||
static inline int rhashtable_replace_fast(
|
||||
struct rhashtable *ht, struct rhash_head *obj_old,
|
||||
struct rhash_head *obj_new,
|
||||
const struct rhashtable_params params)
|
||||
{
|
||||
struct bucket_table *tbl;
|
||||
int err;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
tbl = rht_dereference_rcu(ht->tbl, ht);
|
||||
|
||||
/* Because we have already taken (and released) the bucket
|
||||
* lock in old_tbl, if we find that future_tbl is not yet
|
||||
* visible then that guarantees the entry to still be in
|
||||
* the old tbl if it exists.
|
||||
*/
|
||||
while ((err = __rhashtable_replace_fast(ht, tbl, obj_old,
|
||||
obj_new, params)) &&
|
||||
(tbl = rht_dereference_rcu(tbl->future_tbl, ht)))
|
||||
;
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif /* _LINUX_RHASHTABLE_H */
|
||||
|
|
Loading…
Reference in New Issue