您的位置:首页 > 其它

内存管理之bootmem管理之对外分配函数

2017-03-06 10:09 316 查看
alloc_bootmem_bdata和alloc_bootmem_core

基于node和不需要node两个类别的函数

static void * __init alloc_bootmem_bdata(struct bootmem_data *bdata,
unsigned long size, unsigned long align,
unsigned long goal, unsigned long limit)
{
unsigned long fallback = 0;
unsigned long min, max, start, sidx, midx, step;

bdebug("nid=%td size=%lx [%lu pages] align=%lx goal=%lx limit=%lx\n",
bdata - bootmem_node_data, size, PAGE_ALIGN(size) >> PAGE_SHIFT,
align, goal, limit);

BUG_ON(!size);
BUG_ON(align & (align - 1));
BUG_ON(limit && goal + size > limit);

if (!bdata->node_bootmem_map)
return NULL;

min = bdata->node_min_pfn;
max = bdata->node_low_pfn;

goal >>= PAGE_SHIFT;
limit >>= PAGE_SHIFT;

if (limit && max > limit)
max = limit;
if (max <= min)
return NULL;

step = max(align >> PAGE_SHIFT, 1UL);

if (goal && min < goal && goal < max)
start = ALIGN(goal, step);
else
start = ALIGN(min, step);

sidx = start - bdata->node_min_pfn;
midx = max - bdata->node_min_pfn;

if (bdata->hint_idx > sidx) {
/*
* Handle the valid case of sidx being zero and still
* catch the fallback below.
*/
fallback = sidx + 1;
sidx = align_idx(bdata, bdata->hint_idx, step);
}

while (1) {
int merge;
void *region;
unsigned long eidx, i, start_off, end_off;
find_block:
sidx = find_next_zero_bit(bdata->node_bootmem_map, midx, sidx);
sidx = align_idx(bdata, sidx, step);
eidx = sidx + PFN_UP(size);

if (sidx >= midx || eidx > midx)
break;

for (i = sidx; i < eidx; i++)
if (test_bit(i, bdata->node_bootmem_map)) {
sidx = align_idx(bdata, i, step);
if (sidx == i)
sidx += step;
goto find_block;
}

if (bdata->last_end_off & (PAGE_SIZE - 1) &&
PFN_DOWN(bdata->last_end_off) + 1 == sidx)
start_off = align_off(bdata, bdata->last_end_off, align);
else
start_off = PFN_PHYS(sidx);

merge = PFN_DOWN(start_off) < sidx;
end_off = start_off + size;

bdata->last_end_off = end_off;
bdata->hint_idx = PFN_UP(end_off);

/*
* Reserve the area now:
*/
if (__reserve(bdata, PFN_DOWN(start_off) + merge,
PFN_UP(end_off), BOOTMEM_EXCLUSIVE))
BUG();

region = phys_to_virt(PFN_PHYS(bdata->node_min_pfn) +
start_off);
memset(region, 0, size);
/*
* The min_count is set to 0 so that bootmem allocated blocks
* are never reported as leaks.
*/
kmemleak_alloc(region, size, 0, 0);
return region;
}

if (fallback) {
sidx = align_idx(bdata, fallback - 1, step);
fallback = 0;
goto find_block;
}

return NULL;
}


static void * __init alloc_bootmem_core(unsigned long size,
unsigned long align,
unsigned long goal,
unsigned long limit)
{
bootmem_data_t *bdata;
void *region;

if (WARN_ON_ONCE(slab_is_available()))
return kzalloc(size, GFP_NOWAIT);

list_for_each_entry(bdata, &bdata_list, list) {
if (goal && bdata->node_low_pfn <= PFN_DOWN(goal))
continue;
if (limit && bdata->node_min_pfn >= PFN_DOWN(limit))
break;

region = alloc_bootmem_bdata(bdata, size, align, goal, limit);
if (region)
return region;
}

return NULL;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: