1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38#include <linux/klist.h>
39#include <linux/module.h>
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55void klist_init(struct klist * k, void (*get)(struct klist_node *),
56 void (*put)(struct klist_node *))
57{
58 INIT_LIST_HEAD(&k->k_list);
59 spin_lock_init(&k->k_lock);
60 k->get = get;
61 k->put = put;
62}
63
64EXPORT_SYMBOL_GPL(klist_init);
65
66
67static void add_head(struct klist * k, struct klist_node * n)
68{
69 spin_lock(&k->k_lock);
70 list_add(&n->n_node, &k->k_list);
71 spin_unlock(&k->k_lock);
72}
73
74static void add_tail(struct klist * k, struct klist_node * n)
75{
76 spin_lock(&k->k_lock);
77 list_add_tail(&n->n_node, &k->k_list);
78 spin_unlock(&k->k_lock);
79}
80
81
82static void klist_node_init(struct klist * k, struct klist_node * n)
83{
84 INIT_LIST_HEAD(&n->n_node);
85 init_completion(&n->n_removed);
86 kref_init(&n->n_ref);
87 n->n_klist = k;
88 if (k->get)
89 k->get(n);
90}
91
92
93
94
95
96
97
98
99void klist_add_head(struct klist_node * n, struct klist * k)
100{
101 klist_node_init(k, n);
102 add_head(k, n);
103}
104
105EXPORT_SYMBOL_GPL(klist_add_head);
106
107
108
109
110
111
112
113
114void klist_add_tail(struct klist_node * n, struct klist * k)
115{
116 klist_node_init(k, n);
117 add_tail(k, n);
118}
119
120EXPORT_SYMBOL_GPL(klist_add_tail);
121
122
123static void klist_release(struct kref * kref)
124{
125 struct klist_node * n = container_of(kref, struct klist_node, n_ref);
126
127 list_del(&n->n_node);
128 complete(&n->n_removed);
129 n->n_klist = NULL;
130}
131
132static int klist_dec_and_del(struct klist_node * n)
133{
134 return kref_put(&n->n_ref, klist_release);
135}
136
137
138
139
140
141
142
143void klist_del(struct klist_node * n)
144{
145 struct klist * k = n->n_klist;
146 void (*put)(struct klist_node *) = k->put;
147
148 spin_lock(&k->k_lock);
149 if (!klist_dec_and_del(n))
150 put = NULL;
151 spin_unlock(&k->k_lock);
152 if (put)
153 put(n);
154}
155
156EXPORT_SYMBOL_GPL(klist_del);
157
158
159
160
161
162
163
164void klist_remove(struct klist_node * n)
165{
166 klist_del(n);
167 wait_for_completion(&n->n_removed);
168}
169
170EXPORT_SYMBOL_GPL(klist_remove);
171
172
173
174
175
176
177
178int klist_node_attached(struct klist_node * n)
179{
180 return (n->n_klist != NULL);
181}
182
183EXPORT_SYMBOL_GPL(klist_node_attached);
184
185
186
187
188
189
190
191
192
193
194
195
196void klist_iter_init_node(struct klist * k, struct klist_iter * i, struct klist_node * n)
197{
198 i->i_klist = k;
199 i->i_head = &k->k_list;
200 i->i_cur = n;
201 if (n)
202 kref_get(&n->n_ref);
203}
204
205EXPORT_SYMBOL_GPL(klist_iter_init_node);
206
207
208
209
210
211
212
213
214
215
216void klist_iter_init(struct klist * k, struct klist_iter * i)
217{
218 klist_iter_init_node(k, i, NULL);
219}
220
221EXPORT_SYMBOL_GPL(klist_iter_init);
222
223
224
225
226
227
228
229
230
231
232
233void klist_iter_exit(struct klist_iter * i)
234{
235 if (i->i_cur) {
236 klist_del(i->i_cur);
237 i->i_cur = NULL;
238 }
239}
240
241EXPORT_SYMBOL_GPL(klist_iter_exit);
242
243
244static struct klist_node * to_klist_node(struct list_head * n)
245{
246 return container_of(n, struct klist_node, n_node);
247}
248
249
250
251
252
253
254
255
256
257
258
259struct klist_node * klist_next(struct klist_iter * i)
260{
261 struct list_head * next;
262 struct klist_node * lnode = i->i_cur;
263 struct klist_node * knode = NULL;
264 void (*put)(struct klist_node *) = i->i_klist->put;
265
266 spin_lock(&i->i_klist->k_lock);
267 if (lnode) {
268 next = lnode->n_node.next;
269 if (!klist_dec_and_del(lnode))
270 put = NULL;
271 } else
272 next = i->i_head->next;
273
274 if (next != i->i_head) {
275 knode = to_klist_node(next);
276 kref_get(&knode->n_ref);
277 }
278 i->i_cur = knode;
279 spin_unlock(&i->i_klist->k_lock);
280 if (put && lnode)
281 put(lnode);
282 return knode;
283}
284
285EXPORT_SYMBOL_GPL(klist_next);
286
287
288