4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
23 #ifndef __LIBCFS_LINUX_HASH_H__
24 #define __LIBCFS_LINUX_HASH_H__
26 #include <linux/dcache.h>
27 #include <linux/rhashtable.h>
29 u64 cfs_hashlen_string(const void *salt, const char *name);
32 #define hashlen_hash(hashlen) ((u32)(hashlen))
35 #ifndef HAVE_STRINGHASH
36 #ifndef hashlen_create
37 #define hashlen_create(hash, len) ((u64)(len)<<32 | (u32)(hash))
39 #endif /* !HAVE_STRINGHASH */
41 #ifdef HAVE_BROKEN_HASH_64
43 #define GOLDEN_RATIO_32 0x61C88647
44 #define GOLDEN_RATIO_64 0x61C8864680B583EBull
46 static inline u32 cfs_hash_32(u32 val, unsigned int bits)
48 /* High bits are more random, so use them. */
49 return (val * GOLDEN_RATIO_32) >> (32 - bits);
52 static __always_inline u32 cfs_hash_64(u64 val, unsigned int bits)
54 #if BITS_PER_LONG == 64
55 /* 64x64-bit multiply is efficient on all 64-bit processors */
56 return val * GOLDEN_RATIO_64 >> (64 - bits);
58 /* Hash 64 bits using only 32x32-bit multiply. */
59 return cfs_hash_32(((u32)val ^ ((val >> 32) * GOLDEN_RATIO_32)), bits);
63 #if BITS_PER_LONG == 32
64 #define cfs_hash_long(val, bits) cfs_hash_32(val, bits)
65 #elif BITS_PER_LONG == 64
66 #define cfs_hash_long(val, bits) cfs_hash_64(val, bits)
68 #error Wordsize not 32 or 64
73 #define cfs_hash_32 hash_32
74 #define cfs_hash_64 hash_64
75 #define cfs_hash_long hash_long
77 #endif /* HAVE_BROKEN_HASH_64 */
79 #ifndef HAVE_RHASHTABLE_WALK_ENTER
80 static int rhashtable_walk_enter(struct rhashtable *ht,
81 struct rhashtable_iter *iter)
83 #ifdef HAVE_3ARG_RHASHTABLE_WALK_INIT
84 return rhashtable_walk_init(ht, iter, GFP_KERNEL);
86 return rhashtable_walk_init(ht, iter);
93 struct rhash_head rhead;
94 struct rhlist_head __rcu *next;
101 #define rhl_for_each_entry_rcu(tpos, pos, list, member) \
102 for (pos = list; pos && rht_entry(tpos, pos, member); \
103 pos = rcu_dereference_raw(pos->next))
105 static inline int rhltable_init(struct rhltable *hlt,
106 const struct rhashtable_params *params)
108 return rhashtable_init(&hlt->ht, params);
111 static inline struct rhlist_head *rhltable_lookup(
112 struct rhltable *hlt, const void *key,
113 const struct rhashtable_params params)
115 struct rhashtable *ht = &hlt->ht;
116 struct rhashtable_compare_arg arg = {
120 struct bucket_table *tbl;
121 struct rhash_head *he;
124 tbl = rht_dereference_rcu(ht->tbl, ht);
126 hash = rht_key_hashfn(ht, tbl, key, params);
127 rht_for_each_rcu(he, tbl, hash) {
128 if (params.obj_cmpfn ?
129 params.obj_cmpfn(&arg, rht_obj(ht, he)) :
130 rhashtable_compare(&arg, rht_obj(ht, he)))
132 return he ? container_of(he, struct rhlist_head, rhead) : NULL;
135 /* Ensure we see any new tables. */
138 tbl = rht_dereference_rcu(tbl->future_tbl, ht);
145 static inline int rhltable_insert_key(
146 struct rhltable *hlt, const void *key, struct rhlist_head *list,
147 const struct rhashtable_params params)
149 #ifdef HAVE_HASHTABLE_INSERT_FAST_RETURN_INT
150 return __rhashtable_insert_fast(&hlt->ht, key, &list->rhead,
153 return PTR_ERR(__rhashtable_insert_fast(&hlt->ht, key, &list->rhead,
158 static inline int rhltable_remove(
159 struct rhltable *hlt, struct rhlist_head *list,
160 const struct rhashtable_params params)
162 return rhashtable_remove_fast(&hlt->ht, &list->rhead, params);
165 static inline void rhltable_free_and_destroy(struct rhltable *hlt,
166 void (*free_fn)(void *ptr,
170 rhashtable_free_and_destroy(&hlt->ht, free_fn, arg);
173 static inline void rhltable_destroy(struct rhltable *hlt)
175 rhltable_free_and_destroy(hlt, NULL, NULL);
178 static inline void rhltable_walk_enter(struct rhltable *hlt,
179 struct rhashtable_iter *iter)
181 rhashtable_walk_enter(&hlt->ht, iter);
183 #endif /* !HAVE_RHLTABLE */
185 #ifndef HAVE_RHASHTABLE_LOOKUP_GET_INSERT_FAST
187 * rhashtable_lookup_get_insert_fast - lookup and insert object into hash table
189 * @obj: pointer to hash head inside object
190 * @params: hash table parameters
192 * Just like rhashtable_lookup_insert_fast(), but this function returns the
193 * object if it exists, NULL if it did not and the insertion was successful,
194 * and an ERR_PTR otherwise.
196 static inline void *rhashtable_lookup_get_insert_fast(
197 struct rhashtable *ht, struct rhash_head *obj,
198 const struct rhashtable_params params)
204 rc = rhashtable_lookup_insert_fast(ht, obj, params);
207 key = rht_obj(ht, obj);
208 ret = rhashtable_lookup_fast(ht, key, params);
219 #endif /* !HAVE_RHASHTABLE_LOOKUP_GET_INSERT_FAST */
221 #ifndef HAVE_RHASHTABLE_LOOKUP
223 * The function rhashtable_lookup() and rhashtable_lookup_fast()
224 * are almost the same except rhashtable_lookup() doesn't
225 * take the RCU read lock. Since this is the case and only
226 * SLES12 SP3 lacks rhashtable_lookup() just duplicate the
227 * SLES12 SP3 rhashtable_lookup_fast() minus the RCU read lock.
229 static inline void *rhashtable_lookup(
230 struct rhashtable *ht, const void *key,
231 const struct rhashtable_params params)
233 struct rhashtable_compare_arg arg = {
237 const struct bucket_table *tbl;
238 struct rhash_head *he;
241 tbl = rht_dereference_rcu(ht->tbl, ht);
243 hash = rht_key_hashfn(ht, tbl, key, params);
244 rht_for_each_rcu(he, tbl, hash) {
245 if (params.obj_cmpfn ?
246 params.obj_cmpfn(&arg, rht_obj(ht, he)) :
247 rhashtable_compare(&arg, rht_obj(ht, he)))
249 return rht_obj(ht, he);
252 /* Ensure we see any new tables. */
255 tbl = rht_dereference_rcu(tbl->future_tbl, ht);
261 #endif /* !HAVE_RHASHTABLE_LOOKUP */
263 #ifndef HAVE_RHT_BUCKET_VAR
264 static inline struct rhash_head __rcu **rht_bucket_var(
265 struct bucket_table *tbl, unsigned int hash)
267 return &tbl->buckets[hash];
271 #ifndef HAVE_RHASHTABLE_REPLACE
272 /* Internal function, please use rhashtable_replace_fast() instead */
273 static inline int __rhashtable_replace_fast(
274 struct rhashtable *ht, struct bucket_table *tbl,
275 struct rhash_head *obj_old, struct rhash_head *obj_new,
276 const struct rhashtable_params params)
278 struct rhash_head __rcu **pprev;
279 struct rhash_head *he;
284 /* Minimally, the old and new objects must have same hash
285 * (which should mean identifiers are the same).
287 hash = rht_head_hashfn(ht, tbl, obj_old, params);
288 if (hash != rht_head_hashfn(ht, tbl, obj_new, params))
291 lock = rht_bucket_lock(tbl, hash);
295 pprev = rht_bucket_var(tbl, hash);
296 rht_for_each_continue(he, *pprev, tbl, hash) {
302 rcu_assign_pointer(obj_new->next, obj_old->next);
303 rcu_assign_pointer(*pprev, obj_new);
308 spin_unlock_bh(lock);
314 * rhashtable_replace_fast - replace an object in hash table
316 * @obj_old: pointer to hash head inside object being replaced
317 * @obj_new: pointer to hash head inside object which is new
318 * @params: hash table parameters
320 * Replacing an object doesn't affect the number of elements in the hash table
321 * or bucket, so we don't need to worry about shrinking or expanding the
324 * Returns zero on success, -ENOENT if the entry could not be found,
325 * -EINVAL if hash is not the same for the old and new objects.
327 static inline int rhashtable_replace_fast(
328 struct rhashtable *ht, struct rhash_head *obj_old,
329 struct rhash_head *obj_new,
330 const struct rhashtable_params params)
332 struct bucket_table *tbl;
337 tbl = rht_dereference_rcu(ht->tbl, ht);
339 /* Because we have already taken (and released) the bucket
340 * lock in old_tbl, if we find that future_tbl is not yet
341 * visible then that guarantees the entry to still be in
342 * the old tbl if it exists.
344 while ((err = __rhashtable_replace_fast(ht, tbl, obj_old,
346 (tbl = rht_dereference_rcu(tbl->future_tbl, ht)))
353 #endif /* HAVE_RHASHTABLE_REPLACE */
355 #endif /* __LIBCFS_LINUX_HASH_H__ */