Linux内核源码分析-基树处理- radix_tree
本文主要参考《深入理解Linux内核》,结合2.6.11版的内核代码,分析内核文件子系统中的radix_tree处理函数。
注意:
1、 不描述内核同步、错误处理、参数合法性验证相关的内容
2、 源码摘自Linux内核2.6.11 stable版,获取命令:
git clone
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git
cd ./linux-stable/
git checkout linux-2.6.11.y
3、 阅读本文请结合《深入理解Linux内核》第三版相关章节
4、 本文会不定时更新
函数调用结构
公共函数
1、radix_tree_init
源码:
在init/main.c:start_kernel函数中调用该函数
void __init radix_tree_init(void)
{
radix_tree_node_cachep = kmem_cache_create("radix_tree_node",
sizeof(struct radix_tree_node), 0,
SLAB_PANIC, radix_tree_node_ctor, NULL);
radix_tree_init_maxindex();
hotcpu_notifier(radix_tree_callback, 0);
}
处理流出:
1、 调用函数kmem_cache_create分配类型为radix_tree_node、名称为radix_tree_node的slab高速缓存,存入全局变量radix_tree_node_cachep中
2、 调用函数radix_tree_init_maxindex初始化书中各层的最大索引数组height_to_maxindex(1-6层)
3、 调用函数hotcpu_notifier,设置热插拔cpu时的回调函数
2、radix_tree_insert
源码:
/**
* radix_tree_insert - insert into a radix tree
* @root: radix tree root
* @index: index key
* @item: item to insert
*
* Insert an item into the radix tree at position @index.
*/
int radix_tree_insert(struct radix_tree_root *root,
unsigned long index, void *item)
{
struct radix_tree_node *node = NULL, *tmp, **slot;
unsigned int height, shift;
int offset;
int error;
/* Make sure the tree is high enough. */
if ((!index && !root->rnode) ||
index > radix_tree_maxindex(root->height)) {
error = radix_tree_extend(root, index);
if (error)
return error;
}
slot = &root->rnode;
height = root->height;
shift = (height-1) * RADIX_TREE_MAP_SHIFT; //当前层偏移需要移动的位数
offset = 0; /* uninitialised var warning */
while (height > 0) {
if (*slot == NULL) {
/* Have to add a child node. */
if (!(tmp = radix_tree_node_alloc(root)))
return -ENOMEM;
*slot = tmp;
if (node)
node->count++;
}
/* Go a level down */
offset = (index >> shift) & RADIX_TREE_MAP_MASK;
node = *slot;
slot = (struct radix_tree_node **)(node->slots + offset);
shift -= RADIX_TREE_MAP_SHIFT;
height--;
}
if (*slot != NULL)
return -EEXIST;
if (node) {
node->count++;
BUG_ON(tag_get(node, 0, offset));
BUG_ON(tag_get(node, 1, offset));
}
*slot = item;
return 0;
}
处理流程:
1、 调用函数radix_tree_extend扩展树的层数以满足index
2、 循环初始化各层的radix_tree_node对象
3、 初始化最终的页的指针
3、radix_tree_delete
源码:
/**
* 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)
{
struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path;
struct radix_tree_path *orig_pathp;
unsigned int height, shift;
void *ret = NULL;
char tags[RADIX_TREE_TAGS];
int nr_cleared_tags;
height = root->height;
if (index > radix_tree_maxindex(height))
goto out;
shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
pathp->node = NULL;
pathp->slot = &root->rnode;
while (height > 0) {
int offset;
if (*pathp->slot == NULL)
goto out;
offset = (index >> shift) & RADIX_TREE_MAP_MASK;
pathp[1].offset = offset;
pathp[1].node = *pathp[0].slot;
pathp[1].slot = (struct radix_tree_node **)
(pathp[1].node->slots + offset);
pathp++;
shift -= RADIX_TREE_MAP_SHIFT;
height--;
}
ret = *pathp[0].slot;
if (ret == NULL)
goto out;
orig_pathp = pathp;
/*
* Clear all tags associated with the just-deleted item
*/
memset(tags, 0, sizeof(tags));
do {
int tag;
nr_cleared_tags = RADIX_TREE_TAGS;
for (tag =