linux启动内存分配器2。。。。。。
linux启动内存分配器2。。。。。。介绍了上面的初始化流程,对于分配和释放就简单了,分配就是将分配器映射位图中对应的位置1,释放过程相反。
view plaincopy to clipboard01./*分配size大小的空间*/
02.static void * __init alloc_bootmem_core(struct bootmem_data *bdata,
03. unsigned long size, unsigned long align,
04. unsigned long goal, unsigned long limit)
05.{
06. unsigned long fallback = 0;
07. unsigned long min, max, start, sidx, midx, step;
08.
09. bdebug("nid=%td size=%lx [%lu pages] align=%lx goal=%lx limit=%lx\n",
10. bdata - bootmem_node_data, size, PAGE_ALIGN(size) >> PAGE_SHIFT,
11. align, goal, limit);
12.
13. BUG_ON(!size);
14. BUG_ON(align & (align - 1));
15. BUG_ON(limit && goal + size > limit);
16. /*如果没有映射位图返回空,分配失败*/
17. if (!bdata->node_bootmem_map)
18. return NULL;
19.
20. min = bdata->node_min_pfn;
21. max = bdata->node_low_pfn;
22.
23. goal >>= PAGE_SHIFT;
24. limit >>= PAGE_SHIFT;
25.
26. if (limit && max > limit)
27. max = limit;
28. if (max <= min)
29. return NULL;
30. /*step为需要对齐于页面数*/
31. step = max(align >> PAGE_SHIFT, 1UL);
32. /*计算起始页面*/
33. if (goal && min < goal && goal < max)
34. start = ALIGN(goal, step);
35. else
36. start = ALIGN(min, step);
37. /*计算分配页面区间*/
38. sidx = start - bdata->node_min_pfn;
39. midx = max - bdata->node_min_pfn;
40. /*前一次分配的页号比这次开始分配的页面号大
41. 那么,如果第一次没有分配到,回退到这次的
42. 开始重新试,因为第一次分配是从上一次分配
43. 的位置开始的*/
44. if (bdata->hint_idx > sidx) {
45. * Handle the valid case of sidx being zero and still
46. * catch the fallback below.
47. */
48. fallback = sidx + 1;
49. /*从上一次分配的位置开始,对齐与页面*/
50. sidx = align_idx(bdata, bdata->hint_idx, step);
51. }
52.
53. while (1) {
54. int merge;
55. void *region;
56. unsigned long eidx, i, start_off, end_off;
57.find_block:
58. /*查找第一个为0的位*/
59. sidx = find_next_zero_bit(bdata->node_bootmem_map, midx, sidx);
60. sidx = align_idx(bdata, sidx, step);
61. eidx = sidx + PFN_UP(size);/*结束位置*/
62.
63. if (sidx >= midx || eidx > midx)/*找到结束了*/
64. break;
65.
66. for (i = sidx; i < eidx; i++)/*检查这段区域是否空闲*/
67. if (test_bit(i, bdata->node_bootmem_map)) {/*如果不是,将跳过这段继续查找*/
68. sidx = align_idx(bdata, i, step);
69. if (sidx == i)
70. sidx += step;
71. goto find_block;
72. }
73.
74. if (bdata->last_end_off & (PAGE_SIZE - 1) &&/*如果为相邻的页面,也就是说上次分配的页面和这次分配的开始页面为相邻的*/
75. PFN_DOWN(bdata->last_end_off) + 1 == sidx)
76. start_off = align_off(bdata, bdata->last_end_off, align);
77. else
78. start_off = PFN_PHYS(sidx);
79.
80. /*merge==1表示上次结束和这次开始不在同一个页面上*/
81. merge = PFN_DOWN(start_off) < sidx;
82. end_off = start_off + size;
83. /*更新数据*/
84. bdata->last_end_off = end_off;
85. bdata->hint_idx = PFN_UP(end_off);
86.
87. /*
88. * Reserve the area now:
89. */
90. /*设定新加入的页面为保留,就是将对应的映射位置1*/
91. if (__reserve(bdata, PFN_DOWN(start_off) + merge,
92. PFN_UP(end_off), BOOTMEM_EXCLUSIVE))
93. BUG();
94. /*对应开始地址的虚拟地址返回*/
95. region = phys_to_virt(PFN_PHYS(bdata->node_min_pfn) +
96. start_off);
97. memset(region, 0, size);/*分配的大小*/
98. /*
99. * The min_count is set to 0 so that bootmem allocated blocks
100. * are never reported as leaks.
101. */
102. /*调试用*/
103. kmemleak_alloc(region, size, 0, 0);
104. return region;
105. }
106.
107. if (fallback) {/*回退,重新查看*/
108. sidx = align_idx(bdata, fallback - 1, step);
109. fallback = 0;
110. goto find_block;
111. }
112.
113. return NULL;
114.} 谢谢分享
页:
[1]