1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * drivers/block/zram/zram_group/zlist.c
4 *
5 * Copyright (c) 2020-2022 Huawei Technologies Co., Ltd.
6 */
7
8 #define pr_fmt(fmt) "[ZLIST]" fmt
9
10 #include <linux/kernel.h>
11 #include <linux/slab.h>
12 #include <linux/bit_spinlock.h>
13
14 #include "zlist.h"
15
16 #define assert(expr) \
17 do { \
18 if (expr) \
19 break; \
20 pr_err("assertion [%s] failed: in func<%s> at %s:%d\n", \
21 #expr, __func__, __FILE__, __LINE__); \
22 BUG(); \
23 } while (0)
24
zlist_node_lock(struct zlist_node * node)25 static inline void zlist_node_lock(struct zlist_node *node)
26 {
27 bit_spin_lock(ZLIST_LOCK_BIT, (unsigned long *)node);
28 }
29
zlist_node_unlock(struct zlist_node * node)30 static inline void zlist_node_unlock(struct zlist_node *node)
31 {
32 bit_spin_unlock(ZLIST_LOCK_BIT, (unsigned long *)node);
33 }
34
35 #ifdef CONFIG_ZLIST_DEBUG
zlist_before_add_check(struct zlist_table * tab,struct zlist_node * prev,struct zlist_node * node,struct zlist_node * next)36 static inline void zlist_before_add_check(struct zlist_table *tab,
37 struct zlist_node *prev, struct zlist_node *node,
38 struct zlist_node *next)
39 {
40 assert(idx2node(prev->next, tab) == next);
41 assert(idx2node(next->prev, tab) == prev);
42 assert(idx2node(node->prev, tab) == node);
43 assert(idx2node(node->next, tab) == node);
44 }
45
zlist_after_add_check(struct zlist_table * tab,struct zlist_node * prev,struct zlist_node * node,struct zlist_node * next)46 static inline void zlist_after_add_check(struct zlist_table *tab,
47 struct zlist_node *prev, struct zlist_node *node,
48 struct zlist_node *next)
49 {
50 assert(idx2node(prev->next, tab) == node);
51 assert(idx2node(next->prev, tab) == node);
52 assert(idx2node(node->prev, tab) == prev);
53 assert(idx2node(node->next, tab) == next);
54 }
55
zlist_before_del_check(struct zlist_table * tab,struct zlist_node * prev,struct zlist_node * node,struct zlist_node * next)56 static inline void zlist_before_del_check(struct zlist_table *tab,
57 struct zlist_node *prev, struct zlist_node *node,
58 struct zlist_node *next)
59 {
60 assert(idx2node(prev->next, tab) == node);
61 assert(idx2node(next->prev, tab) == node);
62 assert(idx2node(node->prev, tab) == prev);
63 assert(idx2node(node->next, tab) == next);
64 }
65
zlist_after_del_check(struct zlist_table * tab,struct zlist_node * prev,struct zlist_node * node,struct zlist_node * next)66 static inline void zlist_after_del_check(struct zlist_table *tab,
67 struct zlist_node *prev, struct zlist_node *node,
68 struct zlist_node *next)
69 {
70 assert(idx2node(prev->next, tab) == next);
71 assert(idx2node(next->prev, tab) == prev);
72 assert(idx2node(node->prev, tab) == node);
73 assert(idx2node(node->next, tab) == node);
74 }
75 #else
zlist_before_add_check(struct zlist_table * tab,struct zlist_node * prev,struct zlist_node * node,struct zlist_node * next)76 static inline void zlist_before_add_check(struct zlist_table *tab,
77 struct zlist_node *prev, struct zlist_node *node,
78 struct zlist_node *next) {};
zlist_after_add_check(struct zlist_table * tab,struct zlist_node * prev,struct zlist_node * node,struct zlist_node * next)79 static inline void zlist_after_add_check(struct zlist_table *tab,
80 struct zlist_node *prev, struct zlist_node *node,
81 struct zlist_node *next) {};
zlist_before_del_check(struct zlist_table * tab,struct zlist_node * prev,struct zlist_node * node,struct zlist_node * next)82 static inline void zlist_before_del_check(struct zlist_table *tab,
83 struct zlist_node *prev, struct zlist_node *node,
84 struct zlist_node *next) {};
zlist_after_del_check(struct zlist_table * tab,struct zlist_node * prev,struct zlist_node * node,struct zlist_node * next)85 static inline void zlist_after_del_check(struct zlist_table *tab,
86 struct zlist_node *prev, struct zlist_node *node,
87 struct zlist_node *next) {};
88 #endif
89
zlist_table_alloc(struct zlist_node * (* i2n)(u32,void *),void * private,gfp_t gfp)90 struct zlist_table *zlist_table_alloc(struct zlist_node *(*i2n)(u32, void*),
91 void *private, gfp_t gfp)
92 {
93 struct zlist_table *tab = kmalloc(sizeof(struct zlist_table), gfp);
94
95 if (!tab)
96 return NULL;
97 tab->idx2node = i2n;
98 tab->private = private;
99
100 return tab;
101 }
102
zlist_lock(u32 idx,struct zlist_table * tab)103 void zlist_lock(u32 idx, struct zlist_table *tab)
104 {
105 zlist_node_lock(idx2node(idx, tab));
106 }
107
zlist_unlock(u32 idx,struct zlist_table * tab)108 void zlist_unlock(u32 idx, struct zlist_table *tab)
109 {
110 zlist_node_unlock(idx2node(idx, tab));
111 }
112
zlist_add_nolock(u32 hid,u32 idx,struct zlist_table * tab)113 void zlist_add_nolock(u32 hid, u32 idx, struct zlist_table *tab)
114 {
115 struct zlist_node *node = idx2node(idx, tab);
116 struct zlist_node *head = idx2node(hid, tab);
117 u32 nid = head->next;
118 struct zlist_node *next = idx2node(nid, tab);
119
120 zlist_before_add_check(tab, head, node, next);
121 if (idx != hid)
122 zlist_node_lock(node);
123 node->prev = hid;
124 node->next = nid;
125 if (idx != hid)
126 zlist_node_unlock(node);
127 head->next = idx;
128 if (nid != hid)
129 zlist_node_lock(next);
130 next->prev = idx;
131 if (nid != hid)
132 zlist_node_unlock(next);
133 zlist_after_add_check(tab, head, node, next);
134 }
135
zlist_add_tail_nolock(u32 hid,u32 idx,struct zlist_table * tab)136 void zlist_add_tail_nolock(u32 hid, u32 idx, struct zlist_table *tab)
137 {
138 struct zlist_node *node = idx2node(idx, tab);
139 struct zlist_node *head = idx2node(hid, tab);
140 u32 tid = head->prev;
141 struct zlist_node *tail = idx2node(tid, tab);
142
143 zlist_before_add_check(tab, tail, node, head);
144 if (idx != hid)
145 zlist_node_lock(node);
146 node->prev = tid;
147 node->next = hid;
148 if (idx != hid)
149 zlist_node_unlock(node);
150 head->prev = idx;
151 if (tid != hid)
152 zlist_node_lock(tail);
153 tail->next = idx;
154 if (tid != hid)
155 zlist_node_unlock(tail);
156 zlist_after_add_check(tab, tail, node, head);
157 }
158
zlist_del_nolock(u32 hid,u32 idx,struct zlist_table * tab)159 bool zlist_del_nolock(u32 hid, u32 idx, struct zlist_table *tab)
160 {
161 struct zlist_node *node = idx2node(idx, tab);
162 u32 pid = node->prev;
163 u32 nid = node->next;
164 struct zlist_node *prev = idx2node(pid, tab);
165 struct zlist_node *next = idx2node(nid, tab);
166
167 zlist_before_del_check(tab, prev, node, next);
168 if (idx != hid)
169 zlist_node_lock(node);
170 node->prev = idx;
171 node->next = idx;
172 if (idx != hid)
173 zlist_node_unlock(node);
174 if (pid != hid)
175 zlist_node_lock(prev);
176 prev->next = nid;
177 if (pid != hid)
178 zlist_node_unlock(prev);
179 if (nid != hid)
180 zlist_node_lock(next);
181 next->prev = pid;
182 if (nid != hid)
183 zlist_node_unlock(next);
184 zlist_after_del_check(tab, prev, node, next);
185
186 return zlist_is_isolated_nolock(hid, tab);
187 }
188
zlist_is_isolated_nolock(u32 idx,struct zlist_table * tab)189 bool zlist_is_isolated_nolock(u32 idx, struct zlist_table *tab)
190 {
191 struct zlist_node *node = idx2node(idx, tab);
192
193 return (node->prev == idx) && (node->next == idx);
194 }
195
zlist_set_priv(u32 idx,struct zlist_table * tab)196 bool zlist_set_priv(u32 idx, struct zlist_table *tab)
197 {
198 struct zlist_node *node = idx2node(idx, tab);
199 bool ret = false;
200
201 zlist_node_lock(node);
202 ret = !test_and_set_bit(ZLIST_PRIV_BIT, (unsigned long *)node);
203 zlist_node_unlock(node);
204
205 return ret;
206 }
207
zlist_clr_priv(u32 idx,struct zlist_table * tab)208 bool zlist_clr_priv(u32 idx, struct zlist_table *tab)
209 {
210 struct zlist_node *node = idx2node(idx, tab);
211 bool ret = false;
212
213 zlist_node_lock(node);
214 ret = !test_and_clear_bit(ZLIST_PRIV_BIT, (unsigned long *)node);
215 zlist_node_unlock(node);
216
217 return ret;
218 }
219
zlist_node_init(u32 idx,struct zlist_table * tab)220 void zlist_node_init(u32 idx, struct zlist_table *tab)
221 {
222 struct zlist_node *node = idx2node(idx, tab);
223
224 memset(node, 0, sizeof(struct zlist_node));
225 node->prev = idx;
226 node->next = idx;
227 }
228