Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

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