mm: offset align in alloc_bootmem()
need offset alignment when node_boot_start's alignment is less than the alignment required. use local node_boot_start to match alignment - so don't add extra operation in search loop. Signed-off-by: Yinghai Lu <yhlu.kernel@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
parent
ad09315cad
commit
9a2dc04cf0
1 changed files with 34 additions and 26 deletions
60
mm/bootmem.c
60
mm/bootmem.c
|
@ -206,9 +206,11 @@ void * __init
|
||||||
__alloc_bootmem_core(struct bootmem_data *bdata, unsigned long size,
|
__alloc_bootmem_core(struct bootmem_data *bdata, unsigned long size,
|
||||||
unsigned long align, unsigned long goal, unsigned long limit)
|
unsigned long align, unsigned long goal, unsigned long limit)
|
||||||
{
|
{
|
||||||
unsigned long offset, remaining_size, areasize, preferred;
|
unsigned long areasize, preferred;
|
||||||
unsigned long i, start = 0, incr, eidx, end_pfn;
|
unsigned long i, start = 0, incr, eidx, end_pfn;
|
||||||
void *ret;
|
void *ret;
|
||||||
|
unsigned long node_boot_start;
|
||||||
|
void *node_bootmem_map;
|
||||||
|
|
||||||
if (!size) {
|
if (!size) {
|
||||||
printk("__alloc_bootmem_core(): zero-sized request\n");
|
printk("__alloc_bootmem_core(): zero-sized request\n");
|
||||||
|
@ -216,23 +218,29 @@ __alloc_bootmem_core(struct bootmem_data *bdata, unsigned long size,
|
||||||
}
|
}
|
||||||
BUG_ON(align & (align-1));
|
BUG_ON(align & (align-1));
|
||||||
|
|
||||||
if (limit && bdata->node_boot_start >= limit)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* on nodes without memory - bootmem_map is NULL */
|
/* on nodes without memory - bootmem_map is NULL */
|
||||||
if (!bdata->node_bootmem_map)
|
if (!bdata->node_bootmem_map)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
/* bdata->node_boot_start is supposed to be (12+6)bits alignment on x86_64 ? */
|
||||||
|
node_boot_start = bdata->node_boot_start;
|
||||||
|
node_bootmem_map = bdata->node_bootmem_map;
|
||||||
|
if (align) {
|
||||||
|
node_boot_start = ALIGN(bdata->node_boot_start, align);
|
||||||
|
if (node_boot_start > bdata->node_boot_start)
|
||||||
|
node_bootmem_map = (unsigned long *)bdata->node_bootmem_map +
|
||||||
|
PFN_DOWN(node_boot_start - bdata->node_boot_start)/BITS_PER_LONG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (limit && node_boot_start >= limit)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
end_pfn = bdata->node_low_pfn;
|
end_pfn = bdata->node_low_pfn;
|
||||||
limit = PFN_DOWN(limit);
|
limit = PFN_DOWN(limit);
|
||||||
if (limit && end_pfn > limit)
|
if (limit && end_pfn > limit)
|
||||||
end_pfn = limit;
|
end_pfn = limit;
|
||||||
|
|
||||||
eidx = end_pfn - PFN_DOWN(bdata->node_boot_start);
|
eidx = end_pfn - PFN_DOWN(node_boot_start);
|
||||||
offset = 0;
|
|
||||||
if (align && (bdata->node_boot_start & (align - 1UL)) != 0)
|
|
||||||
offset = align - (bdata->node_boot_start & (align - 1UL));
|
|
||||||
offset = PFN_DOWN(offset);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We try to allocate bootmem pages above 'goal'
|
* We try to allocate bootmem pages above 'goal'
|
||||||
|
@ -240,15 +248,16 @@ __alloc_bootmem_core(struct bootmem_data *bdata, unsigned long size,
|
||||||
*/
|
*/
|
||||||
preferred = 0;
|
preferred = 0;
|
||||||
if (goal && PFN_DOWN(goal) < end_pfn) {
|
if (goal && PFN_DOWN(goal) < end_pfn) {
|
||||||
if (goal > bdata->node_boot_start)
|
if (goal > node_boot_start)
|
||||||
preferred = goal - bdata->node_boot_start;
|
preferred = goal - node_boot_start;
|
||||||
|
|
||||||
if (bdata->last_success >= preferred)
|
if (bdata->last_success > node_boot_start &&
|
||||||
|
bdata->last_success - node_boot_start >= preferred)
|
||||||
if (!limit || (limit && limit > bdata->last_success))
|
if (!limit || (limit && limit > bdata->last_success))
|
||||||
preferred = bdata->last_success;
|
preferred = bdata->last_success - node_boot_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
preferred = PFN_DOWN(ALIGN(preferred, align)) + offset;
|
preferred = PFN_DOWN(ALIGN(preferred, align));
|
||||||
areasize = (size + PAGE_SIZE-1) / PAGE_SIZE;
|
areasize = (size + PAGE_SIZE-1) / PAGE_SIZE;
|
||||||
incr = align >> PAGE_SHIFT ? : 1;
|
incr = align >> PAGE_SHIFT ? : 1;
|
||||||
|
|
||||||
|
@ -256,18 +265,18 @@ __alloc_bootmem_core(struct bootmem_data *bdata, unsigned long size,
|
||||||
for (i = preferred; i < eidx;) {
|
for (i = preferred; i < eidx;) {
|
||||||
unsigned long j;
|
unsigned long j;
|
||||||
|
|
||||||
i = find_next_zero_bit(bdata->node_bootmem_map, eidx, i);
|
i = find_next_zero_bit(node_bootmem_map, eidx, i);
|
||||||
i = ALIGN(i, incr);
|
i = ALIGN(i, incr);
|
||||||
if (i >= eidx)
|
if (i >= eidx)
|
||||||
break;
|
break;
|
||||||
if (test_bit(i, bdata->node_bootmem_map)) {
|
if (test_bit(i, node_bootmem_map)) {
|
||||||
i += incr;
|
i += incr;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (j = i + 1; j < i + areasize; ++j) {
|
for (j = i + 1; j < i + areasize; ++j) {
|
||||||
if (j >= eidx)
|
if (j >= eidx)
|
||||||
goto fail_block;
|
goto fail_block;
|
||||||
if (test_bit(j, bdata->node_bootmem_map))
|
if (test_bit(j, node_bootmem_map))
|
||||||
goto fail_block;
|
goto fail_block;
|
||||||
}
|
}
|
||||||
start = i;
|
start = i;
|
||||||
|
@ -278,14 +287,14 @@ __alloc_bootmem_core(struct bootmem_data *bdata, unsigned long size,
|
||||||
i += incr;
|
i += incr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (preferred > offset) {
|
if (preferred > 0) {
|
||||||
preferred = offset;
|
preferred = 0;
|
||||||
goto restart_scan;
|
goto restart_scan;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
found:
|
found:
|
||||||
bdata->last_success = PFN_PHYS(start);
|
bdata->last_success = PFN_PHYS(start) + node_boot_start;
|
||||||
BUG_ON(start >= eidx);
|
BUG_ON(start >= eidx);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -295,6 +304,7 @@ __alloc_bootmem_core(struct bootmem_data *bdata, unsigned long size,
|
||||||
*/
|
*/
|
||||||
if (align < PAGE_SIZE &&
|
if (align < PAGE_SIZE &&
|
||||||
bdata->last_offset && bdata->last_pos+1 == start) {
|
bdata->last_offset && bdata->last_pos+1 == start) {
|
||||||
|
unsigned long offset, remaining_size;
|
||||||
offset = ALIGN(bdata->last_offset, align);
|
offset = ALIGN(bdata->last_offset, align);
|
||||||
BUG_ON(offset > PAGE_SIZE);
|
BUG_ON(offset > PAGE_SIZE);
|
||||||
remaining_size = PAGE_SIZE - offset;
|
remaining_size = PAGE_SIZE - offset;
|
||||||
|
@ -303,14 +313,12 @@ __alloc_bootmem_core(struct bootmem_data *bdata, unsigned long size,
|
||||||
/* last_pos unchanged */
|
/* last_pos unchanged */
|
||||||
bdata->last_offset = offset + size;
|
bdata->last_offset = offset + size;
|
||||||
ret = phys_to_virt(bdata->last_pos * PAGE_SIZE +
|
ret = phys_to_virt(bdata->last_pos * PAGE_SIZE +
|
||||||
offset +
|
offset + node_boot_start);
|
||||||
bdata->node_boot_start);
|
|
||||||
} else {
|
} else {
|
||||||
remaining_size = size - remaining_size;
|
remaining_size = size - remaining_size;
|
||||||
areasize = (remaining_size + PAGE_SIZE-1) / PAGE_SIZE;
|
areasize = (remaining_size + PAGE_SIZE-1) / PAGE_SIZE;
|
||||||
ret = phys_to_virt(bdata->last_pos * PAGE_SIZE +
|
ret = phys_to_virt(bdata->last_pos * PAGE_SIZE +
|
||||||
offset +
|
offset + node_boot_start);
|
||||||
bdata->node_boot_start);
|
|
||||||
bdata->last_pos = start + areasize - 1;
|
bdata->last_pos = start + areasize - 1;
|
||||||
bdata->last_offset = remaining_size;
|
bdata->last_offset = remaining_size;
|
||||||
}
|
}
|
||||||
|
@ -318,14 +326,14 @@ __alloc_bootmem_core(struct bootmem_data *bdata, unsigned long size,
|
||||||
} else {
|
} else {
|
||||||
bdata->last_pos = start + areasize - 1;
|
bdata->last_pos = start + areasize - 1;
|
||||||
bdata->last_offset = size & ~PAGE_MASK;
|
bdata->last_offset = size & ~PAGE_MASK;
|
||||||
ret = phys_to_virt(start * PAGE_SIZE + bdata->node_boot_start);
|
ret = phys_to_virt(start * PAGE_SIZE + node_boot_start);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reserve the area now:
|
* Reserve the area now:
|
||||||
*/
|
*/
|
||||||
for (i = start; i < start + areasize; i++)
|
for (i = start; i < start + areasize; i++)
|
||||||
if (unlikely(test_and_set_bit(i, bdata->node_bootmem_map)))
|
if (unlikely(test_and_set_bit(i, node_bootmem_map)))
|
||||||
BUG();
|
BUG();
|
||||||
memset(ret, 0, size);
|
memset(ret, 0, size);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
Loading…
Reference in a new issue