📄 radix-tree.c
字号:
if (cur_index > max_index) break; slots_found = __lookup(node, results + ret, cur_index, max_items - ret, &next_index); ret += slots_found; if (next_index == 0) break; cur_index = next_index; } return ret;}EXPORT_SYMBOL(radix_tree_gang_lookup_slot);/* * FIXME: the two tag_get()s here should use find_next_bit() instead of * open-coding the search. */static unsigned int__lookup_tag(struct radix_tree_node *slot, void ***results, unsigned long index, unsigned int max_items, unsigned long *next_index, unsigned int tag){ unsigned int nr_found = 0; unsigned int shift, height; height = slot->height; if (height == 0) goto out; shift = (height-1) * RADIX_TREE_MAP_SHIFT; while (height > 0) { unsigned long i = (index >> shift) & RADIX_TREE_MAP_MASK ; for (;;) { if (tag_get(slot, tag, i)) 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; } height--; if (height == 0) { /* Bottom level: grab some items */ unsigned long j = index & RADIX_TREE_MAP_MASK; for ( ; j < RADIX_TREE_MAP_SIZE; j++) { index++; if (!tag_get(slot, tag, j)) continue; /* * Even though the tag was found set, we need to * recheck that we have a non-NULL node, because * if this lookup is lockless, it may have been * subsequently deleted. * * Similar care must be taken in any place that * lookup ->slots[x] without a lock (ie. can't * rely on its value remaining the same). */ if (slot->slots[j]) { results[nr_found++] = &(slot->slots[j]); if (nr_found == max_items) goto out; } } } shift -= RADIX_TREE_MAP_SHIFT; slot = rcu_dereference(slot->slots[i]); if (slot == NULL) break; }out: *next_index = index; return nr_found;}/** * radix_tree_gang_lookup_tag - perform multiple lookup on a radix tree * based on a tag * @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 * @tag: the tag index (< RADIX_TREE_MAX_TAGS) * * Performs an index-ascending scan of the tree for present items which * have the tag indexed by @tag set. Places the items at *@results and * returns the number of items which were placed at *@results. */unsigned intradix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results, unsigned long first_index, unsigned int max_items, unsigned int tag){ struct radix_tree_node *node; unsigned long max_index; unsigned long cur_index = first_index; unsigned int ret; /* check the root's tag bit */ if (!root_tag_get(root, tag)) return 0; 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_tag(node, (void ***)results + ret, cur_index, max_items - ret, &next_index, tag); 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_tag);/** * radix_tree_gang_lookup_tag_slot - perform multiple slot lookup on a * radix tree based on a tag * @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 * @tag: the tag index (< RADIX_TREE_MAX_TAGS) * * Performs an index-ascending scan of the tree for present items which * have the tag indexed by @tag set. Places the slots at *@results and * returns the number of slots which were placed at *@results. */unsigned intradix_tree_gang_lookup_tag_slot(struct radix_tree_root *root, void ***results, unsigned long first_index, unsigned int max_items, unsigned int tag){ struct radix_tree_node *node; unsigned long max_index; unsigned long cur_index = first_index; unsigned int ret; /* check the root's tag bit */ if (!root_tag_get(root, tag)) return 0; 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 */ if (cur_index > max_index) break; slots_found = __lookup_tag(node, results + ret, cur_index, max_items - ret, &next_index, tag); ret += slots_found; if (next_index == 0) break; cur_index = next_index; } return ret;}EXPORT_SYMBOL(radix_tree_gang_lookup_tag_slot);/** * radix_tree_shrink - shrink height of a radix tree to minimal * @root radix tree root */static inline void radix_tree_shrink(struct radix_tree_root *root){ /* try to shrink tree height */ while (root->height > 0) { struct radix_tree_node *to_free = root->rnode; void *newptr; BUG_ON(!radix_tree_is_indirect_ptr(to_free)); to_free = radix_tree_indirect_to_ptr(to_free); /* * The candidate node has more than one child, or its child * is not at the leftmost slot, we cannot shrink. */ if (to_free->count != 1) break; if (!to_free->slots[0]) break; /* * We don't need rcu_assign_pointer(), since we are simply * moving the node from one part of the tree to another. If * it was safe to dereference the old pointer to it * (to_free->slots[0]), it will be safe to dereference the new * one (root->rnode). */ newptr = to_free->slots[0]; if (root->height > 1) newptr = radix_tree_ptr_to_indirect(newptr); root->rnode = newptr; root->height--; radix_tree_node_free(to_free); }}/** * radix_tree_delete - delete an item from a radix tree * @root: radix tree root * @index: index key * * Remove the item at @index from the radix tree rooted at @root. * * Returns the address of the deleted item, or NULL if it was not present. */void *radix_tree_delete(struct radix_tree_root *root, unsigned long index){ /* * 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; struct radix_tree_node *to_free; unsigned int height, shift; int tag; int offset; height = root->height; if (index > radix_tree_maxindex(height)) goto out; slot = root->rnode; if (height == 0) { root_tag_clear_all(root); root->rnode = NULL; goto out; } slot = radix_tree_indirect_to_ptr(slot); shift = (height - 1) * RADIX_TREE_MAP_SHIFT; pathp->node = NULL; do { if (slot == NULL) goto out; pathp++; offset = (index >> shift) & RADIX_TREE_MAP_MASK; pathp->offset = offset; pathp->node = slot; slot = slot->slots[offset]; shift -= RADIX_TREE_MAP_SHIFT; height--; } while (height > 0); if (slot == NULL) goto out; /* * Clear all tags associated with the just-deleted item */ for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) { if (tag_get(pathp->node, tag, pathp->offset)) radix_tree_tag_clear(root, index, tag); } to_free = NULL; /* Now free the nodes we do not need anymore */ while (pathp->node) { pathp->node->slots[pathp->offset] = NULL; pathp->node->count--; /* * Queue the node for deferred freeing after the * last reference to it disappears (set NULL, above). */ if (to_free) radix_tree_node_free(to_free); if (pathp->node->count) { if (pathp->node == radix_tree_indirect_to_ptr(root->rnode)) radix_tree_shrink(root); goto out; } /* Node with zero slots in use so free it */ to_free = pathp->node; pathp--; } root_tag_clear_all(root); root->height = 0; root->rnode = NULL; if (to_free) radix_tree_node_free(to_free);out: return slot;}EXPORT_SYMBOL(radix_tree_delete);/** * radix_tree_tagged - test whether any items in the tree are tagged * @root: radix tree root * @tag: tag to test */int radix_tree_tagged(struct radix_tree_root *root, unsigned int tag){ return root_tag_get(root, tag);}EXPORT_SYMBOL(radix_tree_tagged);static voidradix_tree_node_ctor(void *node){ memset(node, 0, sizeof(struct radix_tree_node));}static __init unsigned long __maxindex(unsigned int height){ unsigned int width = height * RADIX_TREE_MAP_SHIFT; int shift = RADIX_TREE_INDEX_BITS - width; if (shift < 0) return ~0UL; if (shift >= BITS_PER_LONG) return 0UL; return ~0UL >> shift;}static __init void radix_tree_init_maxindex(void){ unsigned int i; for (i = 0; i < ARRAY_SIZE(height_to_maxindex); i++) height_to_maxindex[i] = __maxindex(i);}static int radix_tree_callback(struct notifier_block *nfb, unsigned long action, void *hcpu){ int cpu = (long)hcpu; struct radix_tree_preload *rtp; /* Free per-cpu pool of perloaded nodes */ if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) { rtp = &per_cpu(radix_tree_preloads, cpu); while (rtp->nr) { kmem_cache_free(radix_tree_node_cachep, rtp->nodes[rtp->nr-1]); rtp->nodes[rtp->nr-1] = NULL; rtp->nr--; } } return NOTIFY_OK;}void __init radix_tree_init(void){ radix_tree_node_cachep = kmem_cache_create("radix_tree_node", sizeof(struct radix_tree_node), 0, SLAB_PANIC | SLAB_RECLAIM_ACCOUNT, radix_tree_node_ctor); radix_tree_init_maxindex(); hotcpu_notifier(radix_tree_callback, 0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -