📄 radix-tree.c
字号:
*/void *radix_tree_lookup(struct radix_tree_root *root, unsigned long index){ unsigned int height, shift; struct radix_tree_node *node, **slot; node = rcu_dereference(root->rnode); if (node == NULL) return NULL; if (!radix_tree_is_indirect_ptr(node)) { if (index > 0) return NULL; return node; } node = radix_tree_indirect_to_ptr(node); height = node->height; if (index > radix_tree_maxindex(height)) return NULL; shift = (height-1) * RADIX_TREE_MAP_SHIFT; do { slot = (struct radix_tree_node **) (node->slots + ((index>>shift) & RADIX_TREE_MAP_MASK)); node = rcu_dereference(*slot); if (node == NULL) return NULL; shift -= RADIX_TREE_MAP_SHIFT; height--; } while (height > 0); return node;}EXPORT_SYMBOL(radix_tree_lookup);/** * radix_tree_tag_set - set a tag on a radix tree node * @root: radix tree root * @index: index key * @tag: tag index * * Set the search tag (which must be < RADIX_TREE_MAX_TAGS) * corresponding to @index in the radix tree. From * the root all the way down to the leaf node. * * Returns the address of the tagged item. Setting a tag on a not-present * item is a bug. */void *radix_tree_tag_set(struct radix_tree_root *root, unsigned long index, unsigned int tag){ unsigned int height, shift; struct radix_tree_node *slot; height = root->height; BUG_ON(index > radix_tree_maxindex(height)); slot = radix_tree_indirect_to_ptr(root->rnode); shift = (height - 1) * RADIX_TREE_MAP_SHIFT; while (height > 0) { int offset; offset = (index >> shift) & RADIX_TREE_MAP_MASK; if (!tag_get(slot, tag, offset)) tag_set(slot, tag, offset); slot = slot->slots[offset]; BUG_ON(slot == NULL); shift -= RADIX_TREE_MAP_SHIFT; height--; } /* set the root's tag bit */ if (slot && !root_tag_get(root, tag)) root_tag_set(root, tag); return slot;}EXPORT_SYMBOL(radix_tree_tag_set);/** * radix_tree_tag_clear - clear a tag on a radix tree node * @root: radix tree root * @index: index key * @tag: tag index * * Clear the search tag (which must be < RADIX_TREE_MAX_TAGS) * corresponding to @index in the radix tree. If * this causes the leaf node to have no tags set then clear the tag in the * next-to-leaf node, etc. * * Returns the address of the tagged item on success, else NULL. ie: * has the same return value and semantics as radix_tree_lookup(). */void *radix_tree_tag_clear(struct radix_tree_root *root, unsigned long index, unsigned int tag){ /* * The radix tree path needs to be one longer than the maximum path * since the "list" is null terminated. */ struct radix_tree_path path[RADIX_TREE_MAX_PATH + 1], *pathp = path; struct radix_tree_node *slot = NULL; unsigned int height, shift; height = root->height; if (index > radix_tree_maxindex(height)) goto out; shift = (height - 1) * RADIX_TREE_MAP_SHIFT; pathp->node = NULL; slot = radix_tree_indirect_to_ptr(root->rnode); while (height > 0) { int offset; if (slot == NULL) goto out; offset = (index >> shift) & RADIX_TREE_MAP_MASK; pathp[1].offset = offset; pathp[1].node = slot; slot = slot->slots[offset]; pathp++; shift -= RADIX_TREE_MAP_SHIFT; height--; } if (slot == NULL) goto out; while (pathp->node) { if (!tag_get(pathp->node, tag, pathp->offset)) goto out; tag_clear(pathp->node, tag, pathp->offset); if (any_tag_set(pathp->node, tag)) goto out; pathp--; } /* clear the root's tag bit */ if (root_tag_get(root, tag)) root_tag_clear(root, tag);out: return slot;}EXPORT_SYMBOL(radix_tree_tag_clear);#ifndef __KERNEL__ /* Only the test harness uses this at present *//** * radix_tree_tag_get - get a tag on a radix tree node * @root: radix tree root * @index: index key * @tag: tag index (< RADIX_TREE_MAX_TAGS) * * Return values: * * 0: tag not present or not set * 1: tag set */int radix_tree_tag_get(struct radix_tree_root *root, unsigned long index, unsigned int tag){ unsigned int height, shift; struct radix_tree_node *node; int saw_unset_tag = 0; /* check the root's tag bit */ if (!root_tag_get(root, tag)) return 0; node = rcu_dereference(root->rnode); if (node == NULL) return 0; if (!radix_tree_is_indirect_ptr(node)) return (index == 0); node = radix_tree_indirect_to_ptr(node); height = node->height; if (index > radix_tree_maxindex(height)) return 0; shift = (height - 1) * RADIX_TREE_MAP_SHIFT; for ( ; ; ) { int offset; if (node == NULL) return 0; offset = (index >> shift) & RADIX_TREE_MAP_MASK; /* * This is just a debug check. Later, we can bale as soon as * we see an unset tag. */ if (!tag_get(node, tag, offset)) saw_unset_tag = 1; if (height == 1) { int ret = tag_get(node, tag, offset); BUG_ON(ret && saw_unset_tag); return !!ret; } node = rcu_dereference(node->slots[offset]); shift -= RADIX_TREE_MAP_SHIFT; height--; }}EXPORT_SYMBOL(radix_tree_tag_get);#endif/** * radix_tree_next_hole - find the next hole (not-present entry) * @root: tree root * @index: index key * @max_scan: maximum range to search * * Search the set [index, min(index+max_scan-1, MAX_INDEX)] for the lowest * indexed hole. * * Returns: the index of the hole if found, otherwise returns an index * outside of the set specified (in which case 'return - index >= max_scan' * will be true). * * radix_tree_next_hole may be called under rcu_read_lock. However, like * radix_tree_gang_lookup, this will not atomically search a snapshot of the * tree at a single point in time. For example, if a hole is created at index * 5, then subsequently a hole is created at index 10, radix_tree_next_hole * covering both indexes may return 10 if called under rcu_read_lock. */unsigned long radix_tree_next_hole(struct radix_tree_root *root, unsigned long index, unsigned long max_scan){ unsigned long i; for (i = 0; i < max_scan; i++) { if (!radix_tree_lookup(root, index)) break; index++; if (index == 0) break; } return index;}EXPORT_SYMBOL(radix_tree_next_hole);static unsigned int__lookup(struct radix_tree_node *slot, void ***results, unsigned long index, unsigned int max_items, unsigned long *next_index){ unsigned int nr_found = 0; unsigned int shift, height; unsigned long i; height = slot->height; if (height == 0) goto out; shift = (height-1) * RADIX_TREE_MAP_SHIFT; for ( ; height > 1; height--) { i = (index >> shift) & RADIX_TREE_MAP_MASK; for (;;) { if (slot->slots[i] != NULL) break; index &= ~((1UL << shift) - 1); index += 1UL << shift; if (index == 0) goto out; /* 32-bit wraparound */ i++; if (i == RADIX_TREE_MAP_SIZE) goto out; } shift -= RADIX_TREE_MAP_SHIFT; slot = rcu_dereference(slot->slots[i]); if (slot == NULL) goto out; } /* Bottom level: grab some items */ for (i = index & RADIX_TREE_MAP_MASK; i < RADIX_TREE_MAP_SIZE; i++) { index++; if (slot->slots[i]) { results[nr_found++] = &(slot->slots[i]); if (nr_found == max_items) goto out; } }out: *next_index = index; return nr_found;}/** * radix_tree_gang_lookup - perform multiple lookup on a radix tree * @root: radix tree root * @results: where the results of the lookup are placed * @first_index: start the lookup from this key * @max_items: place up to this many items at *results * * Performs an index-ascending scan of the tree for present items. Places * them at *@results and returns the number of items which were placed at * *@results. * * The implementation is naive. * * Like radix_tree_lookup, radix_tree_gang_lookup may be called under * rcu_read_lock. In this case, rather than the returned results being * an atomic snapshot of the tree at a single point in time, the semantics * of an RCU protected gang lookup are as though multiple radix_tree_lookups * have been issued in individual locks, and results stored in 'results'. */unsigned intradix_tree_gang_lookup(struct radix_tree_root *root, void **results, unsigned long first_index, unsigned int max_items){ unsigned long max_index; struct radix_tree_node *node; unsigned long cur_index = first_index; unsigned int ret; node = rcu_dereference(root->rnode); if (!node) return 0; if (!radix_tree_is_indirect_ptr(node)) { if (first_index > 0) return 0; results[0] = node; return 1; } node = radix_tree_indirect_to_ptr(node); max_index = radix_tree_maxindex(node->height); ret = 0; while (ret < max_items) { unsigned int nr_found, slots_found, i; unsigned long next_index; /* Index of next search */ if (cur_index > max_index) break; slots_found = __lookup(node, (void ***)results + ret, cur_index, max_items - ret, &next_index); nr_found = 0; for (i = 0; i < slots_found; i++) { struct radix_tree_node *slot; slot = *(((void ***)results)[ret + i]); if (!slot) continue; results[ret + nr_found] = rcu_dereference(slot); nr_found++; } ret += nr_found; if (next_index == 0) break; cur_index = next_index; } return ret;}EXPORT_SYMBOL(radix_tree_gang_lookup);/** * radix_tree_gang_lookup_slot - perform multiple slot lookup on radix tree * @root: radix tree root * @results: where the results of the lookup are placed * @first_index: start the lookup from this key * @max_items: place up to this many items at *results * * Performs an index-ascending scan of the tree for present items. Places * their slots at *@results and returns the number of items which were * placed at *@results. * * The implementation is naive. * * Like radix_tree_gang_lookup as far as RCU and locking goes. Slots must * be dereferenced with radix_tree_deref_slot, and if using only RCU * protection, radix_tree_deref_slot may fail requiring a retry. */unsigned intradix_tree_gang_lookup_slot(struct radix_tree_root *root, void ***results, unsigned long first_index, unsigned int max_items){ unsigned long max_index; struct radix_tree_node *node; unsigned long cur_index = first_index; unsigned int ret; node = rcu_dereference(root->rnode); if (!node) return 0; if (!radix_tree_is_indirect_ptr(node)) { if (first_index > 0) return 0; results[0] = (void **)&root->rnode; return 1; } node = radix_tree_indirect_to_ptr(node); max_index = radix_tree_maxindex(node->height); ret = 0; while (ret < max_items) { unsigned int slots_found; unsigned long next_index; /* Index of next search */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -