- 论坛徽章:
- 0
|
linux启动内存分配器2。。。。。。
介绍了上面的初始化流程,对于分配和释放就简单了,分配就是将分配器映射位图中对应的位置1,释放过程相反。
view plaincopy to clipboard- 01./*分配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.}
复制代码 |
|