1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _LINUX_LIST_NULLS_H
3 #define _LINUX_LIST_NULLS_H
4 
5 #include <linux/poison.h>
6 #include <linux/const.h>
7 
8 /*
9  * Special version of lists, where end of list is not a NULL pointer,
10  * but a 'nulls' marker, which can have many different values.
11  * (up to 2^31 different values guaranteed on all platforms)
12  *
13  * In the standard hlist, termination of a list is the NULL pointer.
14  * In this special 'nulls' variant, we use the fact that objects stored in
15  * a list are aligned on a word (4 or 8 bytes alignment).
16  * We therefore use the last significant bit of 'ptr' :
17  * Set to 1 : This is a 'nulls' end-of-list marker (ptr >> 1)
18  * Set to 0 : This is a pointer to some object (ptr)
19  */
20 
21 struct hlist_nulls_head {
22 	struct hlist_nulls_node *first;
23 };
24 
25 struct hlist_nulls_node {
26 	struct hlist_nulls_node *next, **pprev;
27 };
28 #define NULLS_MARKER(value) (1UL | (((long)value) << 1))
29 #define INIT_HLIST_NULLS_HEAD(ptr, nulls) \
30 	((ptr)->first = (struct hlist_nulls_node *) NULLS_MARKER(nulls))
31 #define HLIST_NULLS_HEAD_INIT(nulls) {.first = (struct hlist_nulls_node *)NULLS_MARKER(nulls)}
32 
33 #define hlist_nulls_entry(ptr, type, member) container_of(ptr,type,member)
34 
35 #define hlist_nulls_entry_safe(ptr, type, member) \
36 	({ typeof(ptr) ____ptr = (ptr); \
37 	   !is_a_nulls(____ptr) ? hlist_nulls_entry(____ptr, type, member) : NULL; \
38 	})
39 /**
40  * ptr_is_a_nulls - Test if a ptr is a nulls
41  * @ptr: ptr to be tested
42  *
43  */
is_a_nulls(const struct hlist_nulls_node * ptr)44 static inline int is_a_nulls(const struct hlist_nulls_node *ptr)
45 {
46 	return ((unsigned long)ptr & 1);
47 }
48 
49 /**
50  * get_nulls_value - Get the 'nulls' value of the end of chain
51  * @ptr: end of chain
52  *
53  * Should be called only if is_a_nulls(ptr);
54  */
get_nulls_value(const struct hlist_nulls_node * ptr)55 static inline unsigned long get_nulls_value(const struct hlist_nulls_node *ptr)
56 {
57 	return ((unsigned long)ptr) >> 1;
58 }
59 
60 /**
61  * hlist_nulls_unhashed - Has node been removed and reinitialized?
62  * @h: Node to be checked
63  *
64  * Not that not all removal functions will leave a node in unhashed state.
65  * For example, hlist_del_init_rcu() leaves the node in unhashed state,
66  * but hlist_nulls_del() does not.
67  */
hlist_nulls_unhashed(const struct hlist_nulls_node * h)68 static inline int hlist_nulls_unhashed(const struct hlist_nulls_node *h)
69 {
70 	return !h->pprev;
71 }
72 
73 /**
74  * hlist_nulls_unhashed_lockless - Has node been removed and reinitialized?
75  * @h: Node to be checked
76  *
77  * Not that not all removal functions will leave a node in unhashed state.
78  * For example, hlist_del_init_rcu() leaves the node in unhashed state,
79  * but hlist_nulls_del() does not.  Unlike hlist_nulls_unhashed(), this
80  * function may be used locklessly.
81  */
hlist_nulls_unhashed_lockless(const struct hlist_nulls_node * h)82 static inline int hlist_nulls_unhashed_lockless(const struct hlist_nulls_node *h)
83 {
84 	return !READ_ONCE(h->pprev);
85 }
86 
hlist_nulls_empty(const struct hlist_nulls_head * h)87 static inline int hlist_nulls_empty(const struct hlist_nulls_head *h)
88 {
89 	return is_a_nulls(READ_ONCE(h->first));
90 }
91 
hlist_nulls_add_head(struct hlist_nulls_node * n,struct hlist_nulls_head * h)92 static inline void hlist_nulls_add_head(struct hlist_nulls_node *n,
93 					struct hlist_nulls_head *h)
94 {
95 	struct hlist_nulls_node *first = h->first;
96 
97 	n->next = first;
98 	WRITE_ONCE(n->pprev, &h->first);
99 	h->first = n;
100 	if (!is_a_nulls(first))
101 		WRITE_ONCE(first->pprev, &n->next);
102 }
103 
__hlist_nulls_del(struct hlist_nulls_node * n)104 static inline void __hlist_nulls_del(struct hlist_nulls_node *n)
105 {
106 	struct hlist_nulls_node *next = n->next;
107 	struct hlist_nulls_node **pprev = n->pprev;
108 
109 	WRITE_ONCE(*pprev, next);
110 	if (!is_a_nulls(next))
111 		WRITE_ONCE(next->pprev, pprev);
112 }
113 
hlist_nulls_del(struct hlist_nulls_node * n)114 static inline void hlist_nulls_del(struct hlist_nulls_node *n)
115 {
116 	__hlist_nulls_del(n);
117 	WRITE_ONCE(n->pprev, LIST_POISON2);
118 }
119 
120 /**
121  * hlist_nulls_for_each_entry	- iterate over list of given type
122  * @tpos:	the type * to use as a loop cursor.
123  * @pos:	the &struct hlist_node to use as a loop cursor.
124  * @head:	the head for your list.
125  * @member:	the name of the hlist_node within the struct.
126  *
127  */
128 #define hlist_nulls_for_each_entry(tpos, pos, head, member)		       \
129 	for (pos = (head)->first;					       \
130 	     (!is_a_nulls(pos)) &&					       \
131 		({ tpos = hlist_nulls_entry(pos, typeof(*tpos), member); 1;}); \
132 	     pos = pos->next)
133 
134 /**
135  * hlist_nulls_for_each_entry_from - iterate over a hlist continuing from current point
136  * @tpos:	the type * to use as a loop cursor.
137  * @pos:	the &struct hlist_node to use as a loop cursor.
138  * @member:	the name of the hlist_node within the struct.
139  *
140  */
141 #define hlist_nulls_for_each_entry_from(tpos, pos, member)	\
142 	for (; (!is_a_nulls(pos)) && 				\
143 		({ tpos = hlist_nulls_entry(pos, typeof(*tpos), member); 1;}); \
144 	     pos = pos->next)
145 
146 #endif
147