linux 内存管理通过radix树跟踪绑定到地址映射上的核心页,
该radix树允许内存管理代码快速查找标识为dirty或writeback的页。Linux radix树的API函数在lib/radix-tree.c中实现。
一:主要的数据结构
struct radix_tree_root { unsigned int height;//树总高 gfp_t gfp_mask;//内存的分配方式 struct radix_tree_node __rcu *rnode; };
struct radix_tree_node { unsigned int height; /* Height from the bottom */ unsigned int count; struct rcu_head rcu_head; void __rcu *slots[RADIX_TREE_MAP_SIZE];//存放指针的数组 unsigned long tags[RADIX_TREE_MAX_TAGS][RADIX_TREE_TAG_LONGS]; };
二:初始化
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); }
kmem_cache_create 从slab分配数据结构,主要看 radix_tree_init_maxindex函数
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)//16 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); }分析函数得:
height_to_maxindex[0] = 0 height_to_maxindex[1] = 16 height_to_maxindex[2] = 256 ......二:初始化结构体图
四,主要的函数操作
插入函数
nt radix_tree_insert(struct radix_tree_root *root, unsigned long index, void *item) { if (index > radix_tree_maxindex(root->height)) {//发现需要插入的index大于目前树的叶子个数 error = radix_tree_extend(root, index);//扩展树 if (error) return error; } 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 (!(slot = radix_tree_node_alloc(root))) return -ENOMEM; slot->height = height; if (node) { rcu_assign_pointer(node->slots[offset], slot); node->count++; } else rcu_assign_pointer(root->rnode, ptr_to_indirect(slot)); } /* Go a level down */ offset = (index >> shift) & RADIX_TREE_MAP_MASK; node = slot; slot = node->slots[offset]; shift -= RADIX_TREE_MAP_SHIFT; height--; } return 0; }
static int radix_tree_extend(struct radix_tree_root *root, unsigned long index) {.... do { unsigned int newheight; if (!(node = radix_tree_node_alloc(root))) return -ENOMEM; /* Increase the height. */ node->slots[0] = indirect_to_ptr(root->rnode); /* Propagate the aggregated tag info into the new root */ for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) { if (root_tag_get(root, tag)) tag_set(node, tag, 0); } newheight = root->height+1; node->height = newheight; node->count = 1; node = ptr_to_indirect(node); rcu_assign_pointer(root->rnode, node); root->height = newheight; } while (height > root->height); }
扩展树后图列如下:
插入具体的index,与数据,假如index = 37,二进制位100101
即10,0101, 10=2,0101=5 即得到图下结果
查找函数
static void *radix_tree_lookup_element(struct radix_tree_root *root, unsigned long index, int is_slot) { .... do { slot = (struct radix_tree_node **) (node->slots + ((index>>shift) & RADIX_TREE_MAP_MASK)); node = rcu_dereference_raw(*slot); if (node == NULL) return NULL; shift -= RADIX_TREE_MAP_SHIFT; height--; } while (height > 0); return is_slot ? (void *)slot : indirect_to_ptr(node); }按照index,
(index>>shift 左移,来查找,找不到返回空,如果找到返回存储地址