⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 radix-tree.c

📁 Lib files of linux kernel
💻 C
📖 第 1 页 / 共 3 页
字号:
		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 + -