• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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