xref: /kernel/linux/linux-5.10/lib/rhashtable.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Resizable, Scalable, Concurrent Hash Table
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2015 Herbert Xu <herbert@gondor.apana.org.au>
68c2ecf20Sopenharmony_ci * Copyright (c) 2014-2015 Thomas Graf <tgraf@suug.ch>
78c2ecf20Sopenharmony_ci * Copyright (c) 2008-2014 Patrick McHardy <kaber@trash.net>
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Code partially derived from nft_hash
108c2ecf20Sopenharmony_ci * Rewritten with rehash code from br_multicast plus single list
118c2ecf20Sopenharmony_ci * pointer as suggested by Josh Triplett
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/atomic.h>
158c2ecf20Sopenharmony_ci#include <linux/kernel.h>
168c2ecf20Sopenharmony_ci#include <linux/init.h>
178c2ecf20Sopenharmony_ci#include <linux/log2.h>
188c2ecf20Sopenharmony_ci#include <linux/sched.h>
198c2ecf20Sopenharmony_ci#include <linux/rculist.h>
208c2ecf20Sopenharmony_ci#include <linux/slab.h>
218c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
228c2ecf20Sopenharmony_ci#include <linux/mm.h>
238c2ecf20Sopenharmony_ci#include <linux/jhash.h>
248c2ecf20Sopenharmony_ci#include <linux/random.h>
258c2ecf20Sopenharmony_ci#include <linux/rhashtable.h>
268c2ecf20Sopenharmony_ci#include <linux/err.h>
278c2ecf20Sopenharmony_ci#include <linux/export.h>
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#define HASH_DEFAULT_SIZE	64UL
308c2ecf20Sopenharmony_ci#define HASH_MIN_SIZE		4U
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ciunion nested_table {
338c2ecf20Sopenharmony_ci	union nested_table __rcu *table;
348c2ecf20Sopenharmony_ci	struct rhash_lock_head __rcu *bucket;
358c2ecf20Sopenharmony_ci};
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic u32 head_hashfn(struct rhashtable *ht,
388c2ecf20Sopenharmony_ci		       const struct bucket_table *tbl,
398c2ecf20Sopenharmony_ci		       const struct rhash_head *he)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	return rht_head_hashfn(ht, tbl, he, ht->p);
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci#ifdef CONFIG_PROVE_LOCKING
458c2ecf20Sopenharmony_ci#define ASSERT_RHT_MUTEX(HT) BUG_ON(!lockdep_rht_mutex_is_held(HT))
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ciint lockdep_rht_mutex_is_held(struct rhashtable *ht)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	return (debug_locks) ? lockdep_is_held(&ht->mutex) : 1;
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(lockdep_rht_mutex_is_held);
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ciint lockdep_rht_bucket_is_held(const struct bucket_table *tbl, u32 hash)
548c2ecf20Sopenharmony_ci{
558c2ecf20Sopenharmony_ci	if (!debug_locks)
568c2ecf20Sopenharmony_ci		return 1;
578c2ecf20Sopenharmony_ci	if (unlikely(tbl->nest))
588c2ecf20Sopenharmony_ci		return 1;
598c2ecf20Sopenharmony_ci	return bit_spin_is_locked(0, (unsigned long *)&tbl->buckets[hash]);
608c2ecf20Sopenharmony_ci}
618c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(lockdep_rht_bucket_is_held);
628c2ecf20Sopenharmony_ci#else
638c2ecf20Sopenharmony_ci#define ASSERT_RHT_MUTEX(HT)
648c2ecf20Sopenharmony_ci#endif
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic inline union nested_table *nested_table_top(
678c2ecf20Sopenharmony_ci	const struct bucket_table *tbl)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	/* The top-level bucket entry does not need RCU protection
708c2ecf20Sopenharmony_ci	 * because it's set at the same time as tbl->nest.
718c2ecf20Sopenharmony_ci	 */
728c2ecf20Sopenharmony_ci	return (void *)rcu_dereference_protected(tbl->buckets[0], 1);
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistatic void nested_table_free(union nested_table *ntbl, unsigned int size)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	const unsigned int shift = PAGE_SHIFT - ilog2(sizeof(void *));
788c2ecf20Sopenharmony_ci	const unsigned int len = 1 << shift;
798c2ecf20Sopenharmony_ci	unsigned int i;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	ntbl = rcu_dereference_protected(ntbl->table, 1);
828c2ecf20Sopenharmony_ci	if (!ntbl)
838c2ecf20Sopenharmony_ci		return;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	if (size > len) {
868c2ecf20Sopenharmony_ci		size >>= shift;
878c2ecf20Sopenharmony_ci		for (i = 0; i < len; i++)
888c2ecf20Sopenharmony_ci			nested_table_free(ntbl + i, size);
898c2ecf20Sopenharmony_ci	}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	kfree(ntbl);
928c2ecf20Sopenharmony_ci}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_cistatic void nested_bucket_table_free(const struct bucket_table *tbl)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	unsigned int size = tbl->size >> tbl->nest;
978c2ecf20Sopenharmony_ci	unsigned int len = 1 << tbl->nest;
988c2ecf20Sopenharmony_ci	union nested_table *ntbl;
998c2ecf20Sopenharmony_ci	unsigned int i;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	ntbl = nested_table_top(tbl);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	for (i = 0; i < len; i++)
1048c2ecf20Sopenharmony_ci		nested_table_free(ntbl + i, size);
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	kfree(ntbl);
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic void bucket_table_free(const struct bucket_table *tbl)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	if (tbl->nest)
1128c2ecf20Sopenharmony_ci		nested_bucket_table_free(tbl);
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	kvfree(tbl);
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cistatic void bucket_table_free_rcu(struct rcu_head *head)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	bucket_table_free(container_of(head, struct bucket_table, rcu));
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistatic union nested_table *nested_table_alloc(struct rhashtable *ht,
1238c2ecf20Sopenharmony_ci					      union nested_table __rcu **prev,
1248c2ecf20Sopenharmony_ci					      bool leaf)
1258c2ecf20Sopenharmony_ci{
1268c2ecf20Sopenharmony_ci	union nested_table *ntbl;
1278c2ecf20Sopenharmony_ci	int i;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	ntbl = rcu_dereference(*prev);
1308c2ecf20Sopenharmony_ci	if (ntbl)
1318c2ecf20Sopenharmony_ci		return ntbl;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	ntbl = kzalloc(PAGE_SIZE, GFP_ATOMIC);
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	if (ntbl && leaf) {
1368c2ecf20Sopenharmony_ci		for (i = 0; i < PAGE_SIZE / sizeof(ntbl[0]); i++)
1378c2ecf20Sopenharmony_ci			INIT_RHT_NULLS_HEAD(ntbl[i].bucket);
1388c2ecf20Sopenharmony_ci	}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	if (cmpxchg((union nested_table **)prev, NULL, ntbl) == NULL)
1418c2ecf20Sopenharmony_ci		return ntbl;
1428c2ecf20Sopenharmony_ci	/* Raced with another thread. */
1438c2ecf20Sopenharmony_ci	kfree(ntbl);
1448c2ecf20Sopenharmony_ci	return rcu_dereference(*prev);
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_cistatic struct bucket_table *nested_bucket_table_alloc(struct rhashtable *ht,
1488c2ecf20Sopenharmony_ci						      size_t nbuckets,
1498c2ecf20Sopenharmony_ci						      gfp_t gfp)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	const unsigned int shift = PAGE_SHIFT - ilog2(sizeof(void *));
1528c2ecf20Sopenharmony_ci	struct bucket_table *tbl;
1538c2ecf20Sopenharmony_ci	size_t size;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	if (nbuckets < (1 << (shift + 1)))
1568c2ecf20Sopenharmony_ci		return NULL;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	size = sizeof(*tbl) + sizeof(tbl->buckets[0]);
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	tbl = kzalloc(size, gfp);
1618c2ecf20Sopenharmony_ci	if (!tbl)
1628c2ecf20Sopenharmony_ci		return NULL;
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	if (!nested_table_alloc(ht, (union nested_table __rcu **)tbl->buckets,
1658c2ecf20Sopenharmony_ci				false)) {
1668c2ecf20Sopenharmony_ci		kfree(tbl);
1678c2ecf20Sopenharmony_ci		return NULL;
1688c2ecf20Sopenharmony_ci	}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	tbl->nest = (ilog2(nbuckets) - 1) % shift + 1;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	return tbl;
1738c2ecf20Sopenharmony_ci}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_cistatic struct bucket_table *bucket_table_alloc(struct rhashtable *ht,
1768c2ecf20Sopenharmony_ci					       size_t nbuckets,
1778c2ecf20Sopenharmony_ci					       gfp_t gfp)
1788c2ecf20Sopenharmony_ci{
1798c2ecf20Sopenharmony_ci	struct bucket_table *tbl = NULL;
1808c2ecf20Sopenharmony_ci	size_t size;
1818c2ecf20Sopenharmony_ci	int i;
1828c2ecf20Sopenharmony_ci	static struct lock_class_key __key;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	tbl = kvzalloc(struct_size(tbl, buckets, nbuckets), gfp);
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	size = nbuckets;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	if (tbl == NULL && (gfp & ~__GFP_NOFAIL) != GFP_KERNEL) {
1898c2ecf20Sopenharmony_ci		tbl = nested_bucket_table_alloc(ht, nbuckets, gfp);
1908c2ecf20Sopenharmony_ci		nbuckets = 0;
1918c2ecf20Sopenharmony_ci	}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	if (tbl == NULL)
1948c2ecf20Sopenharmony_ci		return NULL;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	lockdep_init_map(&tbl->dep_map, "rhashtable_bucket", &__key, 0);
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	tbl->size = size;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	rcu_head_init(&tbl->rcu);
2018c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&tbl->walkers);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	tbl->hash_rnd = get_random_u32();
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	for (i = 0; i < nbuckets; i++)
2068c2ecf20Sopenharmony_ci		INIT_RHT_NULLS_HEAD(tbl->buckets[i]);
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	return tbl;
2098c2ecf20Sopenharmony_ci}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_cistatic struct bucket_table *rhashtable_last_table(struct rhashtable *ht,
2128c2ecf20Sopenharmony_ci						  struct bucket_table *tbl)
2138c2ecf20Sopenharmony_ci{
2148c2ecf20Sopenharmony_ci	struct bucket_table *new_tbl;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	do {
2178c2ecf20Sopenharmony_ci		new_tbl = tbl;
2188c2ecf20Sopenharmony_ci		tbl = rht_dereference_rcu(tbl->future_tbl, ht);
2198c2ecf20Sopenharmony_ci	} while (tbl);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	return new_tbl;
2228c2ecf20Sopenharmony_ci}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_cistatic int rhashtable_rehash_one(struct rhashtable *ht,
2258c2ecf20Sopenharmony_ci				 struct rhash_lock_head __rcu **bkt,
2268c2ecf20Sopenharmony_ci				 unsigned int old_hash)
2278c2ecf20Sopenharmony_ci{
2288c2ecf20Sopenharmony_ci	struct bucket_table *old_tbl = rht_dereference(ht->tbl, ht);
2298c2ecf20Sopenharmony_ci	struct bucket_table *new_tbl = rhashtable_last_table(ht, old_tbl);
2308c2ecf20Sopenharmony_ci	int err = -EAGAIN;
2318c2ecf20Sopenharmony_ci	struct rhash_head *head, *next, *entry;
2328c2ecf20Sopenharmony_ci	struct rhash_head __rcu **pprev = NULL;
2338c2ecf20Sopenharmony_ci	unsigned int new_hash;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	if (new_tbl->nest)
2368c2ecf20Sopenharmony_ci		goto out;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	err = -ENOENT;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	rht_for_each_from(entry, rht_ptr(bkt, old_tbl, old_hash),
2418c2ecf20Sopenharmony_ci			  old_tbl, old_hash) {
2428c2ecf20Sopenharmony_ci		err = 0;
2438c2ecf20Sopenharmony_ci		next = rht_dereference_bucket(entry->next, old_tbl, old_hash);
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci		if (rht_is_a_nulls(next))
2468c2ecf20Sopenharmony_ci			break;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci		pprev = &entry->next;
2498c2ecf20Sopenharmony_ci	}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	if (err)
2528c2ecf20Sopenharmony_ci		goto out;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	new_hash = head_hashfn(ht, new_tbl, entry);
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	rht_lock_nested(new_tbl, &new_tbl->buckets[new_hash], SINGLE_DEPTH_NESTING);
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	head = rht_ptr(new_tbl->buckets + new_hash, new_tbl, new_hash);
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	RCU_INIT_POINTER(entry->next, head);
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	rht_assign_unlock(new_tbl, &new_tbl->buckets[new_hash], entry);
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	if (pprev)
2658c2ecf20Sopenharmony_ci		rcu_assign_pointer(*pprev, next);
2668c2ecf20Sopenharmony_ci	else
2678c2ecf20Sopenharmony_ci		/* Need to preserved the bit lock. */
2688c2ecf20Sopenharmony_ci		rht_assign_locked(bkt, next);
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ciout:
2718c2ecf20Sopenharmony_ci	return err;
2728c2ecf20Sopenharmony_ci}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_cistatic int rhashtable_rehash_chain(struct rhashtable *ht,
2758c2ecf20Sopenharmony_ci				    unsigned int old_hash)
2768c2ecf20Sopenharmony_ci{
2778c2ecf20Sopenharmony_ci	struct bucket_table *old_tbl = rht_dereference(ht->tbl, ht);
2788c2ecf20Sopenharmony_ci	struct rhash_lock_head __rcu **bkt = rht_bucket_var(old_tbl, old_hash);
2798c2ecf20Sopenharmony_ci	int err;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	if (!bkt)
2828c2ecf20Sopenharmony_ci		return 0;
2838c2ecf20Sopenharmony_ci	rht_lock(old_tbl, bkt);
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	while (!(err = rhashtable_rehash_one(ht, bkt, old_hash)))
2868c2ecf20Sopenharmony_ci		;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	if (err == -ENOENT)
2898c2ecf20Sopenharmony_ci		err = 0;
2908c2ecf20Sopenharmony_ci	rht_unlock(old_tbl, bkt);
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	return err;
2938c2ecf20Sopenharmony_ci}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_cistatic int rhashtable_rehash_attach(struct rhashtable *ht,
2968c2ecf20Sopenharmony_ci				    struct bucket_table *old_tbl,
2978c2ecf20Sopenharmony_ci				    struct bucket_table *new_tbl)
2988c2ecf20Sopenharmony_ci{
2998c2ecf20Sopenharmony_ci	/* Make insertions go into the new, empty table right away. Deletions
3008c2ecf20Sopenharmony_ci	 * and lookups will be attempted in both tables until we synchronize.
3018c2ecf20Sopenharmony_ci	 * As cmpxchg() provides strong barriers, we do not need
3028c2ecf20Sopenharmony_ci	 * rcu_assign_pointer().
3038c2ecf20Sopenharmony_ci	 */
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	if (cmpxchg((struct bucket_table **)&old_tbl->future_tbl, NULL,
3068c2ecf20Sopenharmony_ci		    new_tbl) != NULL)
3078c2ecf20Sopenharmony_ci		return -EEXIST;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	return 0;
3108c2ecf20Sopenharmony_ci}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_cistatic int rhashtable_rehash_table(struct rhashtable *ht)
3138c2ecf20Sopenharmony_ci{
3148c2ecf20Sopenharmony_ci	struct bucket_table *old_tbl = rht_dereference(ht->tbl, ht);
3158c2ecf20Sopenharmony_ci	struct bucket_table *new_tbl;
3168c2ecf20Sopenharmony_ci	struct rhashtable_walker *walker;
3178c2ecf20Sopenharmony_ci	unsigned int old_hash;
3188c2ecf20Sopenharmony_ci	int err;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	new_tbl = rht_dereference(old_tbl->future_tbl, ht);
3218c2ecf20Sopenharmony_ci	if (!new_tbl)
3228c2ecf20Sopenharmony_ci		return 0;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	for (old_hash = 0; old_hash < old_tbl->size; old_hash++) {
3258c2ecf20Sopenharmony_ci		err = rhashtable_rehash_chain(ht, old_hash);
3268c2ecf20Sopenharmony_ci		if (err)
3278c2ecf20Sopenharmony_ci			return err;
3288c2ecf20Sopenharmony_ci		cond_resched();
3298c2ecf20Sopenharmony_ci	}
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	/* Publish the new table pointer. */
3328c2ecf20Sopenharmony_ci	rcu_assign_pointer(ht->tbl, new_tbl);
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	spin_lock(&ht->lock);
3358c2ecf20Sopenharmony_ci	list_for_each_entry(walker, &old_tbl->walkers, list)
3368c2ecf20Sopenharmony_ci		walker->tbl = NULL;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	/* Wait for readers. All new readers will see the new
3398c2ecf20Sopenharmony_ci	 * table, and thus no references to the old table will
3408c2ecf20Sopenharmony_ci	 * remain.
3418c2ecf20Sopenharmony_ci	 * We do this inside the locked region so that
3428c2ecf20Sopenharmony_ci	 * rhashtable_walk_stop() can use rcu_head_after_call_rcu()
3438c2ecf20Sopenharmony_ci	 * to check if it should not re-link the table.
3448c2ecf20Sopenharmony_ci	 */
3458c2ecf20Sopenharmony_ci	call_rcu(&old_tbl->rcu, bucket_table_free_rcu);
3468c2ecf20Sopenharmony_ci	spin_unlock(&ht->lock);
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	return rht_dereference(new_tbl->future_tbl, ht) ? -EAGAIN : 0;
3498c2ecf20Sopenharmony_ci}
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_cistatic int rhashtable_rehash_alloc(struct rhashtable *ht,
3528c2ecf20Sopenharmony_ci				   struct bucket_table *old_tbl,
3538c2ecf20Sopenharmony_ci				   unsigned int size)
3548c2ecf20Sopenharmony_ci{
3558c2ecf20Sopenharmony_ci	struct bucket_table *new_tbl;
3568c2ecf20Sopenharmony_ci	int err;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	ASSERT_RHT_MUTEX(ht);
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	new_tbl = bucket_table_alloc(ht, size, GFP_KERNEL);
3618c2ecf20Sopenharmony_ci	if (new_tbl == NULL)
3628c2ecf20Sopenharmony_ci		return -ENOMEM;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	err = rhashtable_rehash_attach(ht, old_tbl, new_tbl);
3658c2ecf20Sopenharmony_ci	if (err)
3668c2ecf20Sopenharmony_ci		bucket_table_free(new_tbl);
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	return err;
3698c2ecf20Sopenharmony_ci}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci/**
3728c2ecf20Sopenharmony_ci * rhashtable_shrink - Shrink hash table while allowing concurrent lookups
3738c2ecf20Sopenharmony_ci * @ht:		the hash table to shrink
3748c2ecf20Sopenharmony_ci *
3758c2ecf20Sopenharmony_ci * This function shrinks the hash table to fit, i.e., the smallest
3768c2ecf20Sopenharmony_ci * size would not cause it to expand right away automatically.
3778c2ecf20Sopenharmony_ci *
3788c2ecf20Sopenharmony_ci * The caller must ensure that no concurrent resizing occurs by holding
3798c2ecf20Sopenharmony_ci * ht->mutex.
3808c2ecf20Sopenharmony_ci *
3818c2ecf20Sopenharmony_ci * The caller must ensure that no concurrent table mutations take place.
3828c2ecf20Sopenharmony_ci * It is however valid to have concurrent lookups if they are RCU protected.
3838c2ecf20Sopenharmony_ci *
3848c2ecf20Sopenharmony_ci * It is valid to have concurrent insertions and deletions protected by per
3858c2ecf20Sopenharmony_ci * bucket locks or concurrent RCU protected lookups and traversals.
3868c2ecf20Sopenharmony_ci */
3878c2ecf20Sopenharmony_cistatic int rhashtable_shrink(struct rhashtable *ht)
3888c2ecf20Sopenharmony_ci{
3898c2ecf20Sopenharmony_ci	struct bucket_table *old_tbl = rht_dereference(ht->tbl, ht);
3908c2ecf20Sopenharmony_ci	unsigned int nelems = atomic_read(&ht->nelems);
3918c2ecf20Sopenharmony_ci	unsigned int size = 0;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	if (nelems)
3948c2ecf20Sopenharmony_ci		size = roundup_pow_of_two(nelems * 3 / 2);
3958c2ecf20Sopenharmony_ci	if (size < ht->p.min_size)
3968c2ecf20Sopenharmony_ci		size = ht->p.min_size;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	if (old_tbl->size <= size)
3998c2ecf20Sopenharmony_ci		return 0;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	if (rht_dereference(old_tbl->future_tbl, ht))
4028c2ecf20Sopenharmony_ci		return -EEXIST;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	return rhashtable_rehash_alloc(ht, old_tbl, size);
4058c2ecf20Sopenharmony_ci}
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_cistatic void rht_deferred_worker(struct work_struct *work)
4088c2ecf20Sopenharmony_ci{
4098c2ecf20Sopenharmony_ci	struct rhashtable *ht;
4108c2ecf20Sopenharmony_ci	struct bucket_table *tbl;
4118c2ecf20Sopenharmony_ci	int err = 0;
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	ht = container_of(work, struct rhashtable, run_work);
4148c2ecf20Sopenharmony_ci	mutex_lock(&ht->mutex);
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	tbl = rht_dereference(ht->tbl, ht);
4178c2ecf20Sopenharmony_ci	tbl = rhashtable_last_table(ht, tbl);
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	if (rht_grow_above_75(ht, tbl))
4208c2ecf20Sopenharmony_ci		err = rhashtable_rehash_alloc(ht, tbl, tbl->size * 2);
4218c2ecf20Sopenharmony_ci	else if (ht->p.automatic_shrinking && rht_shrink_below_30(ht, tbl))
4228c2ecf20Sopenharmony_ci		err = rhashtable_shrink(ht);
4238c2ecf20Sopenharmony_ci	else if (tbl->nest)
4248c2ecf20Sopenharmony_ci		err = rhashtable_rehash_alloc(ht, tbl, tbl->size);
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	if (!err || err == -EEXIST) {
4278c2ecf20Sopenharmony_ci		int nerr;
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci		nerr = rhashtable_rehash_table(ht);
4308c2ecf20Sopenharmony_ci		err = err ?: nerr;
4318c2ecf20Sopenharmony_ci	}
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	mutex_unlock(&ht->mutex);
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	if (err)
4368c2ecf20Sopenharmony_ci		schedule_work(&ht->run_work);
4378c2ecf20Sopenharmony_ci}
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_cistatic int rhashtable_insert_rehash(struct rhashtable *ht,
4408c2ecf20Sopenharmony_ci				    struct bucket_table *tbl)
4418c2ecf20Sopenharmony_ci{
4428c2ecf20Sopenharmony_ci	struct bucket_table *old_tbl;
4438c2ecf20Sopenharmony_ci	struct bucket_table *new_tbl;
4448c2ecf20Sopenharmony_ci	unsigned int size;
4458c2ecf20Sopenharmony_ci	int err;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	old_tbl = rht_dereference_rcu(ht->tbl, ht);
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	size = tbl->size;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	err = -EBUSY;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	if (rht_grow_above_75(ht, tbl))
4548c2ecf20Sopenharmony_ci		size *= 2;
4558c2ecf20Sopenharmony_ci	/* Do not schedule more than one rehash */
4568c2ecf20Sopenharmony_ci	else if (old_tbl != tbl)
4578c2ecf20Sopenharmony_ci		goto fail;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	err = -ENOMEM;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	new_tbl = bucket_table_alloc(ht, size, GFP_ATOMIC | __GFP_NOWARN);
4628c2ecf20Sopenharmony_ci	if (new_tbl == NULL)
4638c2ecf20Sopenharmony_ci		goto fail;
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	err = rhashtable_rehash_attach(ht, tbl, new_tbl);
4668c2ecf20Sopenharmony_ci	if (err) {
4678c2ecf20Sopenharmony_ci		bucket_table_free(new_tbl);
4688c2ecf20Sopenharmony_ci		if (err == -EEXIST)
4698c2ecf20Sopenharmony_ci			err = 0;
4708c2ecf20Sopenharmony_ci	} else
4718c2ecf20Sopenharmony_ci		schedule_work(&ht->run_work);
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	return err;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_cifail:
4768c2ecf20Sopenharmony_ci	/* Do not fail the insert if someone else did a rehash. */
4778c2ecf20Sopenharmony_ci	if (likely(rcu_access_pointer(tbl->future_tbl)))
4788c2ecf20Sopenharmony_ci		return 0;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	/* Schedule async rehash to retry allocation in process context. */
4818c2ecf20Sopenharmony_ci	if (err == -ENOMEM)
4828c2ecf20Sopenharmony_ci		schedule_work(&ht->run_work);
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	return err;
4858c2ecf20Sopenharmony_ci}
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_cistatic void *rhashtable_lookup_one(struct rhashtable *ht,
4888c2ecf20Sopenharmony_ci				   struct rhash_lock_head __rcu **bkt,
4898c2ecf20Sopenharmony_ci				   struct bucket_table *tbl, unsigned int hash,
4908c2ecf20Sopenharmony_ci				   const void *key, struct rhash_head *obj)
4918c2ecf20Sopenharmony_ci{
4928c2ecf20Sopenharmony_ci	struct rhashtable_compare_arg arg = {
4938c2ecf20Sopenharmony_ci		.ht = ht,
4948c2ecf20Sopenharmony_ci		.key = key,
4958c2ecf20Sopenharmony_ci	};
4968c2ecf20Sopenharmony_ci	struct rhash_head __rcu **pprev = NULL;
4978c2ecf20Sopenharmony_ci	struct rhash_head *head;
4988c2ecf20Sopenharmony_ci	int elasticity;
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	elasticity = RHT_ELASTICITY;
5018c2ecf20Sopenharmony_ci	rht_for_each_from(head, rht_ptr(bkt, tbl, hash), tbl, hash) {
5028c2ecf20Sopenharmony_ci		struct rhlist_head *list;
5038c2ecf20Sopenharmony_ci		struct rhlist_head *plist;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci		elasticity--;
5068c2ecf20Sopenharmony_ci		if (!key ||
5078c2ecf20Sopenharmony_ci		    (ht->p.obj_cmpfn ?
5088c2ecf20Sopenharmony_ci		     ht->p.obj_cmpfn(&arg, rht_obj(ht, head)) :
5098c2ecf20Sopenharmony_ci		     rhashtable_compare(&arg, rht_obj(ht, head)))) {
5108c2ecf20Sopenharmony_ci			pprev = &head->next;
5118c2ecf20Sopenharmony_ci			continue;
5128c2ecf20Sopenharmony_ci		}
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci		if (!ht->rhlist)
5158c2ecf20Sopenharmony_ci			return rht_obj(ht, head);
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci		list = container_of(obj, struct rhlist_head, rhead);
5188c2ecf20Sopenharmony_ci		plist = container_of(head, struct rhlist_head, rhead);
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci		RCU_INIT_POINTER(list->next, plist);
5218c2ecf20Sopenharmony_ci		head = rht_dereference_bucket(head->next, tbl, hash);
5228c2ecf20Sopenharmony_ci		RCU_INIT_POINTER(list->rhead.next, head);
5238c2ecf20Sopenharmony_ci		if (pprev)
5248c2ecf20Sopenharmony_ci			rcu_assign_pointer(*pprev, obj);
5258c2ecf20Sopenharmony_ci		else
5268c2ecf20Sopenharmony_ci			/* Need to preserve the bit lock */
5278c2ecf20Sopenharmony_ci			rht_assign_locked(bkt, obj);
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci		return NULL;
5308c2ecf20Sopenharmony_ci	}
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	if (elasticity <= 0)
5338c2ecf20Sopenharmony_ci		return ERR_PTR(-EAGAIN);
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	return ERR_PTR(-ENOENT);
5368c2ecf20Sopenharmony_ci}
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_cistatic struct bucket_table *rhashtable_insert_one(
5398c2ecf20Sopenharmony_ci	struct rhashtable *ht, struct rhash_lock_head __rcu **bkt,
5408c2ecf20Sopenharmony_ci	struct bucket_table *tbl, unsigned int hash, struct rhash_head *obj,
5418c2ecf20Sopenharmony_ci	void *data)
5428c2ecf20Sopenharmony_ci{
5438c2ecf20Sopenharmony_ci	struct bucket_table *new_tbl;
5448c2ecf20Sopenharmony_ci	struct rhash_head *head;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	if (!IS_ERR_OR_NULL(data))
5478c2ecf20Sopenharmony_ci		return ERR_PTR(-EEXIST);
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	if (PTR_ERR(data) != -EAGAIN && PTR_ERR(data) != -ENOENT)
5508c2ecf20Sopenharmony_ci		return ERR_CAST(data);
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	new_tbl = rht_dereference_rcu(tbl->future_tbl, ht);
5538c2ecf20Sopenharmony_ci	if (new_tbl)
5548c2ecf20Sopenharmony_ci		return new_tbl;
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	if (PTR_ERR(data) != -ENOENT)
5578c2ecf20Sopenharmony_ci		return ERR_CAST(data);
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	if (unlikely(rht_grow_above_max(ht, tbl)))
5608c2ecf20Sopenharmony_ci		return ERR_PTR(-E2BIG);
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	if (unlikely(rht_grow_above_100(ht, tbl)))
5638c2ecf20Sopenharmony_ci		return ERR_PTR(-EAGAIN);
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	head = rht_ptr(bkt, tbl, hash);
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	RCU_INIT_POINTER(obj->next, head);
5688c2ecf20Sopenharmony_ci	if (ht->rhlist) {
5698c2ecf20Sopenharmony_ci		struct rhlist_head *list;
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci		list = container_of(obj, struct rhlist_head, rhead);
5728c2ecf20Sopenharmony_ci		RCU_INIT_POINTER(list->next, NULL);
5738c2ecf20Sopenharmony_ci	}
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	/* bkt is always the head of the list, so it holds
5768c2ecf20Sopenharmony_ci	 * the lock, which we need to preserve
5778c2ecf20Sopenharmony_ci	 */
5788c2ecf20Sopenharmony_ci	rht_assign_locked(bkt, obj);
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	atomic_inc(&ht->nelems);
5818c2ecf20Sopenharmony_ci	if (rht_grow_above_75(ht, tbl))
5828c2ecf20Sopenharmony_ci		schedule_work(&ht->run_work);
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	return NULL;
5858c2ecf20Sopenharmony_ci}
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_cistatic void *rhashtable_try_insert(struct rhashtable *ht, const void *key,
5888c2ecf20Sopenharmony_ci				   struct rhash_head *obj)
5898c2ecf20Sopenharmony_ci{
5908c2ecf20Sopenharmony_ci	struct bucket_table *new_tbl;
5918c2ecf20Sopenharmony_ci	struct bucket_table *tbl;
5928c2ecf20Sopenharmony_ci	struct rhash_lock_head __rcu **bkt;
5938c2ecf20Sopenharmony_ci	unsigned int hash;
5948c2ecf20Sopenharmony_ci	void *data;
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci	new_tbl = rcu_dereference(ht->tbl);
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	do {
5998c2ecf20Sopenharmony_ci		tbl = new_tbl;
6008c2ecf20Sopenharmony_ci		hash = rht_head_hashfn(ht, tbl, obj, ht->p);
6018c2ecf20Sopenharmony_ci		if (rcu_access_pointer(tbl->future_tbl))
6028c2ecf20Sopenharmony_ci			/* Failure is OK */
6038c2ecf20Sopenharmony_ci			bkt = rht_bucket_var(tbl, hash);
6048c2ecf20Sopenharmony_ci		else
6058c2ecf20Sopenharmony_ci			bkt = rht_bucket_insert(ht, tbl, hash);
6068c2ecf20Sopenharmony_ci		if (bkt == NULL) {
6078c2ecf20Sopenharmony_ci			new_tbl = rht_dereference_rcu(tbl->future_tbl, ht);
6088c2ecf20Sopenharmony_ci			data = ERR_PTR(-EAGAIN);
6098c2ecf20Sopenharmony_ci		} else {
6108c2ecf20Sopenharmony_ci			rht_lock(tbl, bkt);
6118c2ecf20Sopenharmony_ci			data = rhashtable_lookup_one(ht, bkt, tbl,
6128c2ecf20Sopenharmony_ci						     hash, key, obj);
6138c2ecf20Sopenharmony_ci			new_tbl = rhashtable_insert_one(ht, bkt, tbl,
6148c2ecf20Sopenharmony_ci							hash, obj, data);
6158c2ecf20Sopenharmony_ci			if (PTR_ERR(new_tbl) != -EEXIST)
6168c2ecf20Sopenharmony_ci				data = ERR_CAST(new_tbl);
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci			rht_unlock(tbl, bkt);
6198c2ecf20Sopenharmony_ci		}
6208c2ecf20Sopenharmony_ci	} while (!IS_ERR_OR_NULL(new_tbl));
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	if (PTR_ERR(data) == -EAGAIN)
6238c2ecf20Sopenharmony_ci		data = ERR_PTR(rhashtable_insert_rehash(ht, tbl) ?:
6248c2ecf20Sopenharmony_ci			       -EAGAIN);
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	return data;
6278c2ecf20Sopenharmony_ci}
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_civoid *rhashtable_insert_slow(struct rhashtable *ht, const void *key,
6308c2ecf20Sopenharmony_ci			     struct rhash_head *obj)
6318c2ecf20Sopenharmony_ci{
6328c2ecf20Sopenharmony_ci	void *data;
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	do {
6358c2ecf20Sopenharmony_ci		rcu_read_lock();
6368c2ecf20Sopenharmony_ci		data = rhashtable_try_insert(ht, key, obj);
6378c2ecf20Sopenharmony_ci		rcu_read_unlock();
6388c2ecf20Sopenharmony_ci	} while (PTR_ERR(data) == -EAGAIN);
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci	return data;
6418c2ecf20Sopenharmony_ci}
6428c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rhashtable_insert_slow);
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci/**
6458c2ecf20Sopenharmony_ci * rhashtable_walk_enter - Initialise an iterator
6468c2ecf20Sopenharmony_ci * @ht:		Table to walk over
6478c2ecf20Sopenharmony_ci * @iter:	Hash table Iterator
6488c2ecf20Sopenharmony_ci *
6498c2ecf20Sopenharmony_ci * This function prepares a hash table walk.
6508c2ecf20Sopenharmony_ci *
6518c2ecf20Sopenharmony_ci * Note that if you restart a walk after rhashtable_walk_stop you
6528c2ecf20Sopenharmony_ci * may see the same object twice.  Also, you may miss objects if
6538c2ecf20Sopenharmony_ci * there are removals in between rhashtable_walk_stop and the next
6548c2ecf20Sopenharmony_ci * call to rhashtable_walk_start.
6558c2ecf20Sopenharmony_ci *
6568c2ecf20Sopenharmony_ci * For a completely stable walk you should construct your own data
6578c2ecf20Sopenharmony_ci * structure outside the hash table.
6588c2ecf20Sopenharmony_ci *
6598c2ecf20Sopenharmony_ci * This function may be called from any process context, including
6608c2ecf20Sopenharmony_ci * non-preemptable context, but cannot be called from softirq or
6618c2ecf20Sopenharmony_ci * hardirq context.
6628c2ecf20Sopenharmony_ci *
6638c2ecf20Sopenharmony_ci * You must call rhashtable_walk_exit after this function returns.
6648c2ecf20Sopenharmony_ci */
6658c2ecf20Sopenharmony_civoid rhashtable_walk_enter(struct rhashtable *ht, struct rhashtable_iter *iter)
6668c2ecf20Sopenharmony_ci{
6678c2ecf20Sopenharmony_ci	iter->ht = ht;
6688c2ecf20Sopenharmony_ci	iter->p = NULL;
6698c2ecf20Sopenharmony_ci	iter->slot = 0;
6708c2ecf20Sopenharmony_ci	iter->skip = 0;
6718c2ecf20Sopenharmony_ci	iter->end_of_table = 0;
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci	spin_lock(&ht->lock);
6748c2ecf20Sopenharmony_ci	iter->walker.tbl =
6758c2ecf20Sopenharmony_ci		rcu_dereference_protected(ht->tbl, lockdep_is_held(&ht->lock));
6768c2ecf20Sopenharmony_ci	list_add(&iter->walker.list, &iter->walker.tbl->walkers);
6778c2ecf20Sopenharmony_ci	spin_unlock(&ht->lock);
6788c2ecf20Sopenharmony_ci}
6798c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rhashtable_walk_enter);
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci/**
6828c2ecf20Sopenharmony_ci * rhashtable_walk_exit - Free an iterator
6838c2ecf20Sopenharmony_ci * @iter:	Hash table Iterator
6848c2ecf20Sopenharmony_ci *
6858c2ecf20Sopenharmony_ci * This function frees resources allocated by rhashtable_walk_enter.
6868c2ecf20Sopenharmony_ci */
6878c2ecf20Sopenharmony_civoid rhashtable_walk_exit(struct rhashtable_iter *iter)
6888c2ecf20Sopenharmony_ci{
6898c2ecf20Sopenharmony_ci	spin_lock(&iter->ht->lock);
6908c2ecf20Sopenharmony_ci	if (iter->walker.tbl)
6918c2ecf20Sopenharmony_ci		list_del(&iter->walker.list);
6928c2ecf20Sopenharmony_ci	spin_unlock(&iter->ht->lock);
6938c2ecf20Sopenharmony_ci}
6948c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rhashtable_walk_exit);
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci/**
6978c2ecf20Sopenharmony_ci * rhashtable_walk_start_check - Start a hash table walk
6988c2ecf20Sopenharmony_ci * @iter:	Hash table iterator
6998c2ecf20Sopenharmony_ci *
7008c2ecf20Sopenharmony_ci * Start a hash table walk at the current iterator position.  Note that we take
7018c2ecf20Sopenharmony_ci * the RCU lock in all cases including when we return an error.  So you must
7028c2ecf20Sopenharmony_ci * always call rhashtable_walk_stop to clean up.
7038c2ecf20Sopenharmony_ci *
7048c2ecf20Sopenharmony_ci * Returns zero if successful.
7058c2ecf20Sopenharmony_ci *
7068c2ecf20Sopenharmony_ci * Returns -EAGAIN if resize event occured.  Note that the iterator
7078c2ecf20Sopenharmony_ci * will rewind back to the beginning and you may use it immediately
7088c2ecf20Sopenharmony_ci * by calling rhashtable_walk_next.
7098c2ecf20Sopenharmony_ci *
7108c2ecf20Sopenharmony_ci * rhashtable_walk_start is defined as an inline variant that returns
7118c2ecf20Sopenharmony_ci * void. This is preferred in cases where the caller would ignore
7128c2ecf20Sopenharmony_ci * resize events and always continue.
7138c2ecf20Sopenharmony_ci */
7148c2ecf20Sopenharmony_ciint rhashtable_walk_start_check(struct rhashtable_iter *iter)
7158c2ecf20Sopenharmony_ci	__acquires(RCU)
7168c2ecf20Sopenharmony_ci{
7178c2ecf20Sopenharmony_ci	struct rhashtable *ht = iter->ht;
7188c2ecf20Sopenharmony_ci	bool rhlist = ht->rhlist;
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	rcu_read_lock();
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	spin_lock(&ht->lock);
7238c2ecf20Sopenharmony_ci	if (iter->walker.tbl)
7248c2ecf20Sopenharmony_ci		list_del(&iter->walker.list);
7258c2ecf20Sopenharmony_ci	spin_unlock(&ht->lock);
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	if (iter->end_of_table)
7288c2ecf20Sopenharmony_ci		return 0;
7298c2ecf20Sopenharmony_ci	if (!iter->walker.tbl) {
7308c2ecf20Sopenharmony_ci		iter->walker.tbl = rht_dereference_rcu(ht->tbl, ht);
7318c2ecf20Sopenharmony_ci		iter->slot = 0;
7328c2ecf20Sopenharmony_ci		iter->skip = 0;
7338c2ecf20Sopenharmony_ci		return -EAGAIN;
7348c2ecf20Sopenharmony_ci	}
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	if (iter->p && !rhlist) {
7378c2ecf20Sopenharmony_ci		/*
7388c2ecf20Sopenharmony_ci		 * We need to validate that 'p' is still in the table, and
7398c2ecf20Sopenharmony_ci		 * if so, update 'skip'
7408c2ecf20Sopenharmony_ci		 */
7418c2ecf20Sopenharmony_ci		struct rhash_head *p;
7428c2ecf20Sopenharmony_ci		int skip = 0;
7438c2ecf20Sopenharmony_ci		rht_for_each_rcu(p, iter->walker.tbl, iter->slot) {
7448c2ecf20Sopenharmony_ci			skip++;
7458c2ecf20Sopenharmony_ci			if (p == iter->p) {
7468c2ecf20Sopenharmony_ci				iter->skip = skip;
7478c2ecf20Sopenharmony_ci				goto found;
7488c2ecf20Sopenharmony_ci			}
7498c2ecf20Sopenharmony_ci		}
7508c2ecf20Sopenharmony_ci		iter->p = NULL;
7518c2ecf20Sopenharmony_ci	} else if (iter->p && rhlist) {
7528c2ecf20Sopenharmony_ci		/* Need to validate that 'list' is still in the table, and
7538c2ecf20Sopenharmony_ci		 * if so, update 'skip' and 'p'.
7548c2ecf20Sopenharmony_ci		 */
7558c2ecf20Sopenharmony_ci		struct rhash_head *p;
7568c2ecf20Sopenharmony_ci		struct rhlist_head *list;
7578c2ecf20Sopenharmony_ci		int skip = 0;
7588c2ecf20Sopenharmony_ci		rht_for_each_rcu(p, iter->walker.tbl, iter->slot) {
7598c2ecf20Sopenharmony_ci			for (list = container_of(p, struct rhlist_head, rhead);
7608c2ecf20Sopenharmony_ci			     list;
7618c2ecf20Sopenharmony_ci			     list = rcu_dereference(list->next)) {
7628c2ecf20Sopenharmony_ci				skip++;
7638c2ecf20Sopenharmony_ci				if (list == iter->list) {
7648c2ecf20Sopenharmony_ci					iter->p = p;
7658c2ecf20Sopenharmony_ci					iter->skip = skip;
7668c2ecf20Sopenharmony_ci					goto found;
7678c2ecf20Sopenharmony_ci				}
7688c2ecf20Sopenharmony_ci			}
7698c2ecf20Sopenharmony_ci		}
7708c2ecf20Sopenharmony_ci		iter->p = NULL;
7718c2ecf20Sopenharmony_ci	}
7728c2ecf20Sopenharmony_cifound:
7738c2ecf20Sopenharmony_ci	return 0;
7748c2ecf20Sopenharmony_ci}
7758c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rhashtable_walk_start_check);
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci/**
7788c2ecf20Sopenharmony_ci * __rhashtable_walk_find_next - Find the next element in a table (or the first
7798c2ecf20Sopenharmony_ci * one in case of a new walk).
7808c2ecf20Sopenharmony_ci *
7818c2ecf20Sopenharmony_ci * @iter:	Hash table iterator
7828c2ecf20Sopenharmony_ci *
7838c2ecf20Sopenharmony_ci * Returns the found object or NULL when the end of the table is reached.
7848c2ecf20Sopenharmony_ci *
7858c2ecf20Sopenharmony_ci * Returns -EAGAIN if resize event occurred.
7868c2ecf20Sopenharmony_ci */
7878c2ecf20Sopenharmony_cistatic void *__rhashtable_walk_find_next(struct rhashtable_iter *iter)
7888c2ecf20Sopenharmony_ci{
7898c2ecf20Sopenharmony_ci	struct bucket_table *tbl = iter->walker.tbl;
7908c2ecf20Sopenharmony_ci	struct rhlist_head *list = iter->list;
7918c2ecf20Sopenharmony_ci	struct rhashtable *ht = iter->ht;
7928c2ecf20Sopenharmony_ci	struct rhash_head *p = iter->p;
7938c2ecf20Sopenharmony_ci	bool rhlist = ht->rhlist;
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci	if (!tbl)
7968c2ecf20Sopenharmony_ci		return NULL;
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	for (; iter->slot < tbl->size; iter->slot++) {
7998c2ecf20Sopenharmony_ci		int skip = iter->skip;
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci		rht_for_each_rcu(p, tbl, iter->slot) {
8028c2ecf20Sopenharmony_ci			if (rhlist) {
8038c2ecf20Sopenharmony_ci				list = container_of(p, struct rhlist_head,
8048c2ecf20Sopenharmony_ci						    rhead);
8058c2ecf20Sopenharmony_ci				do {
8068c2ecf20Sopenharmony_ci					if (!skip)
8078c2ecf20Sopenharmony_ci						goto next;
8088c2ecf20Sopenharmony_ci					skip--;
8098c2ecf20Sopenharmony_ci					list = rcu_dereference(list->next);
8108c2ecf20Sopenharmony_ci				} while (list);
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci				continue;
8138c2ecf20Sopenharmony_ci			}
8148c2ecf20Sopenharmony_ci			if (!skip)
8158c2ecf20Sopenharmony_ci				break;
8168c2ecf20Sopenharmony_ci			skip--;
8178c2ecf20Sopenharmony_ci		}
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_cinext:
8208c2ecf20Sopenharmony_ci		if (!rht_is_a_nulls(p)) {
8218c2ecf20Sopenharmony_ci			iter->skip++;
8228c2ecf20Sopenharmony_ci			iter->p = p;
8238c2ecf20Sopenharmony_ci			iter->list = list;
8248c2ecf20Sopenharmony_ci			return rht_obj(ht, rhlist ? &list->rhead : p);
8258c2ecf20Sopenharmony_ci		}
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci		iter->skip = 0;
8288c2ecf20Sopenharmony_ci	}
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	iter->p = NULL;
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci	/* Ensure we see any new tables. */
8338c2ecf20Sopenharmony_ci	smp_rmb();
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci	iter->walker.tbl = rht_dereference_rcu(tbl->future_tbl, ht);
8368c2ecf20Sopenharmony_ci	if (iter->walker.tbl) {
8378c2ecf20Sopenharmony_ci		iter->slot = 0;
8388c2ecf20Sopenharmony_ci		iter->skip = 0;
8398c2ecf20Sopenharmony_ci		return ERR_PTR(-EAGAIN);
8408c2ecf20Sopenharmony_ci	} else {
8418c2ecf20Sopenharmony_ci		iter->end_of_table = true;
8428c2ecf20Sopenharmony_ci	}
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	return NULL;
8458c2ecf20Sopenharmony_ci}
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci/**
8488c2ecf20Sopenharmony_ci * rhashtable_walk_next - Return the next object and advance the iterator
8498c2ecf20Sopenharmony_ci * @iter:	Hash table iterator
8508c2ecf20Sopenharmony_ci *
8518c2ecf20Sopenharmony_ci * Note that you must call rhashtable_walk_stop when you are finished
8528c2ecf20Sopenharmony_ci * with the walk.
8538c2ecf20Sopenharmony_ci *
8548c2ecf20Sopenharmony_ci * Returns the next object or NULL when the end of the table is reached.
8558c2ecf20Sopenharmony_ci *
8568c2ecf20Sopenharmony_ci * Returns -EAGAIN if resize event occurred.  Note that the iterator
8578c2ecf20Sopenharmony_ci * will rewind back to the beginning and you may continue to use it.
8588c2ecf20Sopenharmony_ci */
8598c2ecf20Sopenharmony_civoid *rhashtable_walk_next(struct rhashtable_iter *iter)
8608c2ecf20Sopenharmony_ci{
8618c2ecf20Sopenharmony_ci	struct rhlist_head *list = iter->list;
8628c2ecf20Sopenharmony_ci	struct rhashtable *ht = iter->ht;
8638c2ecf20Sopenharmony_ci	struct rhash_head *p = iter->p;
8648c2ecf20Sopenharmony_ci	bool rhlist = ht->rhlist;
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	if (p) {
8678c2ecf20Sopenharmony_ci		if (!rhlist || !(list = rcu_dereference(list->next))) {
8688c2ecf20Sopenharmony_ci			p = rcu_dereference(p->next);
8698c2ecf20Sopenharmony_ci			list = container_of(p, struct rhlist_head, rhead);
8708c2ecf20Sopenharmony_ci		}
8718c2ecf20Sopenharmony_ci		if (!rht_is_a_nulls(p)) {
8728c2ecf20Sopenharmony_ci			iter->skip++;
8738c2ecf20Sopenharmony_ci			iter->p = p;
8748c2ecf20Sopenharmony_ci			iter->list = list;
8758c2ecf20Sopenharmony_ci			return rht_obj(ht, rhlist ? &list->rhead : p);
8768c2ecf20Sopenharmony_ci		}
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci		/* At the end of this slot, switch to next one and then find
8798c2ecf20Sopenharmony_ci		 * next entry from that point.
8808c2ecf20Sopenharmony_ci		 */
8818c2ecf20Sopenharmony_ci		iter->skip = 0;
8828c2ecf20Sopenharmony_ci		iter->slot++;
8838c2ecf20Sopenharmony_ci	}
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci	return __rhashtable_walk_find_next(iter);
8868c2ecf20Sopenharmony_ci}
8878c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rhashtable_walk_next);
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci/**
8908c2ecf20Sopenharmony_ci * rhashtable_walk_peek - Return the next object but don't advance the iterator
8918c2ecf20Sopenharmony_ci * @iter:	Hash table iterator
8928c2ecf20Sopenharmony_ci *
8938c2ecf20Sopenharmony_ci * Returns the next object or NULL when the end of the table is reached.
8948c2ecf20Sopenharmony_ci *
8958c2ecf20Sopenharmony_ci * Returns -EAGAIN if resize event occurred.  Note that the iterator
8968c2ecf20Sopenharmony_ci * will rewind back to the beginning and you may continue to use it.
8978c2ecf20Sopenharmony_ci */
8988c2ecf20Sopenharmony_civoid *rhashtable_walk_peek(struct rhashtable_iter *iter)
8998c2ecf20Sopenharmony_ci{
9008c2ecf20Sopenharmony_ci	struct rhlist_head *list = iter->list;
9018c2ecf20Sopenharmony_ci	struct rhashtable *ht = iter->ht;
9028c2ecf20Sopenharmony_ci	struct rhash_head *p = iter->p;
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	if (p)
9058c2ecf20Sopenharmony_ci		return rht_obj(ht, ht->rhlist ? &list->rhead : p);
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	/* No object found in current iter, find next one in the table. */
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	if (iter->skip) {
9108c2ecf20Sopenharmony_ci		/* A nonzero skip value points to the next entry in the table
9118c2ecf20Sopenharmony_ci		 * beyond that last one that was found. Decrement skip so
9128c2ecf20Sopenharmony_ci		 * we find the current value. __rhashtable_walk_find_next
9138c2ecf20Sopenharmony_ci		 * will restore the original value of skip assuming that
9148c2ecf20Sopenharmony_ci		 * the table hasn't changed.
9158c2ecf20Sopenharmony_ci		 */
9168c2ecf20Sopenharmony_ci		iter->skip--;
9178c2ecf20Sopenharmony_ci	}
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci	return __rhashtable_walk_find_next(iter);
9208c2ecf20Sopenharmony_ci}
9218c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rhashtable_walk_peek);
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci/**
9248c2ecf20Sopenharmony_ci * rhashtable_walk_stop - Finish a hash table walk
9258c2ecf20Sopenharmony_ci * @iter:	Hash table iterator
9268c2ecf20Sopenharmony_ci *
9278c2ecf20Sopenharmony_ci * Finish a hash table walk.  Does not reset the iterator to the start of the
9288c2ecf20Sopenharmony_ci * hash table.
9298c2ecf20Sopenharmony_ci */
9308c2ecf20Sopenharmony_civoid rhashtable_walk_stop(struct rhashtable_iter *iter)
9318c2ecf20Sopenharmony_ci	__releases(RCU)
9328c2ecf20Sopenharmony_ci{
9338c2ecf20Sopenharmony_ci	struct rhashtable *ht;
9348c2ecf20Sopenharmony_ci	struct bucket_table *tbl = iter->walker.tbl;
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	if (!tbl)
9378c2ecf20Sopenharmony_ci		goto out;
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci	ht = iter->ht;
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci	spin_lock(&ht->lock);
9428c2ecf20Sopenharmony_ci	if (rcu_head_after_call_rcu(&tbl->rcu, bucket_table_free_rcu))
9438c2ecf20Sopenharmony_ci		/* This bucket table is being freed, don't re-link it. */
9448c2ecf20Sopenharmony_ci		iter->walker.tbl = NULL;
9458c2ecf20Sopenharmony_ci	else
9468c2ecf20Sopenharmony_ci		list_add(&iter->walker.list, &tbl->walkers);
9478c2ecf20Sopenharmony_ci	spin_unlock(&ht->lock);
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ciout:
9508c2ecf20Sopenharmony_ci	rcu_read_unlock();
9518c2ecf20Sopenharmony_ci}
9528c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rhashtable_walk_stop);
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_cistatic size_t rounded_hashtable_size(const struct rhashtable_params *params)
9558c2ecf20Sopenharmony_ci{
9568c2ecf20Sopenharmony_ci	size_t retsize;
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	if (params->nelem_hint)
9598c2ecf20Sopenharmony_ci		retsize = max(roundup_pow_of_two(params->nelem_hint * 4 / 3),
9608c2ecf20Sopenharmony_ci			      (unsigned long)params->min_size);
9618c2ecf20Sopenharmony_ci	else
9628c2ecf20Sopenharmony_ci		retsize = max(HASH_DEFAULT_SIZE,
9638c2ecf20Sopenharmony_ci			      (unsigned long)params->min_size);
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	return retsize;
9668c2ecf20Sopenharmony_ci}
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_cistatic u32 rhashtable_jhash2(const void *key, u32 length, u32 seed)
9698c2ecf20Sopenharmony_ci{
9708c2ecf20Sopenharmony_ci	return jhash2(key, length, seed);
9718c2ecf20Sopenharmony_ci}
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci/**
9748c2ecf20Sopenharmony_ci * rhashtable_init - initialize a new hash table
9758c2ecf20Sopenharmony_ci * @ht:		hash table to be initialized
9768c2ecf20Sopenharmony_ci * @params:	configuration parameters
9778c2ecf20Sopenharmony_ci *
9788c2ecf20Sopenharmony_ci * Initializes a new hash table based on the provided configuration
9798c2ecf20Sopenharmony_ci * parameters. A table can be configured either with a variable or
9808c2ecf20Sopenharmony_ci * fixed length key:
9818c2ecf20Sopenharmony_ci *
9828c2ecf20Sopenharmony_ci * Configuration Example 1: Fixed length keys
9838c2ecf20Sopenharmony_ci * struct test_obj {
9848c2ecf20Sopenharmony_ci *	int			key;
9858c2ecf20Sopenharmony_ci *	void *			my_member;
9868c2ecf20Sopenharmony_ci *	struct rhash_head	node;
9878c2ecf20Sopenharmony_ci * };
9888c2ecf20Sopenharmony_ci *
9898c2ecf20Sopenharmony_ci * struct rhashtable_params params = {
9908c2ecf20Sopenharmony_ci *	.head_offset = offsetof(struct test_obj, node),
9918c2ecf20Sopenharmony_ci *	.key_offset = offsetof(struct test_obj, key),
9928c2ecf20Sopenharmony_ci *	.key_len = sizeof(int),
9938c2ecf20Sopenharmony_ci *	.hashfn = jhash,
9948c2ecf20Sopenharmony_ci * };
9958c2ecf20Sopenharmony_ci *
9968c2ecf20Sopenharmony_ci * Configuration Example 2: Variable length keys
9978c2ecf20Sopenharmony_ci * struct test_obj {
9988c2ecf20Sopenharmony_ci *	[...]
9998c2ecf20Sopenharmony_ci *	struct rhash_head	node;
10008c2ecf20Sopenharmony_ci * };
10018c2ecf20Sopenharmony_ci *
10028c2ecf20Sopenharmony_ci * u32 my_hash_fn(const void *data, u32 len, u32 seed)
10038c2ecf20Sopenharmony_ci * {
10048c2ecf20Sopenharmony_ci *	struct test_obj *obj = data;
10058c2ecf20Sopenharmony_ci *
10068c2ecf20Sopenharmony_ci *	return [... hash ...];
10078c2ecf20Sopenharmony_ci * }
10088c2ecf20Sopenharmony_ci *
10098c2ecf20Sopenharmony_ci * struct rhashtable_params params = {
10108c2ecf20Sopenharmony_ci *	.head_offset = offsetof(struct test_obj, node),
10118c2ecf20Sopenharmony_ci *	.hashfn = jhash,
10128c2ecf20Sopenharmony_ci *	.obj_hashfn = my_hash_fn,
10138c2ecf20Sopenharmony_ci * };
10148c2ecf20Sopenharmony_ci */
10158c2ecf20Sopenharmony_ciint rhashtable_init(struct rhashtable *ht,
10168c2ecf20Sopenharmony_ci		    const struct rhashtable_params *params)
10178c2ecf20Sopenharmony_ci{
10188c2ecf20Sopenharmony_ci	struct bucket_table *tbl;
10198c2ecf20Sopenharmony_ci	size_t size;
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ci	if ((!params->key_len && !params->obj_hashfn) ||
10228c2ecf20Sopenharmony_ci	    (params->obj_hashfn && !params->obj_cmpfn))
10238c2ecf20Sopenharmony_ci		return -EINVAL;
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci	memset(ht, 0, sizeof(*ht));
10268c2ecf20Sopenharmony_ci	mutex_init(&ht->mutex);
10278c2ecf20Sopenharmony_ci	spin_lock_init(&ht->lock);
10288c2ecf20Sopenharmony_ci	memcpy(&ht->p, params, sizeof(*params));
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	if (params->min_size)
10318c2ecf20Sopenharmony_ci		ht->p.min_size = roundup_pow_of_two(params->min_size);
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci	/* Cap total entries at 2^31 to avoid nelems overflow. */
10348c2ecf20Sopenharmony_ci	ht->max_elems = 1u << 31;
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci	if (params->max_size) {
10378c2ecf20Sopenharmony_ci		ht->p.max_size = rounddown_pow_of_two(params->max_size);
10388c2ecf20Sopenharmony_ci		if (ht->p.max_size < ht->max_elems / 2)
10398c2ecf20Sopenharmony_ci			ht->max_elems = ht->p.max_size * 2;
10408c2ecf20Sopenharmony_ci	}
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_ci	ht->p.min_size = max_t(u16, ht->p.min_size, HASH_MIN_SIZE);
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_ci	size = rounded_hashtable_size(&ht->p);
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_ci	ht->key_len = ht->p.key_len;
10478c2ecf20Sopenharmony_ci	if (!params->hashfn) {
10488c2ecf20Sopenharmony_ci		ht->p.hashfn = jhash;
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_ci		if (!(ht->key_len & (sizeof(u32) - 1))) {
10518c2ecf20Sopenharmony_ci			ht->key_len /= sizeof(u32);
10528c2ecf20Sopenharmony_ci			ht->p.hashfn = rhashtable_jhash2;
10538c2ecf20Sopenharmony_ci		}
10548c2ecf20Sopenharmony_ci	}
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_ci	/*
10578c2ecf20Sopenharmony_ci	 * This is api initialization and thus we need to guarantee the
10588c2ecf20Sopenharmony_ci	 * initial rhashtable allocation. Upon failure, retry with the
10598c2ecf20Sopenharmony_ci	 * smallest possible size with __GFP_NOFAIL semantics.
10608c2ecf20Sopenharmony_ci	 */
10618c2ecf20Sopenharmony_ci	tbl = bucket_table_alloc(ht, size, GFP_KERNEL);
10628c2ecf20Sopenharmony_ci	if (unlikely(tbl == NULL)) {
10638c2ecf20Sopenharmony_ci		size = max_t(u16, ht->p.min_size, HASH_MIN_SIZE);
10648c2ecf20Sopenharmony_ci		tbl = bucket_table_alloc(ht, size, GFP_KERNEL | __GFP_NOFAIL);
10658c2ecf20Sopenharmony_ci	}
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci	atomic_set(&ht->nelems, 0);
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci	RCU_INIT_POINTER(ht->tbl, tbl);
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci	INIT_WORK(&ht->run_work, rht_deferred_worker);
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ci	return 0;
10748c2ecf20Sopenharmony_ci}
10758c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rhashtable_init);
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci/**
10788c2ecf20Sopenharmony_ci * rhltable_init - initialize a new hash list table
10798c2ecf20Sopenharmony_ci * @hlt:	hash list table to be initialized
10808c2ecf20Sopenharmony_ci * @params:	configuration parameters
10818c2ecf20Sopenharmony_ci *
10828c2ecf20Sopenharmony_ci * Initializes a new hash list table.
10838c2ecf20Sopenharmony_ci *
10848c2ecf20Sopenharmony_ci * See documentation for rhashtable_init.
10858c2ecf20Sopenharmony_ci */
10868c2ecf20Sopenharmony_ciint rhltable_init(struct rhltable *hlt, const struct rhashtable_params *params)
10878c2ecf20Sopenharmony_ci{
10888c2ecf20Sopenharmony_ci	int err;
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	err = rhashtable_init(&hlt->ht, params);
10918c2ecf20Sopenharmony_ci	hlt->ht.rhlist = true;
10928c2ecf20Sopenharmony_ci	return err;
10938c2ecf20Sopenharmony_ci}
10948c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rhltable_init);
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_cistatic void rhashtable_free_one(struct rhashtable *ht, struct rhash_head *obj,
10978c2ecf20Sopenharmony_ci				void (*free_fn)(void *ptr, void *arg),
10988c2ecf20Sopenharmony_ci				void *arg)
10998c2ecf20Sopenharmony_ci{
11008c2ecf20Sopenharmony_ci	struct rhlist_head *list;
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci	if (!ht->rhlist) {
11038c2ecf20Sopenharmony_ci		free_fn(rht_obj(ht, obj), arg);
11048c2ecf20Sopenharmony_ci		return;
11058c2ecf20Sopenharmony_ci	}
11068c2ecf20Sopenharmony_ci
11078c2ecf20Sopenharmony_ci	list = container_of(obj, struct rhlist_head, rhead);
11088c2ecf20Sopenharmony_ci	do {
11098c2ecf20Sopenharmony_ci		obj = &list->rhead;
11108c2ecf20Sopenharmony_ci		list = rht_dereference(list->next, ht);
11118c2ecf20Sopenharmony_ci		free_fn(rht_obj(ht, obj), arg);
11128c2ecf20Sopenharmony_ci	} while (list);
11138c2ecf20Sopenharmony_ci}
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci/**
11168c2ecf20Sopenharmony_ci * rhashtable_free_and_destroy - free elements and destroy hash table
11178c2ecf20Sopenharmony_ci * @ht:		the hash table to destroy
11188c2ecf20Sopenharmony_ci * @free_fn:	callback to release resources of element
11198c2ecf20Sopenharmony_ci * @arg:	pointer passed to free_fn
11208c2ecf20Sopenharmony_ci *
11218c2ecf20Sopenharmony_ci * Stops an eventual async resize. If defined, invokes free_fn for each
11228c2ecf20Sopenharmony_ci * element to releasal resources. Please note that RCU protected
11238c2ecf20Sopenharmony_ci * readers may still be accessing the elements. Releasing of resources
11248c2ecf20Sopenharmony_ci * must occur in a compatible manner. Then frees the bucket array.
11258c2ecf20Sopenharmony_ci *
11268c2ecf20Sopenharmony_ci * This function will eventually sleep to wait for an async resize
11278c2ecf20Sopenharmony_ci * to complete. The caller is responsible that no further write operations
11288c2ecf20Sopenharmony_ci * occurs in parallel.
11298c2ecf20Sopenharmony_ci */
11308c2ecf20Sopenharmony_civoid rhashtable_free_and_destroy(struct rhashtable *ht,
11318c2ecf20Sopenharmony_ci				 void (*free_fn)(void *ptr, void *arg),
11328c2ecf20Sopenharmony_ci				 void *arg)
11338c2ecf20Sopenharmony_ci{
11348c2ecf20Sopenharmony_ci	struct bucket_table *tbl, *next_tbl;
11358c2ecf20Sopenharmony_ci	unsigned int i;
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_ci	cancel_work_sync(&ht->run_work);
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci	mutex_lock(&ht->mutex);
11408c2ecf20Sopenharmony_ci	tbl = rht_dereference(ht->tbl, ht);
11418c2ecf20Sopenharmony_cirestart:
11428c2ecf20Sopenharmony_ci	if (free_fn) {
11438c2ecf20Sopenharmony_ci		for (i = 0; i < tbl->size; i++) {
11448c2ecf20Sopenharmony_ci			struct rhash_head *pos, *next;
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_ci			cond_resched();
11478c2ecf20Sopenharmony_ci			for (pos = rht_ptr_exclusive(rht_bucket(tbl, i)),
11488c2ecf20Sopenharmony_ci			     next = !rht_is_a_nulls(pos) ?
11498c2ecf20Sopenharmony_ci					rht_dereference(pos->next, ht) : NULL;
11508c2ecf20Sopenharmony_ci			     !rht_is_a_nulls(pos);
11518c2ecf20Sopenharmony_ci			     pos = next,
11528c2ecf20Sopenharmony_ci			     next = !rht_is_a_nulls(pos) ?
11538c2ecf20Sopenharmony_ci					rht_dereference(pos->next, ht) : NULL)
11548c2ecf20Sopenharmony_ci				rhashtable_free_one(ht, pos, free_fn, arg);
11558c2ecf20Sopenharmony_ci		}
11568c2ecf20Sopenharmony_ci	}
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_ci	next_tbl = rht_dereference(tbl->future_tbl, ht);
11598c2ecf20Sopenharmony_ci	bucket_table_free(tbl);
11608c2ecf20Sopenharmony_ci	if (next_tbl) {
11618c2ecf20Sopenharmony_ci		tbl = next_tbl;
11628c2ecf20Sopenharmony_ci		goto restart;
11638c2ecf20Sopenharmony_ci	}
11648c2ecf20Sopenharmony_ci	mutex_unlock(&ht->mutex);
11658c2ecf20Sopenharmony_ci}
11668c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rhashtable_free_and_destroy);
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_civoid rhashtable_destroy(struct rhashtable *ht)
11698c2ecf20Sopenharmony_ci{
11708c2ecf20Sopenharmony_ci	return rhashtable_free_and_destroy(ht, NULL, NULL);
11718c2ecf20Sopenharmony_ci}
11728c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rhashtable_destroy);
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_cistruct rhash_lock_head __rcu **__rht_bucket_nested(
11758c2ecf20Sopenharmony_ci	const struct bucket_table *tbl, unsigned int hash)
11768c2ecf20Sopenharmony_ci{
11778c2ecf20Sopenharmony_ci	const unsigned int shift = PAGE_SHIFT - ilog2(sizeof(void *));
11788c2ecf20Sopenharmony_ci	unsigned int index = hash & ((1 << tbl->nest) - 1);
11798c2ecf20Sopenharmony_ci	unsigned int size = tbl->size >> tbl->nest;
11808c2ecf20Sopenharmony_ci	unsigned int subhash = hash;
11818c2ecf20Sopenharmony_ci	union nested_table *ntbl;
11828c2ecf20Sopenharmony_ci
11838c2ecf20Sopenharmony_ci	ntbl = nested_table_top(tbl);
11848c2ecf20Sopenharmony_ci	ntbl = rht_dereference_bucket_rcu(ntbl[index].table, tbl, hash);
11858c2ecf20Sopenharmony_ci	subhash >>= tbl->nest;
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci	while (ntbl && size > (1 << shift)) {
11888c2ecf20Sopenharmony_ci		index = subhash & ((1 << shift) - 1);
11898c2ecf20Sopenharmony_ci		ntbl = rht_dereference_bucket_rcu(ntbl[index].table,
11908c2ecf20Sopenharmony_ci						  tbl, hash);
11918c2ecf20Sopenharmony_ci		size >>= shift;
11928c2ecf20Sopenharmony_ci		subhash >>= shift;
11938c2ecf20Sopenharmony_ci	}
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ci	if (!ntbl)
11968c2ecf20Sopenharmony_ci		return NULL;
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci	return &ntbl[subhash].bucket;
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci}
12018c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__rht_bucket_nested);
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_cistruct rhash_lock_head __rcu **rht_bucket_nested(
12048c2ecf20Sopenharmony_ci	const struct bucket_table *tbl, unsigned int hash)
12058c2ecf20Sopenharmony_ci{
12068c2ecf20Sopenharmony_ci	static struct rhash_lock_head __rcu *rhnull;
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci	if (!rhnull)
12098c2ecf20Sopenharmony_ci		INIT_RHT_NULLS_HEAD(rhnull);
12108c2ecf20Sopenharmony_ci	return __rht_bucket_nested(tbl, hash) ?: &rhnull;
12118c2ecf20Sopenharmony_ci}
12128c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rht_bucket_nested);
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_cistruct rhash_lock_head __rcu **rht_bucket_nested_insert(
12158c2ecf20Sopenharmony_ci	struct rhashtable *ht, struct bucket_table *tbl, unsigned int hash)
12168c2ecf20Sopenharmony_ci{
12178c2ecf20Sopenharmony_ci	const unsigned int shift = PAGE_SHIFT - ilog2(sizeof(void *));
12188c2ecf20Sopenharmony_ci	unsigned int index = hash & ((1 << tbl->nest) - 1);
12198c2ecf20Sopenharmony_ci	unsigned int size = tbl->size >> tbl->nest;
12208c2ecf20Sopenharmony_ci	union nested_table *ntbl;
12218c2ecf20Sopenharmony_ci
12228c2ecf20Sopenharmony_ci	ntbl = nested_table_top(tbl);
12238c2ecf20Sopenharmony_ci	hash >>= tbl->nest;
12248c2ecf20Sopenharmony_ci	ntbl = nested_table_alloc(ht, &ntbl[index].table,
12258c2ecf20Sopenharmony_ci				  size <= (1 << shift));
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci	while (ntbl && size > (1 << shift)) {
12288c2ecf20Sopenharmony_ci		index = hash & ((1 << shift) - 1);
12298c2ecf20Sopenharmony_ci		size >>= shift;
12308c2ecf20Sopenharmony_ci		hash >>= shift;
12318c2ecf20Sopenharmony_ci		ntbl = nested_table_alloc(ht, &ntbl[index].table,
12328c2ecf20Sopenharmony_ci					  size <= (1 << shift));
12338c2ecf20Sopenharmony_ci	}
12348c2ecf20Sopenharmony_ci
12358c2ecf20Sopenharmony_ci	if (!ntbl)
12368c2ecf20Sopenharmony_ci		return NULL;
12378c2ecf20Sopenharmony_ci
12388c2ecf20Sopenharmony_ci	return &ntbl[hash].bucket;
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_ci}
12418c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rht_bucket_nested_insert);
1242