Line data Source code
1 : /* Generic associative array implementation.
2 : *
3 : * See Documentation/assoc_array.txt for information.
4 : *
5 : * Copyright (C) 2013 Red Hat, Inc. All Rights Reserved.
6 : * Written by David Howells (dhowells@redhat.com)
7 : *
8 : * This program is free software; you can redistribute it and/or
9 : * modify it under the terms of the GNU General Public Licence
10 : * as published by the Free Software Foundation; either version
11 : * 2 of the Licence, or (at your option) any later version.
12 : */
13 : //#define DEBUG
14 : #include <linux/rcupdate.h>
15 : #include <linux/slab.h>
16 : #include <linux/err.h>
17 : #include <linux/assoc_array_priv.h>
18 :
19 : /*
20 : * Iterate over an associative array. The caller must hold the RCU read lock
21 : * or better.
22 : */
23 0 : static int assoc_array_subtree_iterate(const struct assoc_array_ptr *root,
24 : const struct assoc_array_ptr *stop,
25 : int (*iterator)(const void *leaf,
26 : void *iterator_data),
27 : void *iterator_data)
28 : {
29 : const struct assoc_array_shortcut *shortcut;
30 : const struct assoc_array_node *node;
31 : const struct assoc_array_ptr *cursor, *ptr, *parent;
32 : unsigned long has_meta;
33 : int slot, ret;
34 :
35 : cursor = root;
36 :
37 : begin_node:
38 0 : if (assoc_array_ptr_is_shortcut(cursor)) {
39 : /* Descend through a shortcut */
40 : shortcut = assoc_array_ptr_to_shortcut(cursor);
41 : smp_read_barrier_depends();
42 0 : cursor = ACCESS_ONCE(shortcut->next_node);
43 : }
44 :
45 : node = assoc_array_ptr_to_node(cursor);
46 : smp_read_barrier_depends();
47 : slot = 0;
48 :
49 : /* We perform two passes of each node.
50 : *
51 : * The first pass does all the leaves in this node. This means we
52 : * don't miss any leaves if the node is split up by insertion whilst
53 : * we're iterating over the branches rooted here (we may, however, see
54 : * some leaves twice).
55 : */
56 : has_meta = 0;
57 0 : for (; slot < ASSOC_ARRAY_FAN_OUT; slot++) {
58 0 : ptr = ACCESS_ONCE(node->slots[slot]);
59 0 : has_meta |= (unsigned long)ptr;
60 0 : if (ptr && assoc_array_ptr_is_leaf(ptr)) {
61 : /* We need a barrier between the read of the pointer
62 : * and dereferencing the pointer - but only if we are
63 : * actually going to dereference it.
64 : */
65 : smp_read_barrier_depends();
66 :
67 : /* Invoke the callback */
68 0 : ret = iterator(assoc_array_ptr_to_leaf(ptr),
69 : iterator_data);
70 0 : if (ret)
71 : return ret;
72 : }
73 : }
74 :
75 : /* The second pass attends to all the metadata pointers. If we follow
76 : * one of these we may find that we don't come back here, but rather go
77 : * back to a replacement node with the leaves in a different layout.
78 : *
79 : * We are guaranteed to make progress, however, as the slot number for
80 : * a particular portion of the key space cannot change - and we
81 : * continue at the back pointer + 1.
82 : */
83 0 : if (!(has_meta & ASSOC_ARRAY_PTR_META_TYPE))
84 : goto finished_node;
85 : slot = 0;
86 :
87 : continue_node:
88 : node = assoc_array_ptr_to_node(cursor);
89 : smp_read_barrier_depends();
90 :
91 0 : for (; slot < ASSOC_ARRAY_FAN_OUT; slot++) {
92 0 : ptr = ACCESS_ONCE(node->slots[slot]);
93 0 : if (assoc_array_ptr_is_meta(ptr)) {
94 : cursor = ptr;
95 : goto begin_node;
96 : }
97 : }
98 :
99 : finished_node:
100 : /* Move up to the parent (may need to skip back over a shortcut) */
101 0 : parent = ACCESS_ONCE(node->back_pointer);
102 0 : slot = node->parent_slot;
103 0 : if (parent == stop)
104 : return 0;
105 :
106 0 : if (assoc_array_ptr_is_shortcut(parent)) {
107 : shortcut = assoc_array_ptr_to_shortcut(parent);
108 : smp_read_barrier_depends();
109 : cursor = parent;
110 0 : parent = ACCESS_ONCE(shortcut->back_pointer);
111 0 : slot = shortcut->parent_slot;
112 0 : if (parent == stop)
113 : return 0;
114 : }
115 :
116 : /* Ascend to next slot in parent node */
117 : cursor = parent;
118 0 : slot++;
119 0 : goto continue_node;
120 : }
121 :
122 : /**
123 : * assoc_array_iterate - Pass all objects in the array to a callback
124 : * @array: The array to iterate over.
125 : * @iterator: The callback function.
126 : * @iterator_data: Private data for the callback function.
127 : *
128 : * Iterate over all the objects in an associative array. Each one will be
129 : * presented to the iterator function.
130 : *
131 : * If the array is being modified concurrently with the iteration then it is
132 : * possible that some objects in the array will be passed to the iterator
133 : * callback more than once - though every object should be passed at least
134 : * once. If this is undesirable then the caller must lock against modification
135 : * for the duration of this function.
136 : *
137 : * The function will return 0 if no objects were in the array or else it will
138 : * return the result of the last iterator function called. Iteration stops
139 : * immediately if any call to the iteration function results in a non-zero
140 : * return.
141 : *
142 : * The caller should hold the RCU read lock or better if concurrent
143 : * modification is possible.
144 : */
145 0 : int assoc_array_iterate(const struct assoc_array *array,
146 : int (*iterator)(const void *object,
147 : void *iterator_data),
148 : void *iterator_data)
149 : {
150 0 : struct assoc_array_ptr *root = ACCESS_ONCE(array->root);
151 :
152 0 : if (!root)
153 : return 0;
154 0 : return assoc_array_subtree_iterate(root, NULL, iterator, iterator_data);
155 : }
156 :
157 : enum assoc_array_walk_status {
158 : assoc_array_walk_tree_empty,
159 : assoc_array_walk_found_terminal_node,
160 : assoc_array_walk_found_wrong_shortcut,
161 : };
162 :
163 : struct assoc_array_walk_result {
164 : struct {
165 : struct assoc_array_node *node; /* Node in which leaf might be found */
166 : int level;
167 : int slot;
168 : } terminal_node;
169 : struct {
170 : struct assoc_array_shortcut *shortcut;
171 : int level;
172 : int sc_level;
173 : unsigned long sc_segments;
174 : unsigned long dissimilarity;
175 : } wrong_shortcut;
176 : };
177 :
178 : /*
179 : * Navigate through the internal tree looking for the closest node to the key.
180 : */
181 : static enum assoc_array_walk_status
182 2 : assoc_array_walk(const struct assoc_array *array,
183 : const struct assoc_array_ops *ops,
184 : const void *index_key,
185 : struct assoc_array_walk_result *result)
186 : {
187 : struct assoc_array_shortcut *shortcut;
188 : struct assoc_array_node *node;
189 : struct assoc_array_ptr *cursor, *ptr;
190 : unsigned long sc_segments, dissimilarity;
191 : unsigned long segments;
192 : int level, sc_level, next_sc_level;
193 : int slot;
194 :
195 : pr_devel("-->%s()\n", __func__);
196 :
197 2 : cursor = ACCESS_ONCE(array->root);
198 2 : if (!cursor)
199 : return assoc_array_walk_tree_empty;
200 :
201 : level = 0;
202 :
203 : /* Use segments from the key for the new leaf to navigate through the
204 : * internal tree, skipping through nodes and shortcuts that are on
205 : * route to the destination. Eventually we'll come to a slot that is
206 : * either empty or contains a leaf at which point we've found a node in
207 : * which the leaf we're looking for might be found or into which it
208 : * should be inserted.
209 : */
210 : jumped:
211 0 : segments = ops->get_key_chunk(index_key, level);
212 : pr_devel("segments[%d]: %lx\n", level, segments);
213 :
214 0 : if (assoc_array_ptr_is_shortcut(cursor))
215 : goto follow_shortcut;
216 :
217 : consider_node:
218 : node = assoc_array_ptr_to_node(cursor);
219 : smp_read_barrier_depends();
220 :
221 0 : slot = segments >> (level & ASSOC_ARRAY_KEY_CHUNK_MASK);
222 0 : slot &= ASSOC_ARRAY_FAN_MASK;
223 0 : ptr = ACCESS_ONCE(node->slots[slot]);
224 :
225 : pr_devel("consider slot %x [ix=%d type=%lu]\n",
226 : slot, level, (unsigned long)ptr & 3);
227 :
228 0 : if (!assoc_array_ptr_is_meta(ptr)) {
229 : /* The node doesn't have a node/shortcut pointer in the slot
230 : * corresponding to the index key that we have to follow.
231 : */
232 0 : result->terminal_node.node = node;
233 0 : result->terminal_node.level = level;
234 0 : result->terminal_node.slot = slot;
235 : pr_devel("<--%s() = terminal_node\n", __func__);
236 : return assoc_array_walk_found_terminal_node;
237 : }
238 :
239 0 : if (assoc_array_ptr_is_node(ptr)) {
240 : /* There is a pointer to a node in the slot corresponding to
241 : * this index key segment, so we need to follow it.
242 : */
243 : cursor = ptr;
244 0 : level += ASSOC_ARRAY_LEVEL_STEP;
245 0 : if ((level & ASSOC_ARRAY_KEY_CHUNK_MASK) != 0)
246 : goto consider_node;
247 : goto jumped;
248 : }
249 :
250 : /* There is a shortcut in the slot corresponding to the index key
251 : * segment. We follow the shortcut if its partial index key matches
252 : * this leaf's. Otherwise we need to split the shortcut.
253 : */
254 : cursor = ptr;
255 : follow_shortcut:
256 : shortcut = assoc_array_ptr_to_shortcut(cursor);
257 : smp_read_barrier_depends();
258 : pr_devel("shortcut to %d\n", shortcut->skip_to_level);
259 0 : sc_level = level + ASSOC_ARRAY_LEVEL_STEP;
260 : BUG_ON(sc_level > shortcut->skip_to_level);
261 :
262 : do {
263 : /* Check the leaf against the shortcut's index key a word at a
264 : * time, trimming the final word (the shortcut stores the index
265 : * key completely from the root to the shortcut's target).
266 : */
267 0 : if ((sc_level & ASSOC_ARRAY_KEY_CHUNK_MASK) == 0)
268 0 : segments = ops->get_key_chunk(index_key, sc_level);
269 :
270 0 : sc_segments = shortcut->index_key[sc_level >> ASSOC_ARRAY_KEY_CHUNK_SHIFT];
271 0 : dissimilarity = segments ^ sc_segments;
272 :
273 0 : if (round_up(sc_level, ASSOC_ARRAY_KEY_CHUNK_SIZE) > shortcut->skip_to_level) {
274 : /* Trim segments that are beyond the shortcut */
275 0 : int shift = shortcut->skip_to_level & ASSOC_ARRAY_KEY_CHUNK_MASK;
276 0 : dissimilarity &= ~(ULONG_MAX << shift);
277 : next_sc_level = shortcut->skip_to_level;
278 : } else {
279 0 : next_sc_level = sc_level + ASSOC_ARRAY_KEY_CHUNK_SIZE;
280 0 : next_sc_level = round_down(next_sc_level, ASSOC_ARRAY_KEY_CHUNK_SIZE);
281 : }
282 :
283 0 : if (dissimilarity != 0) {
284 : /* This shortcut points elsewhere */
285 0 : result->wrong_shortcut.shortcut = shortcut;
286 0 : result->wrong_shortcut.level = level;
287 0 : result->wrong_shortcut.sc_level = sc_level;
288 0 : result->wrong_shortcut.sc_segments = sc_segments;
289 0 : result->wrong_shortcut.dissimilarity = dissimilarity;
290 : return assoc_array_walk_found_wrong_shortcut;
291 : }
292 :
293 : sc_level = next_sc_level;
294 0 : } while (sc_level < shortcut->skip_to_level);
295 :
296 : /* The shortcut matches the leaf's index to this point. */
297 0 : cursor = ACCESS_ONCE(shortcut->next_node);
298 0 : if (((level ^ sc_level) & ~ASSOC_ARRAY_KEY_CHUNK_MASK) != 0) {
299 : level = sc_level;
300 : goto jumped;
301 : } else {
302 : level = sc_level;
303 : goto consider_node;
304 : }
305 : }
306 :
307 : /**
308 : * assoc_array_find - Find an object by index key
309 : * @array: The associative array to search.
310 : * @ops: The operations to use.
311 : * @index_key: The key to the object.
312 : *
313 : * Find an object in an associative array by walking through the internal tree
314 : * to the node that should contain the object and then searching the leaves
315 : * there. NULL is returned if the requested object was not found in the array.
316 : *
317 : * The caller must hold the RCU read lock or better.
318 : */
319 1 : void *assoc_array_find(const struct assoc_array *array,
320 : const struct assoc_array_ops *ops,
321 : const void *index_key)
322 : {
323 : struct assoc_array_walk_result result;
324 : const struct assoc_array_node *node;
325 : const struct assoc_array_ptr *ptr;
326 : const void *leaf;
327 : int slot;
328 :
329 1 : if (assoc_array_walk(array, ops, index_key, &result) !=
330 : assoc_array_walk_found_terminal_node)
331 : return NULL;
332 :
333 0 : node = result.terminal_node.node;
334 : smp_read_barrier_depends();
335 :
336 : /* If the target key is available to us, it's has to be pointed to by
337 : * the terminal node.
338 : */
339 0 : for (slot = 0; slot < ASSOC_ARRAY_FAN_OUT; slot++) {
340 0 : ptr = ACCESS_ONCE(node->slots[slot]);
341 0 : if (ptr && assoc_array_ptr_is_leaf(ptr)) {
342 : /* We need a barrier between the read of the pointer
343 : * and dereferencing the pointer - but only if we are
344 : * actually going to dereference it.
345 : */
346 : leaf = assoc_array_ptr_to_leaf(ptr);
347 : smp_read_barrier_depends();
348 0 : if (ops->compare_object(leaf, index_key))
349 : return (void *)leaf;
350 : }
351 : }
352 :
353 : return NULL;
354 : }
355 :
356 : /*
357 : * Destructively iterate over an associative array. The caller must prevent
358 : * other simultaneous accesses.
359 : */
360 0 : static void assoc_array_destroy_subtree(struct assoc_array_ptr *root,
361 : const struct assoc_array_ops *ops)
362 : {
363 : struct assoc_array_shortcut *shortcut;
364 : struct assoc_array_node *node;
365 : struct assoc_array_ptr *cursor, *parent = NULL;
366 : int slot = -1;
367 :
368 : pr_devel("-->%s()\n", __func__);
369 :
370 : cursor = root;
371 0 : if (!cursor) {
372 : pr_devel("empty\n");
373 : return;
374 : }
375 :
376 : move_to_meta:
377 0 : if (assoc_array_ptr_is_shortcut(cursor)) {
378 : /* Descend through a shortcut */
379 : pr_devel("[%d] shortcut\n", slot);
380 : BUG_ON(!assoc_array_ptr_is_shortcut(cursor));
381 : shortcut = assoc_array_ptr_to_shortcut(cursor);
382 : BUG_ON(shortcut->back_pointer != parent);
383 : BUG_ON(slot != -1 && shortcut->parent_slot != slot);
384 : parent = cursor;
385 0 : cursor = shortcut->next_node;
386 : slot = -1;
387 : BUG_ON(!assoc_array_ptr_is_node(cursor));
388 : }
389 :
390 : pr_devel("[%d] node\n", slot);
391 : node = assoc_array_ptr_to_node(cursor);
392 : BUG_ON(node->back_pointer != parent);
393 : BUG_ON(slot != -1 && node->parent_slot != slot);
394 : slot = 0;
395 :
396 : continue_node:
397 : pr_devel("Node %p [back=%p]\n", node, node->back_pointer);
398 0 : for (; slot < ASSOC_ARRAY_FAN_OUT; slot++) {
399 0 : struct assoc_array_ptr *ptr = node->slots[slot];
400 0 : if (!ptr)
401 0 : continue;
402 0 : if (assoc_array_ptr_is_meta(ptr)) {
403 : parent = cursor;
404 : cursor = ptr;
405 : goto move_to_meta;
406 : }
407 :
408 0 : if (ops) {
409 : pr_devel("[%d] free leaf\n", slot);
410 0 : ops->free_object(assoc_array_ptr_to_leaf(ptr));
411 : }
412 : }
413 :
414 0 : parent = node->back_pointer;
415 0 : slot = node->parent_slot;
416 : pr_devel("free node\n");
417 0 : kfree(node);
418 0 : if (!parent)
419 : return; /* Done */
420 :
421 : /* Move back up to the parent (may need to free a shortcut on
422 : * the way up) */
423 0 : if (assoc_array_ptr_is_shortcut(parent)) {
424 : shortcut = assoc_array_ptr_to_shortcut(parent);
425 : BUG_ON(shortcut->next_node != cursor);
426 : cursor = parent;
427 0 : parent = shortcut->back_pointer;
428 0 : slot = shortcut->parent_slot;
429 : pr_devel("free shortcut\n");
430 0 : kfree(shortcut);
431 0 : if (!parent)
432 : return;
433 :
434 : BUG_ON(!assoc_array_ptr_is_node(parent));
435 : }
436 :
437 : /* Ascend to next slot in parent node */
438 : pr_devel("ascend to %p[%d]\n", parent, slot);
439 : cursor = parent;
440 : node = assoc_array_ptr_to_node(cursor);
441 0 : slot++;
442 0 : goto continue_node;
443 : }
444 :
445 : /**
446 : * assoc_array_destroy - Destroy an associative array
447 : * @array: The array to destroy.
448 : * @ops: The operations to use.
449 : *
450 : * Discard all metadata and free all objects in an associative array. The
451 : * array will be empty and ready to use again upon completion. This function
452 : * cannot fail.
453 : *
454 : * The caller must prevent all other accesses whilst this takes place as no
455 : * attempt is made to adjust pointers gracefully to permit RCU readlock-holding
456 : * accesses to continue. On the other hand, no memory allocation is required.
457 : */
458 0 : void assoc_array_destroy(struct assoc_array *array,
459 : const struct assoc_array_ops *ops)
460 : {
461 0 : assoc_array_destroy_subtree(array->root, ops);
462 0 : array->root = NULL;
463 0 : }
464 :
465 : /*
466 : * Handle insertion into an empty tree.
467 : */
468 1 : static bool assoc_array_insert_in_empty_tree(struct assoc_array_edit *edit)
469 : {
470 : struct assoc_array_node *new_n0;
471 :
472 : pr_devel("-->%s()\n", __func__);
473 :
474 : new_n0 = kzalloc(sizeof(struct assoc_array_node), GFP_KERNEL);
475 1 : if (!new_n0)
476 : return false;
477 :
478 1 : edit->new_meta[0] = assoc_array_node_to_ptr(new_n0);
479 1 : edit->leaf_p = &new_n0->slots[0];
480 1 : edit->adjust_count_on = new_n0;
481 1 : edit->set[0].ptr = &edit->array->root;
482 1 : edit->set[0].to = assoc_array_node_to_ptr(new_n0);
483 :
484 : pr_devel("<--%s() = ok [no root]\n", __func__);
485 1 : return true;
486 : }
487 :
488 : /*
489 : * Handle insertion into a terminal node.
490 : */
491 0 : static bool assoc_array_insert_into_terminal_node(struct assoc_array_edit *edit,
492 : const struct assoc_array_ops *ops,
493 : const void *index_key,
494 : struct assoc_array_walk_result *result)
495 : {
496 : struct assoc_array_shortcut *shortcut, *new_s0;
497 : struct assoc_array_node *node, *new_n0, *new_n1, *side;
498 : struct assoc_array_ptr *ptr;
499 : unsigned long dissimilarity, base_seg, blank;
500 : size_t keylen;
501 : bool have_meta;
502 : int level, diff;
503 : int slot, next_slot, free_slot, i, j;
504 :
505 0 : node = result->terminal_node.node;
506 0 : level = result->terminal_node.level;
507 0 : edit->segment_cache[ASSOC_ARRAY_FAN_OUT] = result->terminal_node.slot;
508 :
509 : pr_devel("-->%s()\n", __func__);
510 :
511 : /* We arrived at a node which doesn't have an onward node or shortcut
512 : * pointer that we have to follow. This means that (a) the leaf we
513 : * want must go here (either by insertion or replacement) or (b) we
514 : * need to split this node and insert in one of the fragments.
515 : */
516 : free_slot = -1;
517 :
518 : /* Firstly, we have to check the leaves in this node to see if there's
519 : * a matching one we should replace in place.
520 : */
521 0 : for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++) {
522 0 : ptr = node->slots[i];
523 0 : if (!ptr) {
524 : free_slot = i;
525 0 : continue;
526 : }
527 0 : if (ops->compare_object(assoc_array_ptr_to_leaf(ptr), index_key)) {
528 : pr_devel("replace in slot %d\n", i);
529 0 : edit->leaf_p = &node->slots[i];
530 0 : edit->dead_leaf = node->slots[i];
531 : pr_devel("<--%s() = ok [replace]\n", __func__);
532 0 : return true;
533 : }
534 : }
535 :
536 : /* If there is a free slot in this node then we can just insert the
537 : * leaf here.
538 : */
539 0 : if (free_slot >= 0) {
540 : pr_devel("insert in free slot %d\n", free_slot);
541 0 : edit->leaf_p = &node->slots[free_slot];
542 0 : edit->adjust_count_on = node;
543 : pr_devel("<--%s() = ok [insert]\n", __func__);
544 0 : return true;
545 : }
546 :
547 : /* The node has no spare slots - so we're either going to have to split
548 : * it or insert another node before it.
549 : *
550 : * Whatever, we're going to need at least two new nodes - so allocate
551 : * those now. We may also need a new shortcut, but we deal with that
552 : * when we need it.
553 : */
554 : new_n0 = kzalloc(sizeof(struct assoc_array_node), GFP_KERNEL);
555 0 : if (!new_n0)
556 : return false;
557 0 : edit->new_meta[0] = assoc_array_node_to_ptr(new_n0);
558 : new_n1 = kzalloc(sizeof(struct assoc_array_node), GFP_KERNEL);
559 0 : if (!new_n1)
560 : return false;
561 0 : edit->new_meta[1] = assoc_array_node_to_ptr(new_n1);
562 :
563 : /* We need to find out how similar the leaves are. */
564 : pr_devel("no spare slots\n");
565 : have_meta = false;
566 0 : for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++) {
567 0 : ptr = node->slots[i];
568 0 : if (assoc_array_ptr_is_meta(ptr)) {
569 0 : edit->segment_cache[i] = 0xff;
570 : have_meta = true;
571 0 : continue;
572 : }
573 0 : base_seg = ops->get_object_key_chunk(
574 : assoc_array_ptr_to_leaf(ptr), level);
575 0 : base_seg >>= level & ASSOC_ARRAY_KEY_CHUNK_MASK;
576 0 : edit->segment_cache[i] = base_seg & ASSOC_ARRAY_FAN_MASK;
577 : }
578 :
579 0 : if (have_meta) {
580 : pr_devel("have meta\n");
581 : goto split_node;
582 : }
583 :
584 : /* The node contains only leaves */
585 : dissimilarity = 0;
586 0 : base_seg = edit->segment_cache[0];
587 0 : for (i = 1; i < ASSOC_ARRAY_FAN_OUT; i++)
588 0 : dissimilarity |= edit->segment_cache[i] ^ base_seg;
589 :
590 : pr_devel("only leaves; dissimilarity=%lx\n", dissimilarity);
591 :
592 0 : if ((dissimilarity & ASSOC_ARRAY_FAN_MASK) == 0) {
593 : /* The old leaves all cluster in the same slot. We will need
594 : * to insert a shortcut if the new node wants to cluster with them.
595 : */
596 0 : if ((edit->segment_cache[ASSOC_ARRAY_FAN_OUT] ^ base_seg) == 0)
597 : goto all_leaves_cluster_together;
598 :
599 : /* Otherwise we can just insert a new node ahead of the old
600 : * one.
601 : */
602 : goto present_leaves_cluster_but_not_new_leaf;
603 : }
604 :
605 : split_node:
606 : pr_devel("split node\n");
607 :
608 : /* We need to split the current node; we know that the node doesn't
609 : * simply contain a full set of leaves that cluster together (it
610 : * contains meta pointers and/or non-clustering leaves).
611 : *
612 : * We need to expel at least two leaves out of a set consisting of the
613 : * leaves in the node and the new leaf.
614 : *
615 : * We need a new node (n0) to replace the current one and a new node to
616 : * take the expelled nodes (n1).
617 : */
618 0 : edit->set[0].to = assoc_array_node_to_ptr(new_n0);
619 0 : new_n0->back_pointer = node->back_pointer;
620 0 : new_n0->parent_slot = node->parent_slot;
621 0 : new_n1->back_pointer = assoc_array_node_to_ptr(new_n0);
622 0 : new_n1->parent_slot = -1; /* Need to calculate this */
623 :
624 : do_split_node:
625 : pr_devel("do_split_node\n");
626 :
627 0 : new_n0->nr_leaves_on_branch = node->nr_leaves_on_branch;
628 0 : new_n1->nr_leaves_on_branch = 0;
629 :
630 : /* Begin by finding two matching leaves. There have to be at least two
631 : * that match - even if there are meta pointers - because any leaf that
632 : * would match a slot with a meta pointer in it must be somewhere
633 : * behind that meta pointer and cannot be here. Further, given N
634 : * remaining leaf slots, we now have N+1 leaves to go in them.
635 : */
636 0 : for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++) {
637 0 : slot = edit->segment_cache[i];
638 0 : if (slot != 0xff)
639 0 : for (j = i + 1; j < ASSOC_ARRAY_FAN_OUT + 1; j++)
640 0 : if (edit->segment_cache[j] == slot)
641 : goto found_slot_for_multiple_occupancy;
642 : }
643 : found_slot_for_multiple_occupancy:
644 : pr_devel("same slot: %x %x [%02x]\n", i, j, slot);
645 : BUG_ON(i >= ASSOC_ARRAY_FAN_OUT);
646 : BUG_ON(j >= ASSOC_ARRAY_FAN_OUT + 1);
647 : BUG_ON(slot >= ASSOC_ARRAY_FAN_OUT);
648 :
649 0 : new_n1->parent_slot = slot;
650 :
651 : /* Metadata pointers cannot change slot */
652 0 : for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++)
653 0 : if (assoc_array_ptr_is_meta(node->slots[i]))
654 0 : new_n0->slots[i] = node->slots[i];
655 : else
656 0 : new_n0->slots[i] = NULL;
657 : BUG_ON(new_n0->slots[slot] != NULL);
658 0 : new_n0->slots[slot] = assoc_array_node_to_ptr(new_n1);
659 :
660 : /* Filter the leaf pointers between the new nodes */
661 : free_slot = -1;
662 : next_slot = 0;
663 0 : for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++) {
664 0 : if (assoc_array_ptr_is_meta(node->slots[i]))
665 0 : continue;
666 0 : if (edit->segment_cache[i] == slot) {
667 0 : new_n1->slots[next_slot++] = node->slots[i];
668 0 : new_n1->nr_leaves_on_branch++;
669 : } else {
670 : do {
671 0 : free_slot++;
672 0 : } while (new_n0->slots[free_slot] != NULL);
673 0 : new_n0->slots[free_slot] = node->slots[i];
674 : }
675 : }
676 :
677 : pr_devel("filtered: f=%x n=%x\n", free_slot, next_slot);
678 :
679 0 : if (edit->segment_cache[ASSOC_ARRAY_FAN_OUT] != slot) {
680 : do {
681 0 : free_slot++;
682 0 : } while (new_n0->slots[free_slot] != NULL);
683 0 : edit->leaf_p = &new_n0->slots[free_slot];
684 0 : edit->adjust_count_on = new_n0;
685 : } else {
686 0 : edit->leaf_p = &new_n1->slots[next_slot++];
687 0 : edit->adjust_count_on = new_n1;
688 : }
689 :
690 : BUG_ON(next_slot <= 1);
691 :
692 0 : edit->set_backpointers_to = assoc_array_node_to_ptr(new_n0);
693 0 : for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++) {
694 0 : if (edit->segment_cache[i] == 0xff) {
695 0 : ptr = node->slots[i];
696 : BUG_ON(assoc_array_ptr_is_leaf(ptr));
697 0 : if (assoc_array_ptr_is_node(ptr)) {
698 : side = assoc_array_ptr_to_node(ptr);
699 0 : edit->set_backpointers[i] = &side->back_pointer;
700 : } else {
701 : shortcut = assoc_array_ptr_to_shortcut(ptr);
702 0 : edit->set_backpointers[i] = &shortcut->back_pointer;
703 : }
704 : }
705 : }
706 :
707 0 : ptr = node->back_pointer;
708 0 : if (!ptr)
709 0 : edit->set[0].ptr = &edit->array->root;
710 0 : else if (assoc_array_ptr_is_node(ptr))
711 0 : edit->set[0].ptr = &assoc_array_ptr_to_node(ptr)->slots[node->parent_slot];
712 : else
713 0 : edit->set[0].ptr = &assoc_array_ptr_to_shortcut(ptr)->next_node;
714 0 : edit->excised_meta[0] = assoc_array_node_to_ptr(node);
715 : pr_devel("<--%s() = ok [split node]\n", __func__);
716 0 : return true;
717 :
718 : present_leaves_cluster_but_not_new_leaf:
719 : /* All the old leaves cluster in the same slot, but the new leaf wants
720 : * to go into a different slot, so we create a new node to hold the new
721 : * leaf and a pointer to a new node holding all the old leaves.
722 : */
723 : pr_devel("present leaves cluster but not new leaf\n");
724 :
725 0 : new_n0->back_pointer = node->back_pointer;
726 0 : new_n0->parent_slot = node->parent_slot;
727 0 : new_n0->nr_leaves_on_branch = node->nr_leaves_on_branch;
728 0 : new_n1->back_pointer = assoc_array_node_to_ptr(new_n0);
729 0 : new_n1->parent_slot = edit->segment_cache[0];
730 0 : new_n1->nr_leaves_on_branch = node->nr_leaves_on_branch;
731 0 : edit->adjust_count_on = new_n0;
732 :
733 0 : for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++)
734 0 : new_n1->slots[i] = node->slots[i];
735 :
736 0 : new_n0->slots[edit->segment_cache[0]] = assoc_array_node_to_ptr(new_n0);
737 0 : edit->leaf_p = &new_n0->slots[edit->segment_cache[ASSOC_ARRAY_FAN_OUT]];
738 :
739 0 : edit->set[0].ptr = &assoc_array_ptr_to_node(node->back_pointer)->slots[node->parent_slot];
740 0 : edit->set[0].to = assoc_array_node_to_ptr(new_n0);
741 0 : edit->excised_meta[0] = assoc_array_node_to_ptr(node);
742 : pr_devel("<--%s() = ok [insert node before]\n", __func__);
743 0 : return true;
744 :
745 : all_leaves_cluster_together:
746 : /* All the leaves, new and old, want to cluster together in this node
747 : * in the same slot, so we have to replace this node with a shortcut to
748 : * skip over the identical parts of the key and then place a pair of
749 : * nodes, one inside the other, at the end of the shortcut and
750 : * distribute the keys between them.
751 : *
752 : * Firstly we need to work out where the leaves start diverging as a
753 : * bit position into their keys so that we know how big the shortcut
754 : * needs to be.
755 : *
756 : * We only need to make a single pass of N of the N+1 leaves because if
757 : * any keys differ between themselves at bit X then at least one of
758 : * them must also differ with the base key at bit X or before.
759 : */
760 : pr_devel("all leaves cluster together\n");
761 : diff = INT_MAX;
762 0 : for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++) {
763 0 : int x = ops->diff_objects(assoc_array_ptr_to_leaf(node->slots[i]),
764 : index_key);
765 0 : if (x < diff) {
766 : BUG_ON(x < 0);
767 : diff = x;
768 : }
769 : }
770 : BUG_ON(diff == INT_MAX);
771 : BUG_ON(diff < level + ASSOC_ARRAY_LEVEL_STEP);
772 :
773 0 : keylen = round_up(diff, ASSOC_ARRAY_KEY_CHUNK_SIZE);
774 0 : keylen >>= ASSOC_ARRAY_KEY_CHUNK_SHIFT;
775 :
776 0 : new_s0 = kzalloc(sizeof(struct assoc_array_shortcut) +
777 : keylen * sizeof(unsigned long), GFP_KERNEL);
778 0 : if (!new_s0)
779 : return false;
780 0 : edit->new_meta[2] = assoc_array_shortcut_to_ptr(new_s0);
781 :
782 0 : edit->set[0].to = assoc_array_shortcut_to_ptr(new_s0);
783 0 : new_s0->back_pointer = node->back_pointer;
784 0 : new_s0->parent_slot = node->parent_slot;
785 0 : new_s0->next_node = assoc_array_node_to_ptr(new_n0);
786 0 : new_n0->back_pointer = assoc_array_shortcut_to_ptr(new_s0);
787 0 : new_n0->parent_slot = 0;
788 0 : new_n1->back_pointer = assoc_array_node_to_ptr(new_n0);
789 0 : new_n1->parent_slot = -1; /* Need to calculate this */
790 :
791 0 : new_s0->skip_to_level = level = diff & ~ASSOC_ARRAY_LEVEL_STEP_MASK;
792 : pr_devel("skip_to_level = %d [diff %d]\n", level, diff);
793 : BUG_ON(level <= 0);
794 :
795 0 : for (i = 0; i < keylen; i++)
796 0 : new_s0->index_key[i] =
797 0 : ops->get_key_chunk(index_key, i * ASSOC_ARRAY_KEY_CHUNK_SIZE);
798 :
799 0 : blank = ULONG_MAX << (level & ASSOC_ARRAY_KEY_CHUNK_MASK);
800 : pr_devel("blank off [%zu] %d: %lx\n", keylen - 1, level, blank);
801 0 : new_s0->index_key[keylen - 1] &= ~blank;
802 :
803 : /* This now reduces to a node splitting exercise for which we'll need
804 : * to regenerate the disparity table.
805 : */
806 0 : for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++) {
807 0 : ptr = node->slots[i];
808 0 : base_seg = ops->get_object_key_chunk(assoc_array_ptr_to_leaf(ptr),
809 : level);
810 0 : base_seg >>= level & ASSOC_ARRAY_KEY_CHUNK_MASK;
811 0 : edit->segment_cache[i] = base_seg & ASSOC_ARRAY_FAN_MASK;
812 : }
813 :
814 0 : base_seg = ops->get_key_chunk(index_key, level);
815 0 : base_seg >>= level & ASSOC_ARRAY_KEY_CHUNK_MASK;
816 0 : edit->segment_cache[ASSOC_ARRAY_FAN_OUT] = base_seg & ASSOC_ARRAY_FAN_MASK;
817 0 : goto do_split_node;
818 : }
819 :
820 : /*
821 : * Handle insertion into the middle of a shortcut.
822 : */
823 0 : static bool assoc_array_insert_mid_shortcut(struct assoc_array_edit *edit,
824 : const struct assoc_array_ops *ops,
825 : struct assoc_array_walk_result *result)
826 : {
827 : struct assoc_array_shortcut *shortcut, *new_s0, *new_s1;
828 : struct assoc_array_node *node, *new_n0, *side;
829 : unsigned long sc_segments, dissimilarity, blank;
830 : size_t keylen;
831 : int level, sc_level, diff;
832 : int sc_slot;
833 :
834 0 : shortcut = result->wrong_shortcut.shortcut;
835 0 : level = result->wrong_shortcut.level;
836 0 : sc_level = result->wrong_shortcut.sc_level;
837 0 : sc_segments = result->wrong_shortcut.sc_segments;
838 0 : dissimilarity = result->wrong_shortcut.dissimilarity;
839 :
840 : pr_devel("-->%s(ix=%d dis=%lx scix=%d)\n",
841 : __func__, level, dissimilarity, sc_level);
842 :
843 : /* We need to split a shortcut and insert a node between the two
844 : * pieces. Zero-length pieces will be dispensed with entirely.
845 : *
846 : * First of all, we need to find out in which level the first
847 : * difference was.
848 : */
849 : diff = __ffs(dissimilarity);
850 0 : diff &= ~ASSOC_ARRAY_LEVEL_STEP_MASK;
851 0 : diff += sc_level & ~ASSOC_ARRAY_KEY_CHUNK_MASK;
852 : pr_devel("diff=%d\n", diff);
853 :
854 0 : if (!shortcut->back_pointer) {
855 0 : edit->set[0].ptr = &edit->array->root;
856 0 : } else if (assoc_array_ptr_is_node(shortcut->back_pointer)) {
857 : node = assoc_array_ptr_to_node(shortcut->back_pointer);
858 0 : edit->set[0].ptr = &node->slots[shortcut->parent_slot];
859 : } else {
860 : BUG();
861 : }
862 :
863 0 : edit->excised_meta[0] = assoc_array_shortcut_to_ptr(shortcut);
864 :
865 : /* Create a new node now since we're going to need it anyway */
866 : new_n0 = kzalloc(sizeof(struct assoc_array_node), GFP_KERNEL);
867 0 : if (!new_n0)
868 : return false;
869 0 : edit->new_meta[0] = assoc_array_node_to_ptr(new_n0);
870 0 : edit->adjust_count_on = new_n0;
871 :
872 : /* Insert a new shortcut before the new node if this segment isn't of
873 : * zero length - otherwise we just connect the new node directly to the
874 : * parent.
875 : */
876 0 : level += ASSOC_ARRAY_LEVEL_STEP;
877 0 : if (diff > level) {
878 : pr_devel("pre-shortcut %d...%d\n", level, diff);
879 0 : keylen = round_up(diff, ASSOC_ARRAY_KEY_CHUNK_SIZE);
880 0 : keylen >>= ASSOC_ARRAY_KEY_CHUNK_SHIFT;
881 :
882 0 : new_s0 = kzalloc(sizeof(struct assoc_array_shortcut) +
883 : keylen * sizeof(unsigned long), GFP_KERNEL);
884 0 : if (!new_s0)
885 : return false;
886 0 : edit->new_meta[1] = assoc_array_shortcut_to_ptr(new_s0);
887 0 : edit->set[0].to = assoc_array_shortcut_to_ptr(new_s0);
888 0 : new_s0->back_pointer = shortcut->back_pointer;
889 0 : new_s0->parent_slot = shortcut->parent_slot;
890 0 : new_s0->next_node = assoc_array_node_to_ptr(new_n0);
891 0 : new_s0->skip_to_level = diff;
892 :
893 0 : new_n0->back_pointer = assoc_array_shortcut_to_ptr(new_s0);
894 0 : new_n0->parent_slot = 0;
895 :
896 0 : memcpy(new_s0->index_key, shortcut->index_key,
897 : keylen * sizeof(unsigned long));
898 :
899 0 : blank = ULONG_MAX << (diff & ASSOC_ARRAY_KEY_CHUNK_MASK);
900 : pr_devel("blank off [%zu] %d: %lx\n", keylen - 1, diff, blank);
901 0 : new_s0->index_key[keylen - 1] &= ~blank;
902 : } else {
903 : pr_devel("no pre-shortcut\n");
904 0 : edit->set[0].to = assoc_array_node_to_ptr(new_n0);
905 0 : new_n0->back_pointer = shortcut->back_pointer;
906 0 : new_n0->parent_slot = shortcut->parent_slot;
907 : }
908 :
909 0 : side = assoc_array_ptr_to_node(shortcut->next_node);
910 0 : new_n0->nr_leaves_on_branch = side->nr_leaves_on_branch;
911 :
912 : /* We need to know which slot in the new node is going to take a
913 : * metadata pointer.
914 : */
915 0 : sc_slot = sc_segments >> (diff & ASSOC_ARRAY_KEY_CHUNK_MASK);
916 0 : sc_slot &= ASSOC_ARRAY_FAN_MASK;
917 :
918 : pr_devel("new slot %lx >> %d -> %d\n",
919 : sc_segments, diff & ASSOC_ARRAY_KEY_CHUNK_MASK, sc_slot);
920 :
921 : /* Determine whether we need to follow the new node with a replacement
922 : * for the current shortcut. We could in theory reuse the current
923 : * shortcut if its parent slot number doesn't change - but that's a
924 : * 1-in-16 chance so not worth expending the code upon.
925 : */
926 0 : level = diff + ASSOC_ARRAY_LEVEL_STEP;
927 0 : if (level < shortcut->skip_to_level) {
928 : pr_devel("post-shortcut %d...%d\n", level, shortcut->skip_to_level);
929 0 : keylen = round_up(shortcut->skip_to_level, ASSOC_ARRAY_KEY_CHUNK_SIZE);
930 0 : keylen >>= ASSOC_ARRAY_KEY_CHUNK_SHIFT;
931 :
932 0 : new_s1 = kzalloc(sizeof(struct assoc_array_shortcut) +
933 : keylen * sizeof(unsigned long), GFP_KERNEL);
934 0 : if (!new_s1)
935 : return false;
936 0 : edit->new_meta[2] = assoc_array_shortcut_to_ptr(new_s1);
937 :
938 0 : new_s1->back_pointer = assoc_array_node_to_ptr(new_n0);
939 0 : new_s1->parent_slot = sc_slot;
940 0 : new_s1->next_node = shortcut->next_node;
941 0 : new_s1->skip_to_level = shortcut->skip_to_level;
942 :
943 0 : new_n0->slots[sc_slot] = assoc_array_shortcut_to_ptr(new_s1);
944 :
945 0 : memcpy(new_s1->index_key, shortcut->index_key,
946 : keylen * sizeof(unsigned long));
947 :
948 0 : edit->set[1].ptr = &side->back_pointer;
949 0 : edit->set[1].to = assoc_array_shortcut_to_ptr(new_s1);
950 : } else {
951 : pr_devel("no post-shortcut\n");
952 :
953 : /* We don't have to replace the pointed-to node as long as we
954 : * use memory barriers to make sure the parent slot number is
955 : * changed before the back pointer (the parent slot number is
956 : * irrelevant to the old parent shortcut).
957 : */
958 0 : new_n0->slots[sc_slot] = shortcut->next_node;
959 0 : edit->set_parent_slot[0].p = &side->parent_slot;
960 0 : edit->set_parent_slot[0].to = sc_slot;
961 0 : edit->set[1].ptr = &side->back_pointer;
962 0 : edit->set[1].to = assoc_array_node_to_ptr(new_n0);
963 : }
964 :
965 : /* Install the new leaf in a spare slot in the new node. */
966 0 : if (sc_slot == 0)
967 0 : edit->leaf_p = &new_n0->slots[1];
968 : else
969 0 : edit->leaf_p = &new_n0->slots[0];
970 :
971 : pr_devel("<--%s() = ok [split shortcut]\n", __func__);
972 0 : return edit;
973 : }
974 :
975 : /**
976 : * assoc_array_insert - Script insertion of an object into an associative array
977 : * @array: The array to insert into.
978 : * @ops: The operations to use.
979 : * @index_key: The key to insert at.
980 : * @object: The object to insert.
981 : *
982 : * Precalculate and preallocate a script for the insertion or replacement of an
983 : * object in an associative array. This results in an edit script that can
984 : * either be applied or cancelled.
985 : *
986 : * The function returns a pointer to an edit script or -ENOMEM.
987 : *
988 : * The caller should lock against other modifications and must continue to hold
989 : * the lock until assoc_array_apply_edit() has been called.
990 : *
991 : * Accesses to the tree may take place concurrently with this function,
992 : * provided they hold the RCU read lock.
993 : */
994 1 : struct assoc_array_edit *assoc_array_insert(struct assoc_array *array,
995 : const struct assoc_array_ops *ops,
996 : const void *index_key,
997 : void *object)
998 : {
999 : struct assoc_array_walk_result result;
1000 : struct assoc_array_edit *edit;
1001 :
1002 : pr_devel("-->%s()\n", __func__);
1003 :
1004 : /* The leaf pointer we're given must not have the bottom bit set as we
1005 : * use those for type-marking the pointer. NULL pointers are also not
1006 : * allowed as they indicate an empty slot but we have to allow them
1007 : * here as they can be updated later.
1008 : */
1009 : BUG_ON(assoc_array_ptr_is_meta(object));
1010 :
1011 : edit = kzalloc(sizeof(struct assoc_array_edit), GFP_KERNEL);
1012 1 : if (!edit)
1013 : return ERR_PTR(-ENOMEM);
1014 1 : edit->array = array;
1015 1 : edit->ops = ops;
1016 1 : edit->leaf = assoc_array_leaf_to_ptr(object);
1017 1 : edit->adjust_count_by = 1;
1018 :
1019 1 : switch (assoc_array_walk(array, ops, index_key, &result)) {
1020 : case assoc_array_walk_tree_empty:
1021 : /* Allocate a root node if there isn't one yet */
1022 1 : if (!assoc_array_insert_in_empty_tree(edit))
1023 : goto enomem;
1024 : return edit;
1025 :
1026 : case assoc_array_walk_found_terminal_node:
1027 : /* We found a node that doesn't have a node/shortcut pointer in
1028 : * the slot corresponding to the index key that we have to
1029 : * follow.
1030 : */
1031 0 : if (!assoc_array_insert_into_terminal_node(edit, ops, index_key,
1032 : &result))
1033 : goto enomem;
1034 : return edit;
1035 :
1036 : case assoc_array_walk_found_wrong_shortcut:
1037 : /* We found a shortcut that didn't match our key in a slot we
1038 : * needed to follow.
1039 : */
1040 0 : if (!assoc_array_insert_mid_shortcut(edit, ops, &result))
1041 : goto enomem;
1042 : return edit;
1043 : }
1044 :
1045 : enomem:
1046 : /* Clean up after an out of memory error */
1047 : pr_devel("enomem\n");
1048 0 : assoc_array_cancel_edit(edit);
1049 0 : return ERR_PTR(-ENOMEM);
1050 : }
1051 :
1052 : /**
1053 : * assoc_array_insert_set_object - Set the new object pointer in an edit script
1054 : * @edit: The edit script to modify.
1055 : * @object: The object pointer to set.
1056 : *
1057 : * Change the object to be inserted in an edit script. The object pointed to
1058 : * by the old object is not freed. This must be done prior to applying the
1059 : * script.
1060 : */
1061 1 : void assoc_array_insert_set_object(struct assoc_array_edit *edit, void *object)
1062 : {
1063 : BUG_ON(!object);
1064 1 : edit->leaf = assoc_array_leaf_to_ptr(object);
1065 1 : }
1066 :
1067 : struct assoc_array_delete_collapse_context {
1068 : struct assoc_array_node *node;
1069 : const void *skip_leaf;
1070 : int slot;
1071 : };
1072 :
1073 : /*
1074 : * Subtree collapse to node iterator.
1075 : */
1076 0 : static int assoc_array_delete_collapse_iterator(const void *leaf,
1077 : void *iterator_data)
1078 : {
1079 : struct assoc_array_delete_collapse_context *collapse = iterator_data;
1080 :
1081 0 : if (leaf == collapse->skip_leaf)
1082 : return 0;
1083 :
1084 : BUG_ON(collapse->slot >= ASSOC_ARRAY_FAN_OUT);
1085 :
1086 0 : collapse->node->slots[collapse->slot++] = assoc_array_leaf_to_ptr(leaf);
1087 0 : return 0;
1088 : }
1089 :
1090 : /**
1091 : * assoc_array_delete - Script deletion of an object from an associative array
1092 : * @array: The array to search.
1093 : * @ops: The operations to use.
1094 : * @index_key: The key to the object.
1095 : *
1096 : * Precalculate and preallocate a script for the deletion of an object from an
1097 : * associative array. This results in an edit script that can either be
1098 : * applied or cancelled.
1099 : *
1100 : * The function returns a pointer to an edit script if the object was found,
1101 : * NULL if the object was not found or -ENOMEM.
1102 : *
1103 : * The caller should lock against other modifications and must continue to hold
1104 : * the lock until assoc_array_apply_edit() has been called.
1105 : *
1106 : * Accesses to the tree may take place concurrently with this function,
1107 : * provided they hold the RCU read lock.
1108 : */
1109 0 : struct assoc_array_edit *assoc_array_delete(struct assoc_array *array,
1110 : const struct assoc_array_ops *ops,
1111 : const void *index_key)
1112 : {
1113 : struct assoc_array_delete_collapse_context collapse;
1114 : struct assoc_array_walk_result result;
1115 : struct assoc_array_node *node, *new_n0;
1116 : struct assoc_array_edit *edit;
1117 : struct assoc_array_ptr *ptr;
1118 : bool has_meta;
1119 : int slot, i;
1120 :
1121 : pr_devel("-->%s()\n", __func__);
1122 :
1123 : edit = kzalloc(sizeof(struct assoc_array_edit), GFP_KERNEL);
1124 0 : if (!edit)
1125 : return ERR_PTR(-ENOMEM);
1126 0 : edit->array = array;
1127 0 : edit->ops = ops;
1128 0 : edit->adjust_count_by = -1;
1129 :
1130 0 : switch (assoc_array_walk(array, ops, index_key, &result)) {
1131 : case assoc_array_walk_found_terminal_node:
1132 : /* We found a node that should contain the leaf we've been
1133 : * asked to remove - *if* it's in the tree.
1134 : */
1135 : pr_devel("terminal_node\n");
1136 0 : node = result.terminal_node.node;
1137 :
1138 0 : for (slot = 0; slot < ASSOC_ARRAY_FAN_OUT; slot++) {
1139 0 : ptr = node->slots[slot];
1140 0 : if (ptr &&
1141 0 : assoc_array_ptr_is_leaf(ptr) &&
1142 0 : ops->compare_object(assoc_array_ptr_to_leaf(ptr),
1143 : index_key))
1144 : goto found_leaf;
1145 : }
1146 : case assoc_array_walk_tree_empty:
1147 : case assoc_array_walk_found_wrong_shortcut:
1148 : default:
1149 0 : assoc_array_cancel_edit(edit);
1150 : pr_devel("not found\n");
1151 0 : return NULL;
1152 : }
1153 :
1154 : found_leaf:
1155 : BUG_ON(array->nr_leaves_on_tree <= 0);
1156 :
1157 : /* In the simplest form of deletion we just clear the slot and release
1158 : * the leaf after a suitable interval.
1159 : */
1160 0 : edit->dead_leaf = node->slots[slot];
1161 0 : edit->set[0].ptr = &node->slots[slot];
1162 0 : edit->set[0].to = NULL;
1163 0 : edit->adjust_count_on = node;
1164 :
1165 : /* If that concludes erasure of the last leaf, then delete the entire
1166 : * internal array.
1167 : */
1168 0 : if (array->nr_leaves_on_tree == 1) {
1169 0 : edit->set[1].ptr = &array->root;
1170 0 : edit->set[1].to = NULL;
1171 0 : edit->adjust_count_on = NULL;
1172 0 : edit->excised_subtree = array->root;
1173 : pr_devel("all gone\n");
1174 0 : return edit;
1175 : }
1176 :
1177 : /* However, we'd also like to clear up some metadata blocks if we
1178 : * possibly can.
1179 : *
1180 : * We go for a simple algorithm of: if this node has FAN_OUT or fewer
1181 : * leaves in it, then attempt to collapse it - and attempt to
1182 : * recursively collapse up the tree.
1183 : *
1184 : * We could also try and collapse in partially filled subtrees to take
1185 : * up space in this node.
1186 : */
1187 0 : if (node->nr_leaves_on_branch <= ASSOC_ARRAY_FAN_OUT + 1) {
1188 : struct assoc_array_node *parent, *grandparent;
1189 : struct assoc_array_ptr *ptr;
1190 :
1191 : /* First of all, we need to know if this node has metadata so
1192 : * that we don't try collapsing if all the leaves are already
1193 : * here.
1194 : */
1195 : has_meta = false;
1196 0 : for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++) {
1197 0 : ptr = node->slots[i];
1198 0 : if (assoc_array_ptr_is_meta(ptr)) {
1199 : has_meta = true;
1200 : break;
1201 : }
1202 : }
1203 :
1204 : pr_devel("leaves: %ld [m=%d]\n",
1205 : node->nr_leaves_on_branch - 1, has_meta);
1206 :
1207 : /* Look further up the tree to see if we can collapse this node
1208 : * into a more proximal node too.
1209 : */
1210 : parent = node;
1211 : collapse_up:
1212 : pr_devel("collapse subtree: %ld\n", parent->nr_leaves_on_branch);
1213 :
1214 0 : ptr = parent->back_pointer;
1215 0 : if (!ptr)
1216 : goto do_collapse;
1217 0 : if (assoc_array_ptr_is_shortcut(ptr)) {
1218 : struct assoc_array_shortcut *s = assoc_array_ptr_to_shortcut(ptr);
1219 0 : ptr = s->back_pointer;
1220 0 : if (!ptr)
1221 : goto do_collapse;
1222 : }
1223 :
1224 : grandparent = assoc_array_ptr_to_node(ptr);
1225 0 : if (grandparent->nr_leaves_on_branch <= ASSOC_ARRAY_FAN_OUT + 1) {
1226 : parent = grandparent;
1227 : goto collapse_up;
1228 : }
1229 :
1230 : do_collapse:
1231 : /* There's no point collapsing if the original node has no meta
1232 : * pointers to discard and if we didn't merge into one of that
1233 : * node's ancestry.
1234 : */
1235 0 : if (has_meta || parent != node) {
1236 : node = parent;
1237 :
1238 : /* Create a new node to collapse into */
1239 : new_n0 = kzalloc(sizeof(struct assoc_array_node), GFP_KERNEL);
1240 0 : if (!new_n0)
1241 : goto enomem;
1242 0 : edit->new_meta[0] = assoc_array_node_to_ptr(new_n0);
1243 :
1244 0 : new_n0->back_pointer = node->back_pointer;
1245 0 : new_n0->parent_slot = node->parent_slot;
1246 0 : new_n0->nr_leaves_on_branch = node->nr_leaves_on_branch;
1247 0 : edit->adjust_count_on = new_n0;
1248 :
1249 0 : collapse.node = new_n0;
1250 0 : collapse.skip_leaf = assoc_array_ptr_to_leaf(edit->dead_leaf);
1251 0 : collapse.slot = 0;
1252 0 : assoc_array_subtree_iterate(assoc_array_node_to_ptr(node),
1253 0 : node->back_pointer,
1254 : assoc_array_delete_collapse_iterator,
1255 : &collapse);
1256 : pr_devel("collapsed %d,%lu\n", collapse.slot, new_n0->nr_leaves_on_branch);
1257 : BUG_ON(collapse.slot != new_n0->nr_leaves_on_branch - 1);
1258 :
1259 0 : if (!node->back_pointer) {
1260 0 : edit->set[1].ptr = &array->root;
1261 0 : } else if (assoc_array_ptr_is_leaf(node->back_pointer)) {
1262 : BUG();
1263 0 : } else if (assoc_array_ptr_is_node(node->back_pointer)) {
1264 : struct assoc_array_node *p =
1265 : assoc_array_ptr_to_node(node->back_pointer);
1266 0 : edit->set[1].ptr = &p->slots[node->parent_slot];
1267 0 : } else if (assoc_array_ptr_is_shortcut(node->back_pointer)) {
1268 : struct assoc_array_shortcut *s =
1269 : assoc_array_ptr_to_shortcut(node->back_pointer);
1270 0 : edit->set[1].ptr = &s->next_node;
1271 : }
1272 0 : edit->set[1].to = assoc_array_node_to_ptr(new_n0);
1273 0 : edit->excised_subtree = assoc_array_node_to_ptr(node);
1274 : }
1275 : }
1276 :
1277 0 : return edit;
1278 :
1279 : enomem:
1280 : /* Clean up after an out of memory error */
1281 : pr_devel("enomem\n");
1282 0 : assoc_array_cancel_edit(edit);
1283 0 : return ERR_PTR(-ENOMEM);
1284 : }
1285 :
1286 : /**
1287 : * assoc_array_clear - Script deletion of all objects from an associative array
1288 : * @array: The array to clear.
1289 : * @ops: The operations to use.
1290 : *
1291 : * Precalculate and preallocate a script for the deletion of all the objects
1292 : * from an associative array. This results in an edit script that can either
1293 : * be applied or cancelled.
1294 : *
1295 : * The function returns a pointer to an edit script if there are objects to be
1296 : * deleted, NULL if there are no objects in the array or -ENOMEM.
1297 : *
1298 : * The caller should lock against other modifications and must continue to hold
1299 : * the lock until assoc_array_apply_edit() has been called.
1300 : *
1301 : * Accesses to the tree may take place concurrently with this function,
1302 : * provided they hold the RCU read lock.
1303 : */
1304 0 : struct assoc_array_edit *assoc_array_clear(struct assoc_array *array,
1305 : const struct assoc_array_ops *ops)
1306 : {
1307 : struct assoc_array_edit *edit;
1308 :
1309 : pr_devel("-->%s()\n", __func__);
1310 :
1311 0 : if (!array->root)
1312 : return NULL;
1313 :
1314 : edit = kzalloc(sizeof(struct assoc_array_edit), GFP_KERNEL);
1315 0 : if (!edit)
1316 : return ERR_PTR(-ENOMEM);
1317 0 : edit->array = array;
1318 0 : edit->ops = ops;
1319 0 : edit->set[1].ptr = &array->root;
1320 0 : edit->set[1].to = NULL;
1321 0 : edit->excised_subtree = array->root;
1322 0 : edit->ops_for_excised_subtree = ops;
1323 : pr_devel("all gone\n");
1324 0 : return edit;
1325 : }
1326 :
1327 : /*
1328 : * Handle the deferred destruction after an applied edit.
1329 : */
1330 1 : static void assoc_array_rcu_cleanup(struct rcu_head *head)
1331 : {
1332 : struct assoc_array_edit *edit =
1333 : container_of(head, struct assoc_array_edit, rcu);
1334 : int i;
1335 :
1336 : pr_devel("-->%s()\n", __func__);
1337 :
1338 1 : if (edit->dead_leaf)
1339 0 : edit->ops->free_object(assoc_array_ptr_to_leaf(edit->dead_leaf));
1340 1 : for (i = 0; i < ARRAY_SIZE(edit->excised_meta); i++)
1341 1 : if (edit->excised_meta[i])
1342 0 : kfree(assoc_array_ptr_to_node(edit->excised_meta[i]));
1343 :
1344 1 : if (edit->excised_subtree) {
1345 : BUG_ON(assoc_array_ptr_is_leaf(edit->excised_subtree));
1346 0 : if (assoc_array_ptr_is_node(edit->excised_subtree)) {
1347 : struct assoc_array_node *n =
1348 : assoc_array_ptr_to_node(edit->excised_subtree);
1349 0 : n->back_pointer = NULL;
1350 : } else {
1351 : struct assoc_array_shortcut *s =
1352 : assoc_array_ptr_to_shortcut(edit->excised_subtree);
1353 0 : s->back_pointer = NULL;
1354 : }
1355 0 : assoc_array_destroy_subtree(edit->excised_subtree,
1356 : edit->ops_for_excised_subtree);
1357 : }
1358 :
1359 1 : kfree(edit);
1360 1 : }
1361 :
1362 : /**
1363 : * assoc_array_apply_edit - Apply an edit script to an associative array
1364 : * @edit: The script to apply.
1365 : *
1366 : * Apply an edit script to an associative array to effect an insertion,
1367 : * deletion or clearance. As the edit script includes preallocated memory,
1368 : * this is guaranteed not to fail.
1369 : *
1370 : * The edit script, dead objects and dead metadata will be scheduled for
1371 : * destruction after an RCU grace period to permit those doing read-only
1372 : * accesses on the array to continue to do so under the RCU read lock whilst
1373 : * the edit is taking place.
1374 : */
1375 1 : void assoc_array_apply_edit(struct assoc_array_edit *edit)
1376 : {
1377 : struct assoc_array_shortcut *shortcut;
1378 : struct assoc_array_node *node;
1379 : struct assoc_array_ptr *ptr;
1380 : int i;
1381 :
1382 : pr_devel("-->%s()\n", __func__);
1383 :
1384 1 : smp_wmb();
1385 1 : if (edit->leaf_p)
1386 1 : *edit->leaf_p = edit->leaf;
1387 :
1388 1 : smp_wmb();
1389 2 : for (i = 0; i < ARRAY_SIZE(edit->set_parent_slot); i++)
1390 1 : if (edit->set_parent_slot[i].p)
1391 0 : *edit->set_parent_slot[i].p = edit->set_parent_slot[i].to;
1392 :
1393 1 : smp_wmb();
1394 17 : for (i = 0; i < ARRAY_SIZE(edit->set_backpointers); i++)
1395 16 : if (edit->set_backpointers[i])
1396 0 : *edit->set_backpointers[i] = edit->set_backpointers_to;
1397 :
1398 1 : smp_wmb();
1399 3 : for (i = 0; i < ARRAY_SIZE(edit->set); i++)
1400 2 : if (edit->set[i].ptr)
1401 1 : *edit->set[i].ptr = edit->set[i].to;
1402 :
1403 1 : if (edit->array->root == NULL) {
1404 0 : edit->array->nr_leaves_on_tree = 0;
1405 1 : } else if (edit->adjust_count_on) {
1406 : node = edit->adjust_count_on;
1407 : for (;;) {
1408 1 : node->nr_leaves_on_branch += edit->adjust_count_by;
1409 :
1410 1 : ptr = node->back_pointer;
1411 1 : if (!ptr)
1412 : break;
1413 0 : if (assoc_array_ptr_is_shortcut(ptr)) {
1414 : shortcut = assoc_array_ptr_to_shortcut(ptr);
1415 0 : ptr = shortcut->back_pointer;
1416 0 : if (!ptr)
1417 : break;
1418 : }
1419 : BUG_ON(!assoc_array_ptr_is_node(ptr));
1420 : node = assoc_array_ptr_to_node(ptr);
1421 0 : }
1422 :
1423 1 : edit->array->nr_leaves_on_tree += edit->adjust_count_by;
1424 : }
1425 :
1426 1 : call_rcu(&edit->rcu, assoc_array_rcu_cleanup);
1427 1 : }
1428 :
1429 : /**
1430 : * assoc_array_cancel_edit - Discard an edit script.
1431 : * @edit: The script to discard.
1432 : *
1433 : * Free an edit script and all the preallocated data it holds without making
1434 : * any changes to the associative array it was intended for.
1435 : *
1436 : * NOTE! In the case of an insertion script, this does _not_ release the leaf
1437 : * that was to be inserted. That is left to the caller.
1438 : */
1439 0 : void assoc_array_cancel_edit(struct assoc_array_edit *edit)
1440 : {
1441 : struct assoc_array_ptr *ptr;
1442 : int i;
1443 :
1444 : pr_devel("-->%s()\n", __func__);
1445 :
1446 : /* Clean up after an out of memory error */
1447 0 : for (i = 0; i < ARRAY_SIZE(edit->new_meta); i++) {
1448 0 : ptr = edit->new_meta[i];
1449 0 : if (ptr) {
1450 0 : if (assoc_array_ptr_is_node(ptr))
1451 0 : kfree(assoc_array_ptr_to_node(ptr));
1452 : else
1453 0 : kfree(assoc_array_ptr_to_shortcut(ptr));
1454 : }
1455 : }
1456 0 : kfree(edit);
1457 0 : }
1458 :
1459 : /**
1460 : * assoc_array_gc - Garbage collect an associative array.
1461 : * @array: The array to clean.
1462 : * @ops: The operations to use.
1463 : * @iterator: A callback function to pass judgement on each object.
1464 : * @iterator_data: Private data for the callback function.
1465 : *
1466 : * Collect garbage from an associative array and pack down the internal tree to
1467 : * save memory.
1468 : *
1469 : * The iterator function is asked to pass judgement upon each object in the
1470 : * array. If it returns false, the object is discard and if it returns true,
1471 : * the object is kept. If it returns true, it must increment the object's
1472 : * usage count (or whatever it needs to do to retain it) before returning.
1473 : *
1474 : * This function returns 0 if successful or -ENOMEM if out of memory. In the
1475 : * latter case, the array is not changed.
1476 : *
1477 : * The caller should lock against other modifications and must continue to hold
1478 : * the lock until assoc_array_apply_edit() has been called.
1479 : *
1480 : * Accesses to the tree may take place concurrently with this function,
1481 : * provided they hold the RCU read lock.
1482 : */
1483 0 : int assoc_array_gc(struct assoc_array *array,
1484 : const struct assoc_array_ops *ops,
1485 : bool (*iterator)(void *object, void *iterator_data),
1486 : void *iterator_data)
1487 : {
1488 : struct assoc_array_shortcut *shortcut, *new_s;
1489 : struct assoc_array_node *node, *new_n;
1490 : struct assoc_array_edit *edit;
1491 : struct assoc_array_ptr *cursor, *ptr;
1492 : struct assoc_array_ptr *new_root, *new_parent, **new_ptr_pp;
1493 : unsigned long nr_leaves_on_tree;
1494 : int keylen, slot, nr_free, next_slot, i;
1495 :
1496 : pr_devel("-->%s()\n", __func__);
1497 :
1498 0 : if (!array->root)
1499 : return 0;
1500 :
1501 : edit = kzalloc(sizeof(struct assoc_array_edit), GFP_KERNEL);
1502 0 : if (!edit)
1503 : return -ENOMEM;
1504 0 : edit->array = array;
1505 0 : edit->ops = ops;
1506 0 : edit->ops_for_excised_subtree = ops;
1507 0 : edit->set[0].ptr = &array->root;
1508 0 : edit->excised_subtree = array->root;
1509 :
1510 0 : new_root = new_parent = NULL;
1511 : new_ptr_pp = &new_root;
1512 0 : cursor = array->root;
1513 :
1514 : descend:
1515 : /* If this point is a shortcut, then we need to duplicate it and
1516 : * advance the target cursor.
1517 : */
1518 0 : if (assoc_array_ptr_is_shortcut(cursor)) {
1519 : shortcut = assoc_array_ptr_to_shortcut(cursor);
1520 0 : keylen = round_up(shortcut->skip_to_level, ASSOC_ARRAY_KEY_CHUNK_SIZE);
1521 0 : keylen >>= ASSOC_ARRAY_KEY_CHUNK_SHIFT;
1522 0 : new_s = kmalloc(sizeof(struct assoc_array_shortcut) +
1523 : keylen * sizeof(unsigned long), GFP_KERNEL);
1524 0 : if (!new_s)
1525 : goto enomem;
1526 : pr_devel("dup shortcut %p -> %p\n", shortcut, new_s);
1527 0 : memcpy(new_s, shortcut, (sizeof(struct assoc_array_shortcut) +
1528 : keylen * sizeof(unsigned long)));
1529 0 : new_s->back_pointer = new_parent;
1530 0 : new_s->parent_slot = shortcut->parent_slot;
1531 0 : *new_ptr_pp = new_parent = assoc_array_shortcut_to_ptr(new_s);
1532 0 : new_ptr_pp = &new_s->next_node;
1533 0 : cursor = shortcut->next_node;
1534 : }
1535 :
1536 : /* Duplicate the node at this position */
1537 : node = assoc_array_ptr_to_node(cursor);
1538 : new_n = kzalloc(sizeof(struct assoc_array_node), GFP_KERNEL);
1539 0 : if (!new_n)
1540 : goto enomem;
1541 : pr_devel("dup node %p -> %p\n", node, new_n);
1542 0 : new_n->back_pointer = new_parent;
1543 0 : new_n->parent_slot = node->parent_slot;
1544 0 : *new_ptr_pp = new_parent = assoc_array_node_to_ptr(new_n);
1545 : new_ptr_pp = NULL;
1546 : slot = 0;
1547 :
1548 : continue_node:
1549 : /* Filter across any leaves and gc any subtrees */
1550 0 : for (; slot < ASSOC_ARRAY_FAN_OUT; slot++) {
1551 0 : ptr = node->slots[slot];
1552 0 : if (!ptr)
1553 0 : continue;
1554 :
1555 0 : if (assoc_array_ptr_is_leaf(ptr)) {
1556 0 : if (iterator(assoc_array_ptr_to_leaf(ptr),
1557 : iterator_data))
1558 : /* The iterator will have done any reference
1559 : * counting on the object for us.
1560 : */
1561 0 : new_n->slots[slot] = ptr;
1562 0 : continue;
1563 : }
1564 :
1565 0 : new_ptr_pp = &new_n->slots[slot];
1566 : cursor = ptr;
1567 0 : goto descend;
1568 : }
1569 :
1570 : pr_devel("-- compress node %p --\n", new_n);
1571 :
1572 : /* Count up the number of empty slots in this node and work out the
1573 : * subtree leaf count.
1574 : */
1575 0 : new_n->nr_leaves_on_branch = 0;
1576 : nr_free = 0;
1577 0 : for (slot = 0; slot < ASSOC_ARRAY_FAN_OUT; slot++) {
1578 0 : ptr = new_n->slots[slot];
1579 0 : if (!ptr)
1580 0 : nr_free++;
1581 0 : else if (assoc_array_ptr_is_leaf(ptr))
1582 0 : new_n->nr_leaves_on_branch++;
1583 : }
1584 : pr_devel("free=%d, leaves=%lu\n", nr_free, new_n->nr_leaves_on_branch);
1585 :
1586 : /* See what we can fold in */
1587 : next_slot = 0;
1588 0 : for (slot = 0; slot < ASSOC_ARRAY_FAN_OUT; slot++) {
1589 : struct assoc_array_shortcut *s;
1590 : struct assoc_array_node *child;
1591 :
1592 0 : ptr = new_n->slots[slot];
1593 0 : if (!ptr || assoc_array_ptr_is_leaf(ptr))
1594 0 : continue;
1595 :
1596 : s = NULL;
1597 0 : if (assoc_array_ptr_is_shortcut(ptr)) {
1598 : s = assoc_array_ptr_to_shortcut(ptr);
1599 0 : ptr = s->next_node;
1600 : }
1601 :
1602 : child = assoc_array_ptr_to_node(ptr);
1603 0 : new_n->nr_leaves_on_branch += child->nr_leaves_on_branch;
1604 :
1605 0 : if (child->nr_leaves_on_branch <= nr_free + 1) {
1606 : /* Fold the child node into this one */
1607 : pr_devel("[%d] fold node %lu/%d [nx %d]\n",
1608 : slot, child->nr_leaves_on_branch, nr_free + 1,
1609 : next_slot);
1610 :
1611 : /* We would already have reaped an intervening shortcut
1612 : * on the way back up the tree.
1613 : */
1614 : BUG_ON(s);
1615 :
1616 0 : new_n->slots[slot] = NULL;
1617 : nr_free++;
1618 0 : if (slot < next_slot)
1619 : next_slot = slot;
1620 0 : for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++) {
1621 0 : struct assoc_array_ptr *p = child->slots[i];
1622 0 : if (!p)
1623 0 : continue;
1624 : BUG_ON(assoc_array_ptr_is_meta(p));
1625 0 : while (new_n->slots[next_slot])
1626 0 : next_slot++;
1627 : BUG_ON(next_slot >= ASSOC_ARRAY_FAN_OUT);
1628 0 : new_n->slots[next_slot++] = p;
1629 0 : nr_free--;
1630 : }
1631 0 : kfree(child);
1632 : } else {
1633 : pr_devel("[%d] retain node %lu/%d [nx %d]\n",
1634 : slot, child->nr_leaves_on_branch, nr_free + 1,
1635 : next_slot);
1636 : }
1637 : }
1638 :
1639 : pr_devel("after: %lu\n", new_n->nr_leaves_on_branch);
1640 :
1641 0 : nr_leaves_on_tree = new_n->nr_leaves_on_branch;
1642 :
1643 : /* Excise this node if it is singly occupied by a shortcut */
1644 0 : if (nr_free == ASSOC_ARRAY_FAN_OUT - 1) {
1645 0 : for (slot = 0; slot < ASSOC_ARRAY_FAN_OUT; slot++)
1646 0 : if ((ptr = new_n->slots[slot]))
1647 : break;
1648 :
1649 0 : if (assoc_array_ptr_is_meta(ptr) &&
1650 : assoc_array_ptr_is_shortcut(ptr)) {
1651 : pr_devel("excise node %p with 1 shortcut\n", new_n);
1652 : new_s = assoc_array_ptr_to_shortcut(ptr);
1653 0 : new_parent = new_n->back_pointer;
1654 0 : slot = new_n->parent_slot;
1655 0 : kfree(new_n);
1656 0 : if (!new_parent) {
1657 0 : new_s->back_pointer = NULL;
1658 0 : new_s->parent_slot = 0;
1659 0 : new_root = ptr;
1660 0 : goto gc_complete;
1661 : }
1662 :
1663 0 : if (assoc_array_ptr_is_shortcut(new_parent)) {
1664 : /* We can discard any preceding shortcut also */
1665 : struct assoc_array_shortcut *s =
1666 : assoc_array_ptr_to_shortcut(new_parent);
1667 :
1668 : pr_devel("excise preceding shortcut\n");
1669 :
1670 0 : new_parent = new_s->back_pointer = s->back_pointer;
1671 0 : slot = new_s->parent_slot = s->parent_slot;
1672 0 : kfree(s);
1673 0 : if (!new_parent) {
1674 0 : new_s->back_pointer = NULL;
1675 0 : new_s->parent_slot = 0;
1676 0 : new_root = ptr;
1677 0 : goto gc_complete;
1678 : }
1679 : }
1680 :
1681 0 : new_s->back_pointer = new_parent;
1682 0 : new_s->parent_slot = slot;
1683 : new_n = assoc_array_ptr_to_node(new_parent);
1684 0 : new_n->slots[slot] = ptr;
1685 0 : goto ascend_old_tree;
1686 : }
1687 : }
1688 :
1689 : /* Excise any shortcuts we might encounter that point to nodes that
1690 : * only contain leaves.
1691 : */
1692 0 : ptr = new_n->back_pointer;
1693 0 : if (!ptr)
1694 : goto gc_complete;
1695 :
1696 0 : if (assoc_array_ptr_is_shortcut(ptr)) {
1697 : new_s = assoc_array_ptr_to_shortcut(ptr);
1698 0 : new_parent = new_s->back_pointer;
1699 0 : slot = new_s->parent_slot;
1700 :
1701 0 : if (new_n->nr_leaves_on_branch <= ASSOC_ARRAY_FAN_OUT) {
1702 : struct assoc_array_node *n;
1703 :
1704 : pr_devel("excise shortcut\n");
1705 0 : new_n->back_pointer = new_parent;
1706 0 : new_n->parent_slot = slot;
1707 0 : kfree(new_s);
1708 0 : if (!new_parent) {
1709 0 : new_root = assoc_array_node_to_ptr(new_n);
1710 0 : goto gc_complete;
1711 : }
1712 :
1713 : n = assoc_array_ptr_to_node(new_parent);
1714 0 : n->slots[slot] = assoc_array_node_to_ptr(new_n);
1715 : }
1716 : } else {
1717 : new_parent = ptr;
1718 : }
1719 : new_n = assoc_array_ptr_to_node(new_parent);
1720 :
1721 : ascend_old_tree:
1722 0 : ptr = node->back_pointer;
1723 0 : if (assoc_array_ptr_is_shortcut(ptr)) {
1724 : shortcut = assoc_array_ptr_to_shortcut(ptr);
1725 0 : slot = shortcut->parent_slot;
1726 0 : cursor = shortcut->back_pointer;
1727 0 : if (!cursor)
1728 : goto gc_complete;
1729 : } else {
1730 0 : slot = node->parent_slot;
1731 : cursor = ptr;
1732 : }
1733 : BUG_ON(!cursor);
1734 : node = assoc_array_ptr_to_node(cursor);
1735 0 : slot++;
1736 0 : goto continue_node;
1737 :
1738 : gc_complete:
1739 0 : edit->set[0].to = new_root;
1740 0 : assoc_array_apply_edit(edit);
1741 0 : array->nr_leaves_on_tree = nr_leaves_on_tree;
1742 0 : return 0;
1743 :
1744 : enomem:
1745 : pr_devel("enomem\n");
1746 0 : assoc_array_destroy_subtree(new_root, edit->ops);
1747 0 : kfree(edit);
1748 0 : return -ENOMEM;
1749 : }
|