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#include <linux/kernel.h>
36#include <linux/module.h>
37#include <linux/slab.h>
38#include <linux/export.h>
39#include <linux/list.h>
40#include <linux/err.h>
41#include <linux/parman.h>
42
43struct parman_algo {
44 int (*item_add)(struct parman *parman, struct parman_prio *prio,
45 struct parman_item *item);
46 void (*item_remove)(struct parman *parman, struct parman_prio *prio,
47 struct parman_item *item);
48};
49
50struct parman {
51 const struct parman_ops *ops;
52 void *priv;
53 const struct parman_algo *algo;
54 unsigned long count;
55 unsigned long limit_count;
56 struct list_head prio_list;
57};
58
59static int parman_enlarge(struct parman *parman)
60{
61 unsigned long new_count = parman->limit_count +
62 parman->ops->resize_step;
63 int err;
64
65 err = parman->ops->resize(parman->priv, new_count);
66 if (err)
67 return err;
68 parman->limit_count = new_count;
69 return 0;
70}
71
72static int parman_shrink(struct parman *parman)
73{
74 unsigned long new_count = parman->limit_count -
75 parman->ops->resize_step;
76 int err;
77
78 if (new_count < parman->ops->base_count)
79 return 0;
80 err = parman->ops->resize(parman->priv, new_count);
81 if (err)
82 return err;
83 parman->limit_count = new_count;
84 return 0;
85}
86
87static bool parman_prio_used(struct parman_prio *prio)
88{
89 return !list_empty(&prio->item_list);
90}
91
92static struct parman_item *parman_prio_first_item(struct parman_prio *prio)
93{
94 return list_first_entry(&prio->item_list,
95 typeof(struct parman_item), list);
96}
97
98static unsigned long parman_prio_first_index(struct parman_prio *prio)
99{
100 return parman_prio_first_item(prio)->index;
101}
102
103static struct parman_item *parman_prio_last_item(struct parman_prio *prio)
104{
105 return list_last_entry(&prio->item_list,
106 typeof(struct parman_item), list);
107}
108
109static unsigned long parman_prio_last_index(struct parman_prio *prio)
110{
111 return parman_prio_last_item(prio)->index;
112}
113
114static unsigned long parman_lsort_new_index_find(struct parman *parman,
115 struct parman_prio *prio)
116{
117 list_for_each_entry_from_reverse(prio, &parman->prio_list, list) {
118 if (!parman_prio_used(prio))
119 continue;
120 return parman_prio_last_index(prio) + 1;
121 }
122 return 0;
123}
124
125static void __parman_prio_move(struct parman *parman, struct parman_prio *prio,
126 struct parman_item *item, unsigned long to_index,
127 unsigned long count)
128{
129 parman->ops->move(parman->priv, item->index, to_index, count);
130}
131
132static void parman_prio_shift_down(struct parman *parman,
133 struct parman_prio *prio)
134{
135 struct parman_item *item;
136 unsigned long to_index;
137
138 if (!parman_prio_used(prio))
139 return;
140 item = parman_prio_first_item(prio);
141 to_index = parman_prio_last_index(prio) + 1;
142 __parman_prio_move(parman, prio, item, to_index, 1);
143 list_move_tail(&item->list, &prio->item_list);
144 item->index = to_index;
145}
146
147static void parman_prio_shift_up(struct parman *parman,
148 struct parman_prio *prio)
149{
150 struct parman_item *item;
151 unsigned long to_index;
152
153 if (!parman_prio_used(prio))
154 return;
155 item = parman_prio_last_item(prio);
156 to_index = parman_prio_first_index(prio) - 1;
157 __parman_prio_move(parman, prio, item, to_index, 1);
158 list_move(&item->list, &prio->item_list);
159 item->index = to_index;
160}
161
162static void parman_prio_item_remove(struct parman *parman,
163 struct parman_prio *prio,
164 struct parman_item *item)
165{
166 struct parman_item *last_item;
167 unsigned long to_index;
168
169 last_item = parman_prio_last_item(prio);
170 if (last_item == item) {
171 list_del(&item->list);
172 return;
173 }
174 to_index = item->index;
175 __parman_prio_move(parman, prio, last_item, to_index, 1);
176 list_del(&last_item->list);
177 list_replace(&item->list, &last_item->list);
178 last_item->index = to_index;
179}
180
181static int parman_lsort_item_add(struct parman *parman,
182 struct parman_prio *prio,
183 struct parman_item *item)
184{
185 struct parman_prio *prio2;
186 unsigned long new_index;
187 int err;
188
189 if (parman->count + 1 > parman->limit_count) {
190 err = parman_enlarge(parman);
191 if (err)
192 return err;
193 }
194
195 new_index = parman_lsort_new_index_find(parman, prio);
196 list_for_each_entry_reverse(prio2, &parman->prio_list, list) {
197 if (prio2 == prio)
198 break;
199 parman_prio_shift_down(parman, prio2);
200 }
201 item->index = new_index;
202 list_add_tail(&item->list, &prio->item_list);
203 parman->count++;
204 return 0;
205}
206
207static void parman_lsort_item_remove(struct parman *parman,
208 struct parman_prio *prio,
209 struct parman_item *item)
210{
211 parman_prio_item_remove(parman, prio, item);
212 list_for_each_entry_continue(prio, &parman->prio_list, list)
213 parman_prio_shift_up(parman, prio);
214 parman->count--;
215 if (parman->limit_count - parman->count >= parman->ops->resize_step)
216 parman_shrink(parman);
217}
218
219static const struct parman_algo parman_lsort = {
220 .item_add = parman_lsort_item_add,
221 .item_remove = parman_lsort_item_remove,
222};
223
224static const struct parman_algo *parman_algos[] = {
225 &parman_lsort,
226};
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267struct parman *parman_create(const struct parman_ops *ops, void *priv)
268{
269 struct parman *parman;
270
271 parman = kzalloc(sizeof(*parman), GFP_KERNEL);
272 if (!parman)
273 return NULL;
274 INIT_LIST_HEAD(&parman->prio_list);
275 parman->ops = ops;
276 parman->priv = priv;
277 parman->limit_count = ops->base_count;
278 parman->algo = parman_algos[ops->algo];
279 return parman;
280}
281EXPORT_SYMBOL(parman_create);
282
283
284
285
286
287
288
289void parman_destroy(struct parman *parman)
290{
291 WARN_ON(!list_empty(&parman->prio_list));
292 kfree(parman);
293}
294EXPORT_SYMBOL(parman_destroy);
295
296
297
298
299
300
301
302
303
304
305
306
307void parman_prio_init(struct parman *parman, struct parman_prio *prio,
308 unsigned long priority)
309{
310 struct parman_prio *prio2;
311 struct list_head *pos;
312
313 INIT_LIST_HEAD(&prio->item_list);
314 prio->priority = priority;
315
316
317 list_for_each(pos, &parman->prio_list) {
318 prio2 = list_entry(pos, typeof(*prio2), list);
319 if (prio2->priority > prio->priority)
320 break;
321 }
322 list_add_tail(&prio->list, pos);
323}
324EXPORT_SYMBOL(parman_prio_init);
325
326
327
328
329
330
331
332void parman_prio_fini(struct parman_prio *prio)
333{
334 WARN_ON(parman_prio_used(prio));
335 list_del(&prio->list);
336}
337EXPORT_SYMBOL(parman_prio_fini);
338
339
340
341
342
343
344
345
346
347
348
349
350
351int parman_item_add(struct parman *parman, struct parman_prio *prio,
352 struct parman_item *item)
353{
354 return parman->algo->item_add(parman, prio, item);
355}
356EXPORT_SYMBOL(parman_item_add);
357
358
359
360
361
362
363
364
365
366void parman_item_remove(struct parman *parman, struct parman_prio *prio,
367 struct parman_item *item)
368{
369 parman->algo->item_remove(parman, prio, item);
370}
371EXPORT_SYMBOL(parman_item_remove);
372
373MODULE_LICENSE("Dual BSD/GPL");
374MODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>");
375MODULE_DESCRIPTION("Priority-based array manager");
376