xref: /freebsd-src/sys/compat/linuxkpi/common/include/linux/hashtable.h (revision 7e77089dccd702eb767350a8bd3d20102c4fb591)
1*f9e90c24SHans Petter Selasky /*-
2*f9e90c24SHans Petter Selasky  * SPDX-License-Identifier: BSD-2-Clause
3*f9e90c24SHans Petter Selasky  *
4*f9e90c24SHans Petter Selasky  * Copyright (c) 2022 NVIDIA corporation & affiliates.
5*f9e90c24SHans Petter Selasky  *
6*f9e90c24SHans Petter Selasky  * Redistribution and use in source and binary forms, with or without
7*f9e90c24SHans Petter Selasky  * modification, are permitted provided that the following conditions
8*f9e90c24SHans Petter Selasky  * are met:
9*f9e90c24SHans Petter Selasky  * 1. Redistributions of source code must retain the above copyright
10*f9e90c24SHans Petter Selasky  *    notice unmodified, this list of conditions, and the following
11*f9e90c24SHans Petter Selasky  *    disclaimer.
12*f9e90c24SHans Petter Selasky  * 2. Redistributions in binary form must reproduce the above copyright
13*f9e90c24SHans Petter Selasky  *    notice, this list of conditions and the following disclaimer in the
14*f9e90c24SHans Petter Selasky  *    documentation and/or other materials provided with the distribution.
15*f9e90c24SHans Petter Selasky  *
16*f9e90c24SHans Petter Selasky  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17*f9e90c24SHans Petter Selasky  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18*f9e90c24SHans Petter Selasky  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19*f9e90c24SHans Petter Selasky  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20*f9e90c24SHans Petter Selasky  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21*f9e90c24SHans Petter Selasky  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22*f9e90c24SHans Petter Selasky  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23*f9e90c24SHans Petter Selasky  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24*f9e90c24SHans Petter Selasky  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25*f9e90c24SHans Petter Selasky  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*f9e90c24SHans Petter Selasky  */
27*f9e90c24SHans Petter Selasky 
28*f9e90c24SHans Petter Selasky #ifndef _LINUXKPI_LINUX_HASHTABLE_H
29*f9e90c24SHans Petter Selasky #define	_LINUXKPI_LINUX_HASHTABLE_H
30*f9e90c24SHans Petter Selasky 
31*f9e90c24SHans Petter Selasky #include <sys/param.h>
32*f9e90c24SHans Petter Selasky #include <sys/systm.h>
33*f9e90c24SHans Petter Selasky 
34*f9e90c24SHans Petter Selasky #include <linux/hash.h>
35*f9e90c24SHans Petter Selasky #include <linux/kernel.h>
36*f9e90c24SHans Petter Selasky #include <linux/list.h>
37*f9e90c24SHans Petter Selasky #include <linux/log2.h>
38*f9e90c24SHans Petter Selasky #include <linux/rcupdate.h>
39*f9e90c24SHans Petter Selasky #include <linux/rculist.h>
40*f9e90c24SHans Petter Selasky 
41*f9e90c24SHans Petter Selasky #include <ck_queue.h>
42*f9e90c24SHans Petter Selasky 
43*f9e90c24SHans Petter Selasky struct lkpi_hash_entry {
44*f9e90c24SHans Petter Selasky 	CK_LIST_ENTRY(lkpi_hash_entry) entry;
45*f9e90c24SHans Petter Selasky };
46*f9e90c24SHans Petter Selasky 
47*f9e90c24SHans Petter Selasky struct lkpi_hash_head {
48*f9e90c24SHans Petter Selasky 	CK_LIST_HEAD(, lkpi_hash_entry) head;
49*f9e90c24SHans Petter Selasky };
50*f9e90c24SHans Petter Selasky 
51*f9e90c24SHans Petter Selasky #define	DEFINE_HASHTABLE(name, bits) \
52*f9e90c24SHans Petter Selasky 	struct lkpi_hash_head name[1UL << (bits)]
53*f9e90c24SHans Petter Selasky 
54*f9e90c24SHans Petter Selasky #define	DEFINE_READ_MOSTLY_HASHTABLE(name, bits) \
55*f9e90c24SHans Petter Selasky 	struct lkpi_hash_head name[1UL << (bits)] __read_mostly
56*f9e90c24SHans Petter Selasky 
57*f9e90c24SHans Petter Selasky #define	DECLARE_HASHTABLE(name, bits) \
58*f9e90c24SHans Petter Selasky 	struct lkpi_hash_head name[1UL << (bits)]
59*f9e90c24SHans Petter Selasky 
60*f9e90c24SHans Petter Selasky #define	HASH_SIZE(name) ARRAY_SIZE(name)
61*f9e90c24SHans Petter Selasky #define	HASH_BITS(name) ilog2(HASH_SIZE(name))
62*f9e90c24SHans Petter Selasky 
63*f9e90c24SHans Petter Selasky #define	hash_min(...) \
64*f9e90c24SHans Petter Selasky 	hash_long(__VA_ARGS__)
65*f9e90c24SHans Petter Selasky 
66*f9e90c24SHans Petter Selasky static inline void
__hash_init(struct lkpi_hash_head * ht,unsigned long size)67*f9e90c24SHans Petter Selasky __hash_init(struct lkpi_hash_head *ht, unsigned long size)
68*f9e90c24SHans Petter Selasky {
69*f9e90c24SHans Petter Selasky 	unsigned long x;
70*f9e90c24SHans Petter Selasky 
71*f9e90c24SHans Petter Selasky 	for (x = 0; x != size; x++)
72*f9e90c24SHans Petter Selasky 		CK_LIST_INIT(&ht[x].head);
73*f9e90c24SHans Petter Selasky }
74*f9e90c24SHans Petter Selasky 
75*f9e90c24SHans Petter Selasky #define	hash_init(ht) \
76*f9e90c24SHans Petter Selasky 	__hash_init(ht, HASH_SIZE(ht))
77*f9e90c24SHans Petter Selasky 
78*f9e90c24SHans Petter Selasky #define	hash_add(...) \
79*f9e90c24SHans Petter Selasky 	hash_add_rcu(__VA_ARGS__)
80*f9e90c24SHans Petter Selasky 
81*f9e90c24SHans Petter Selasky static inline void
__hash_node_type_assert(struct hlist_node * node)82*f9e90c24SHans Petter Selasky __hash_node_type_assert(struct hlist_node *node)
83*f9e90c24SHans Petter Selasky {
84*f9e90c24SHans Petter Selasky 	/*
85*f9e90c24SHans Petter Selasky 	 * Unfortunately Linux doesn't have an own type for the hash
86*f9e90c24SHans Petter Selasky 	 * table node entries. The purpose of this function is simply
87*f9e90c24SHans Petter Selasky 	 * to check the type of the passed argument.
88*f9e90c24SHans Petter Selasky 	 */
89*f9e90c24SHans Petter Selasky 	CTASSERT(sizeof(struct lkpi_hash_entry) == sizeof(*node));
90*f9e90c24SHans Petter Selasky }
91*f9e90c24SHans Petter Selasky 
92*f9e90c24SHans Petter Selasky #define	hash_add_rcu(ht, node, key) do {				\
93*f9e90c24SHans Petter Selasky 	struct lkpi_hash_head *__head = &(ht)[hash_min(key, HASH_BITS(ht))]; \
94*f9e90c24SHans Petter Selasky 	__hash_node_type_assert(node); \
95*f9e90c24SHans Petter Selasky 	CK_LIST_INSERT_HEAD(&__head->head, \
96*f9e90c24SHans Petter Selasky 	    (struct lkpi_hash_entry *)(node), entry); \
97*f9e90c24SHans Petter Selasky } while (0)
98*f9e90c24SHans Petter Selasky 
99*f9e90c24SHans Petter Selasky static inline bool
hash_hashed(struct hlist_node * node)100*f9e90c24SHans Petter Selasky hash_hashed(struct hlist_node *node)
101*f9e90c24SHans Petter Selasky {
102*f9e90c24SHans Petter Selasky 	return (((struct lkpi_hash_entry *)node)->entry.cle_prev != NULL);
103*f9e90c24SHans Petter Selasky }
104*f9e90c24SHans Petter Selasky 
105*f9e90c24SHans Petter Selasky static inline bool
__hash_empty(struct lkpi_hash_head * ht,unsigned long size)106*f9e90c24SHans Petter Selasky __hash_empty(struct lkpi_hash_head *ht, unsigned long size)
107*f9e90c24SHans Petter Selasky {
108*f9e90c24SHans Petter Selasky 	unsigned long x;
109*f9e90c24SHans Petter Selasky 
110*f9e90c24SHans Petter Selasky 	for (x = 0; x != size; x++) {
111*f9e90c24SHans Petter Selasky 		if (!CK_LIST_EMPTY(&ht[x].head))
112*f9e90c24SHans Petter Selasky 			return (false);
113*f9e90c24SHans Petter Selasky 	}
114*f9e90c24SHans Petter Selasky 	return (true);
115*f9e90c24SHans Petter Selasky }
116*f9e90c24SHans Petter Selasky 
117*f9e90c24SHans Petter Selasky #define	hash_empty(ht) \
118*f9e90c24SHans Petter Selasky 	__hash_empty(ht, HASH_SIZE(ht))
119*f9e90c24SHans Petter Selasky 
120*f9e90c24SHans Petter Selasky #define	hash_del(...) \
121*f9e90c24SHans Petter Selasky 	hash_del_rcu(__VA_ARGS__)
122*f9e90c24SHans Petter Selasky 
123*f9e90c24SHans Petter Selasky static inline void
hash_del_rcu(struct hlist_node * node)124*f9e90c24SHans Petter Selasky hash_del_rcu(struct hlist_node *node)
125*f9e90c24SHans Petter Selasky {
126*f9e90c24SHans Petter Selasky 	CK_LIST_REMOVE((struct lkpi_hash_entry *)node, entry);
127*f9e90c24SHans Petter Selasky 	memset(node, 0, sizeof(*node));
128*f9e90c24SHans Petter Selasky }
129*f9e90c24SHans Petter Selasky 
130*f9e90c24SHans Petter Selasky #define	__hash_first(ht, type, member) ({ \
131*f9e90c24SHans Petter Selasky 	const struct lkpi_hash_entry *__first = CK_LIST_FIRST(&(ht)->head); \
132*f9e90c24SHans Petter Selasky 	__hash_node_type_assert(&((type *)0)->member); \
133*f9e90c24SHans Petter Selasky 	(__first != NULL ? container_of((const void *)__first, type, member) : NULL); \
134*f9e90c24SHans Petter Selasky })
135*f9e90c24SHans Petter Selasky 
136*f9e90c24SHans Petter Selasky #define	__hash_next(obj, type, member) ({ \
137*f9e90c24SHans Petter Selasky 	const struct lkpi_hash_entry *__next = \
138*f9e90c24SHans Petter Selasky 	    CK_LIST_NEXT((struct lkpi_hash_entry *)&(obj)->member, entry); \
139*f9e90c24SHans Petter Selasky 	__hash_node_type_assert(&(obj)->member); \
140*f9e90c24SHans Petter Selasky 	(__next != NULL ? container_of((const void *)__next, type, member) : NULL); \
141*f9e90c24SHans Petter Selasky })
142*f9e90c24SHans Petter Selasky 
143*f9e90c24SHans Petter Selasky #define	hash_for_each(...) \
144*f9e90c24SHans Petter Selasky 	hash_for_each_rcu(__VA_ARGS__)
145*f9e90c24SHans Petter Selasky 
146*f9e90c24SHans Petter Selasky #define	hash_for_each_rcu(name, bkt, obj, member) \
147*f9e90c24SHans Petter Selasky 	for ((bkt) = 0, (obj) = NULL; (obj) == NULL && \
148*f9e90c24SHans Petter Selasky 	       (bkt) != HASH_SIZE(name); (bkt)++) \
149*f9e90c24SHans Petter Selasky 		for ((obj) = __hash_first(&(name)[bkt], \
150*f9e90c24SHans Petter Selasky 			__typeof(*(obj)), member); \
151*f9e90c24SHans Petter Selasky 		     (obj) != NULL; \
152*f9e90c24SHans Petter Selasky 		     (obj) = __hash_next(obj, \
153*f9e90c24SHans Petter Selasky 			__typeof(*(obj)), member))
154*f9e90c24SHans Petter Selasky 
155*f9e90c24SHans Petter Selasky #define	hash_for_each_safe(name, bkt, tmp, obj, member) \
156*f9e90c24SHans Petter Selasky 	for ((bkt) = 0, (obj) = NULL; (obj) == NULL && \
157*f9e90c24SHans Petter Selasky 	       (bkt) != HASH_SIZE(name); (bkt)++) \
158*f9e90c24SHans Petter Selasky 		for ((obj) = __hash_first(&(name)[bkt], \
159*f9e90c24SHans Petter Selasky 			__typeof(*(obj)), member); \
160*f9e90c24SHans Petter Selasky 		     (obj) != NULL && ((tmp) = &__hash_next(obj, \
161*f9e90c24SHans Petter Selasky 			__typeof(*(obj)), member)->member, 1); \
162*f9e90c24SHans Petter Selasky 		     (obj) = container_of(tmp, __typeof(*(obj)), member))
163*f9e90c24SHans Petter Selasky 
164*f9e90c24SHans Petter Selasky #define	hash_for_each_possible(...) \
165*f9e90c24SHans Petter Selasky 	hash_for_each_possible_rcu(__VA_ARGS__)
166*f9e90c24SHans Petter Selasky 
167*f9e90c24SHans Petter Selasky #define	hash_for_each_possible_rcu_notrace(...) \
168*f9e90c24SHans Petter Selasky 	hash_for_each_possible_rcu(__VA_ARGS__)
169*f9e90c24SHans Petter Selasky 
170*f9e90c24SHans Petter Selasky #define	hash_for_each_possible_rcu(name, obj, member, key) \
171*f9e90c24SHans Petter Selasky 	for ((obj) = __hash_first(&(name)[hash_min(key, HASH_BITS(name))], \
172*f9e90c24SHans Petter Selasky 		__typeof(*(obj)), member); \
173*f9e90c24SHans Petter Selasky 	     (obj) != NULL; \
174*f9e90c24SHans Petter Selasky 	     (obj) = __hash_next(obj, __typeof(*(obj)), member))
175*f9e90c24SHans Petter Selasky 
176*f9e90c24SHans Petter Selasky #define	hash_for_each_possible_safe(name, obj, tmp, member, key) \
177*f9e90c24SHans Petter Selasky 	for ((obj) = __hash_first(&(name)[hash_min(key, HASH_BITS(name))], \
178*f9e90c24SHans Petter Selasky 		__typeof(*(obj)), member); \
179*f9e90c24SHans Petter Selasky 	     (obj) != NULL && ((tmp) = &__hash_next(obj, \
180*f9e90c24SHans Petter Selasky 		__typeof(*(obj)), member)->member, 1); \
181*f9e90c24SHans Petter Selasky 	     (obj) = container_of(tmp, __typeof(*(obj)), member))
182*f9e90c24SHans Petter Selasky 
183*f9e90c24SHans Petter Selasky #endif					/* _LINUXKPI_LINUX_HASHTABLE_H */
184