These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / include / linux / list_bl.h
1 #ifndef _LINUX_LIST_BL_H
2 #define _LINUX_LIST_BL_H
3
4 #include <linux/list.h>
5 #include <linux/spinlock.h>
6 #include <linux/bit_spinlock.h>
7
8 /*
9  * Special version of lists, where head of the list has a lock in the lowest
10  * bit. This is useful for scalable hash tables without increasing memory
11  * footprint overhead.
12  *
13  * For modification operations, the 0 bit of hlist_bl_head->first
14  * pointer must be set.
15  *
16  * With some small modifications, this can easily be adapted to store several
17  * arbitrary bits (not just a single lock bit), if the need arises to store
18  * some fast and compact auxiliary data.
19  */
20
21 #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
22 #define LIST_BL_LOCKMASK        1UL
23 #else
24 #define LIST_BL_LOCKMASK        0UL
25 #endif
26
27 #ifdef CONFIG_DEBUG_LIST
28 #define LIST_BL_BUG_ON(x) BUG_ON(x)
29 #else
30 #define LIST_BL_BUG_ON(x)
31 #endif
32
33
34 struct hlist_bl_head {
35         struct hlist_bl_node *first;
36 #ifdef CONFIG_PREEMPT_RT_BASE
37         raw_spinlock_t lock;
38 #endif
39 };
40
41 struct hlist_bl_node {
42         struct hlist_bl_node *next, **pprev;
43 };
44
45 #ifdef CONFIG_PREEMPT_RT_BASE
46 #define INIT_HLIST_BL_HEAD(h)           \
47 do {                                    \
48         (h)->first = NULL;              \
49         raw_spin_lock_init(&(h)->lock); \
50 } while (0)
51 #else
52 #define INIT_HLIST_BL_HEAD(h) (h)->first = NULL
53 #endif
54
55 static inline void INIT_HLIST_BL_NODE(struct hlist_bl_node *h)
56 {
57         h->next = NULL;
58         h->pprev = NULL;
59 }
60
61 #define hlist_bl_entry(ptr, type, member) container_of(ptr,type,member)
62
63 static inline int hlist_bl_unhashed(const struct hlist_bl_node *h)
64 {
65         return !h->pprev;
66 }
67
68 static inline struct hlist_bl_node *hlist_bl_first(struct hlist_bl_head *h)
69 {
70         return (struct hlist_bl_node *)
71                 ((unsigned long)h->first & ~LIST_BL_LOCKMASK);
72 }
73
74 static inline void hlist_bl_set_first(struct hlist_bl_head *h,
75                                         struct hlist_bl_node *n)
76 {
77         LIST_BL_BUG_ON((unsigned long)n & LIST_BL_LOCKMASK);
78         LIST_BL_BUG_ON(((unsigned long)h->first & LIST_BL_LOCKMASK) !=
79                                                         LIST_BL_LOCKMASK);
80         h->first = (struct hlist_bl_node *)((unsigned long)n | LIST_BL_LOCKMASK);
81 }
82
83 static inline int hlist_bl_empty(const struct hlist_bl_head *h)
84 {
85         return !((unsigned long)h->first & ~LIST_BL_LOCKMASK);
86 }
87
88 static inline void hlist_bl_add_head(struct hlist_bl_node *n,
89                                         struct hlist_bl_head *h)
90 {
91         struct hlist_bl_node *first = hlist_bl_first(h);
92
93         n->next = first;
94         if (first)
95                 first->pprev = &n->next;
96         n->pprev = &h->first;
97         hlist_bl_set_first(h, n);
98 }
99
100 static inline void __hlist_bl_del(struct hlist_bl_node *n)
101 {
102         struct hlist_bl_node *next = n->next;
103         struct hlist_bl_node **pprev = n->pprev;
104
105         LIST_BL_BUG_ON((unsigned long)n & LIST_BL_LOCKMASK);
106
107         /* pprev may be `first`, so be careful not to lose the lock bit */
108         WRITE_ONCE(*pprev,
109                    (struct hlist_bl_node *)
110                         ((unsigned long)next |
111                          ((unsigned long)*pprev & LIST_BL_LOCKMASK)));
112         if (next)
113                 next->pprev = pprev;
114 }
115
116 static inline void hlist_bl_del(struct hlist_bl_node *n)
117 {
118         __hlist_bl_del(n);
119         n->next = LIST_POISON1;
120         n->pprev = LIST_POISON2;
121 }
122
123 static inline void hlist_bl_del_init(struct hlist_bl_node *n)
124 {
125         if (!hlist_bl_unhashed(n)) {
126                 __hlist_bl_del(n);
127                 INIT_HLIST_BL_NODE(n);
128         }
129 }
130
131 static inline void hlist_bl_lock(struct hlist_bl_head *b)
132 {
133 #ifndef CONFIG_PREEMPT_RT_BASE
134         bit_spin_lock(0, (unsigned long *)b);
135 #else
136         raw_spin_lock(&b->lock);
137 #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
138         __set_bit(0, (unsigned long *)b);
139 #endif
140 #endif
141 }
142
143 static inline void hlist_bl_unlock(struct hlist_bl_head *b)
144 {
145 #ifndef CONFIG_PREEMPT_RT_BASE
146         __bit_spin_unlock(0, (unsigned long *)b);
147 #else
148 #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
149         __clear_bit(0, (unsigned long *)b);
150 #endif
151         raw_spin_unlock(&b->lock);
152 #endif
153 }
154
155 static inline bool hlist_bl_is_locked(struct hlist_bl_head *b)
156 {
157         return bit_spin_is_locked(0, (unsigned long *)b);
158 }
159
160 /**
161  * hlist_bl_for_each_entry      - iterate over list of given type
162  * @tpos:       the type * to use as a loop cursor.
163  * @pos:        the &struct hlist_node to use as a loop cursor.
164  * @head:       the head for your list.
165  * @member:     the name of the hlist_node within the struct.
166  *
167  */
168 #define hlist_bl_for_each_entry(tpos, pos, head, member)                \
169         for (pos = hlist_bl_first(head);                                \
170              pos &&                                                     \
171                 ({ tpos = hlist_bl_entry(pos, typeof(*tpos), member); 1;}); \
172              pos = pos->next)
173
174 /**
175  * hlist_bl_for_each_entry_safe - iterate over list of given type safe against removal of list entry
176  * @tpos:       the type * to use as a loop cursor.
177  * @pos:        the &struct hlist_node to use as a loop cursor.
178  * @n:          another &struct hlist_node to use as temporary storage
179  * @head:       the head for your list.
180  * @member:     the name of the hlist_node within the struct.
181  */
182 #define hlist_bl_for_each_entry_safe(tpos, pos, n, head, member)         \
183         for (pos = hlist_bl_first(head);                                 \
184              pos && ({ n = pos->next; 1; }) &&                           \
185                 ({ tpos = hlist_bl_entry(pos, typeof(*tpos), member); 1;}); \
186              pos = n)
187
188 #endif