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#define DEBUG_SUBSYSTEM S_LNET
37
38#include <linux/libcfs/libcfs.h>
39
40#define CBH_ALLOC(ptr, h) \
41do { \
42 if ((h)->cbh_flags & CBH_FLAG_ATOMIC_GROW) \
43 LIBCFS_CPT_ALLOC_GFP((ptr), h->cbh_cptab, h->cbh_cptid, \
44 CBH_NOB, GFP_ATOMIC); \
45 else \
46 LIBCFS_CPT_ALLOC((ptr), h->cbh_cptab, h->cbh_cptid, \
47 CBH_NOB); \
48} while (0)
49
50#define CBH_FREE(ptr) LIBCFS_FREE(ptr, CBH_NOB)
51
52
53
54
55
56
57
58
59
60
61static int
62cfs_binheap_grow(cfs_binheap_t *h)
63{
64 cfs_binheap_node_t ***frag1 = NULL;
65 cfs_binheap_node_t **frag2;
66 int hwm = h->cbh_hwm;
67
68
69 LASSERT((h->cbh_hwm & CBH_MASK) == 0);
70
71 if (hwm == 0) {
72
73 CBH_ALLOC(h->cbh_elements1, h);
74 if (h->cbh_elements1 == NULL)
75 return -ENOMEM;
76
77 goto out;
78 }
79
80 hwm -= CBH_SIZE;
81 if (hwm < CBH_SIZE * CBH_SIZE) {
82
83 CBH_ALLOC(frag2, h);
84 if (frag2 == NULL)
85 return -ENOMEM;
86
87 if (hwm == 0) {
88
89 CBH_ALLOC(h->cbh_elements2, h);
90 if (h->cbh_elements2 == NULL) {
91 CBH_FREE(frag2);
92 return -ENOMEM;
93 }
94 }
95
96 h->cbh_elements2[hwm >> CBH_SHIFT] = frag2;
97 goto out;
98 }
99
100 hwm -= CBH_SIZE * CBH_SIZE;
101#if (CBH_SHIFT * 3 < 32)
102 if (hwm >= CBH_SIZE * CBH_SIZE * CBH_SIZE) {
103
104 return -ENOMEM;
105 }
106#endif
107 CBH_ALLOC(frag2, h);
108 if (frag2 == NULL)
109 return -ENOMEM;
110
111 if (((hwm >> CBH_SHIFT) & CBH_MASK) == 0) {
112
113 CBH_ALLOC(frag1, h);
114 if (frag1 == NULL) {
115 CBH_FREE(frag2);
116 return -ENOMEM;
117 }
118 }
119
120 if (hwm == 0) {
121
122 CBH_ALLOC(h->cbh_elements3, h);
123 if (h->cbh_elements3 == NULL) {
124 CBH_FREE(frag2);
125 CBH_FREE(frag1);
126 return -ENOMEM;
127 }
128 }
129
130 if (frag1 != NULL) {
131 LASSERT(h->cbh_elements3[hwm >> (2 * CBH_SHIFT)] == NULL);
132 h->cbh_elements3[hwm >> (2 * CBH_SHIFT)] = frag1;
133 } else {
134 frag1 = h->cbh_elements3[hwm >> (2 * CBH_SHIFT)];
135 LASSERT(frag1 != NULL);
136 }
137
138 frag1[(hwm >> CBH_SHIFT) & CBH_MASK] = frag2;
139
140 out:
141 h->cbh_hwm += CBH_SIZE;
142 return 0;
143}
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158cfs_binheap_t *
159cfs_binheap_create(cfs_binheap_ops_t *ops, unsigned int flags,
160 unsigned count, void *arg, struct cfs_cpt_table *cptab,
161 int cptid)
162{
163 cfs_binheap_t *h;
164
165 LASSERT(ops != NULL);
166 LASSERT(ops->hop_compare != NULL);
167 LASSERT(cptab != NULL);
168 LASSERT(cptid == CFS_CPT_ANY ||
169 (cptid >= 0 && cptid < cptab->ctb_nparts));
170
171 LIBCFS_CPT_ALLOC(h, cptab, cptid, sizeof(*h));
172 if (h == NULL)
173 return NULL;
174
175 h->cbh_ops = ops;
176 h->cbh_nelements = 0;
177 h->cbh_hwm = 0;
178 h->cbh_private = arg;
179 h->cbh_flags = flags & (~CBH_FLAG_ATOMIC_GROW);
180 h->cbh_cptab = cptab;
181 h->cbh_cptid = cptid;
182
183 while (h->cbh_hwm < count) {
184 if (cfs_binheap_grow(h) != 0) {
185 cfs_binheap_destroy(h);
186 return NULL;
187 }
188 }
189
190 h->cbh_flags |= flags & CBH_FLAG_ATOMIC_GROW;
191
192 return h;
193}
194EXPORT_SYMBOL(cfs_binheap_create);
195
196
197
198
199
200
201
202
203
204void
205cfs_binheap_destroy(cfs_binheap_t *h)
206{
207 int idx0;
208 int idx1;
209 int n;
210
211 LASSERT(h != NULL);
212
213 n = h->cbh_hwm;
214
215 if (n > 0) {
216 CBH_FREE(h->cbh_elements1);
217 n -= CBH_SIZE;
218 }
219
220 if (n > 0) {
221 for (idx0 = 0; idx0 < CBH_SIZE && n > 0; idx0++) {
222 CBH_FREE(h->cbh_elements2[idx0]);
223 n -= CBH_SIZE;
224 }
225
226 CBH_FREE(h->cbh_elements2);
227 }
228
229 if (n > 0) {
230 for (idx0 = 0; idx0 < CBH_SIZE && n > 0; idx0++) {
231
232 for (idx1 = 0; idx1 < CBH_SIZE && n > 0; idx1++) {
233 CBH_FREE(h->cbh_elements3[idx0][idx1]);
234 n -= CBH_SIZE;
235 }
236
237 CBH_FREE(h->cbh_elements3[idx0]);
238 }
239
240 CBH_FREE(h->cbh_elements3);
241 }
242
243 LIBCFS_FREE(h, sizeof(*h));
244}
245EXPORT_SYMBOL(cfs_binheap_destroy);
246
247
248
249
250
251
252
253
254
255
256static cfs_binheap_node_t **
257cfs_binheap_pointer(cfs_binheap_t *h, unsigned int idx)
258{
259 if (idx < CBH_SIZE)
260 return &(h->cbh_elements1[idx]);
261
262 idx -= CBH_SIZE;
263 if (idx < CBH_SIZE * CBH_SIZE)
264 return &(h->cbh_elements2[idx >> CBH_SHIFT][idx & CBH_MASK]);
265
266 idx -= CBH_SIZE * CBH_SIZE;
267 return &(h->cbh_elements3[idx >> (2 * CBH_SHIFT)]\
268 [(idx >> CBH_SHIFT) & CBH_MASK]\
269 [idx & CBH_MASK]);
270}
271
272
273
274
275
276
277
278
279
280
281cfs_binheap_node_t *
282cfs_binheap_find(cfs_binheap_t *h, unsigned int idx)
283{
284 if (idx >= h->cbh_nelements)
285 return NULL;
286
287 return *cfs_binheap_pointer(h, idx);
288}
289EXPORT_SYMBOL(cfs_binheap_find);
290
291
292
293
294
295
296
297
298
299
300static int
301cfs_binheap_bubble(cfs_binheap_t *h, cfs_binheap_node_t *e)
302{
303 unsigned int cur_idx = e->chn_index;
304 cfs_binheap_node_t **cur_ptr;
305 unsigned int parent_idx;
306 cfs_binheap_node_t **parent_ptr;
307 int did_sth = 0;
308
309 cur_ptr = cfs_binheap_pointer(h, cur_idx);
310 LASSERT(*cur_ptr == e);
311
312 while (cur_idx > 0) {
313 parent_idx = (cur_idx - 1) >> 1;
314
315 parent_ptr = cfs_binheap_pointer(h, parent_idx);
316 LASSERT((*parent_ptr)->chn_index == parent_idx);
317
318 if (h->cbh_ops->hop_compare(*parent_ptr, e))
319 break;
320
321 (*parent_ptr)->chn_index = cur_idx;
322 *cur_ptr = *parent_ptr;
323 cur_ptr = parent_ptr;
324 cur_idx = parent_idx;
325 did_sth = 1;
326 }
327
328 e->chn_index = cur_idx;
329 *cur_ptr = e;
330
331 return did_sth;
332}
333
334
335
336
337
338
339
340
341
342
343static int
344cfs_binheap_sink(cfs_binheap_t *h, cfs_binheap_node_t *e)
345{
346 unsigned int n = h->cbh_nelements;
347 unsigned int child_idx;
348 cfs_binheap_node_t **child_ptr;
349 cfs_binheap_node_t *child;
350 unsigned int child2_idx;
351 cfs_binheap_node_t **child2_ptr;
352 cfs_binheap_node_t *child2;
353 unsigned int cur_idx;
354 cfs_binheap_node_t **cur_ptr;
355 int did_sth = 0;
356
357 cur_idx = e->chn_index;
358 cur_ptr = cfs_binheap_pointer(h, cur_idx);
359 LASSERT(*cur_ptr == e);
360
361 while (cur_idx < n) {
362 child_idx = (cur_idx << 1) + 1;
363 if (child_idx >= n)
364 break;
365
366 child_ptr = cfs_binheap_pointer(h, child_idx);
367 child = *child_ptr;
368
369 child2_idx = child_idx + 1;
370 if (child2_idx < n) {
371 child2_ptr = cfs_binheap_pointer(h, child2_idx);
372 child2 = *child2_ptr;
373
374 if (h->cbh_ops->hop_compare(child2, child)) {
375 child_idx = child2_idx;
376 child_ptr = child2_ptr;
377 child = child2;
378 }
379 }
380
381 LASSERT(child->chn_index == child_idx);
382
383 if (h->cbh_ops->hop_compare(e, child))
384 break;
385
386 child->chn_index = cur_idx;
387 *cur_ptr = child;
388 cur_ptr = child_ptr;
389 cur_idx = child_idx;
390 did_sth = 1;
391 }
392
393 e->chn_index = cur_idx;
394 *cur_ptr = e;
395
396 return did_sth;
397}
398
399
400
401
402
403
404
405
406
407
408int
409cfs_binheap_insert(cfs_binheap_t *h, cfs_binheap_node_t *e)
410{
411 cfs_binheap_node_t **new_ptr;
412 unsigned int new_idx = h->cbh_nelements;
413 int rc;
414
415 if (new_idx == h->cbh_hwm) {
416 rc = cfs_binheap_grow(h);
417 if (rc != 0)
418 return rc;
419 }
420
421 if (h->cbh_ops->hop_enter) {
422 rc = h->cbh_ops->hop_enter(h, e);
423 if (rc != 0)
424 return rc;
425 }
426
427 e->chn_index = new_idx;
428 new_ptr = cfs_binheap_pointer(h, new_idx);
429 h->cbh_nelements++;
430 *new_ptr = e;
431
432 cfs_binheap_bubble(h, e);
433
434 return 0;
435}
436EXPORT_SYMBOL(cfs_binheap_insert);
437
438
439
440
441
442
443
444void
445cfs_binheap_remove(cfs_binheap_t *h, cfs_binheap_node_t *e)
446{
447 unsigned int n = h->cbh_nelements;
448 unsigned int cur_idx = e->chn_index;
449 cfs_binheap_node_t **cur_ptr;
450 cfs_binheap_node_t *last;
451
452 LASSERT(cur_idx != CBH_POISON);
453 LASSERT(cur_idx < n);
454
455 cur_ptr = cfs_binheap_pointer(h, cur_idx);
456 LASSERT(*cur_ptr == e);
457
458 n--;
459 last = *cfs_binheap_pointer(h, n);
460 h->cbh_nelements = n;
461 if (last == e)
462 return;
463
464 last->chn_index = cur_idx;
465 *cur_ptr = last;
466 if (!cfs_binheap_bubble(h, *cur_ptr))
467 cfs_binheap_sink(h, *cur_ptr);
468
469 e->chn_index = CBH_POISON;
470 if (h->cbh_ops->hop_exit)
471 h->cbh_ops->hop_exit(h, e);
472}
473EXPORT_SYMBOL(cfs_binheap_remove);
474
475
476