mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-09-22 04:32:41 +00:00
mm: allow reserve_bootmem() cross nodes
split reserve_bootmem_core() into two functions, one which checks conflicts, and one which sets the bits. and make reserve_bootmem to loop bdata_list to cross the nodes. user could be crashkernel and ramdisk..., in case the range provided by those externalities crosses the nodes. Signed-off-by: Yinghai Lu <yhlu.kernel@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
parent
9a2dc04cf0
commit
a5645a61b3
1 changed files with 70 additions and 24 deletions
94
mm/bootmem.c
94
mm/bootmem.c
|
@ -111,44 +111,74 @@ static unsigned long __init init_bootmem_core(pg_data_t *pgdat,
|
||||||
* might be used for boot-time allocations - or it might get added
|
* might be used for boot-time allocations - or it might get added
|
||||||
* to the free page pool later on.
|
* to the free page pool later on.
|
||||||
*/
|
*/
|
||||||
static int __init reserve_bootmem_core(bootmem_data_t *bdata,
|
static int __init can_reserve_bootmem_core(bootmem_data_t *bdata,
|
||||||
unsigned long addr, unsigned long size, int flags)
|
unsigned long addr, unsigned long size, int flags)
|
||||||
{
|
{
|
||||||
unsigned long sidx, eidx;
|
unsigned long sidx, eidx;
|
||||||
unsigned long i;
|
unsigned long i;
|
||||||
int ret;
|
|
||||||
|
BUG_ON(!size);
|
||||||
|
|
||||||
|
/* out of range, don't hold other */
|
||||||
|
if (addr + size < bdata->node_boot_start ||
|
||||||
|
PFN_DOWN(addr) > bdata->node_low_pfn)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* round up, partially reserved pages are considered
|
* Round up to index to the range.
|
||||||
* fully reserved.
|
|
||||||
*/
|
*/
|
||||||
BUG_ON(!size);
|
if (addr > bdata->node_boot_start)
|
||||||
BUG_ON(PFN_DOWN(addr) >= bdata->node_low_pfn);
|
sidx= PFN_DOWN(addr - bdata->node_boot_start);
|
||||||
BUG_ON(PFN_UP(addr + size) > bdata->node_low_pfn);
|
else
|
||||||
BUG_ON(addr < bdata->node_boot_start);
|
sidx = 0;
|
||||||
|
|
||||||
sidx = PFN_DOWN(addr - bdata->node_boot_start);
|
|
||||||
eidx = PFN_UP(addr + size - bdata->node_boot_start);
|
eidx = PFN_UP(addr + size - bdata->node_boot_start);
|
||||||
|
if (eidx > bdata->node_low_pfn - PFN_DOWN(bdata->node_boot_start))
|
||||||
|
eidx = bdata->node_low_pfn - PFN_DOWN(bdata->node_boot_start);
|
||||||
|
|
||||||
for (i = sidx; i < eidx; i++)
|
for (i = sidx; i < eidx; i++) {
|
||||||
|
if (test_bit(i, bdata->node_bootmem_map)) {
|
||||||
|
if (flags & BOOTMEM_EXCLUSIVE)
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __init reserve_bootmem_core(bootmem_data_t *bdata,
|
||||||
|
unsigned long addr, unsigned long size, int flags)
|
||||||
|
{
|
||||||
|
unsigned long sidx, eidx;
|
||||||
|
unsigned long i;
|
||||||
|
|
||||||
|
BUG_ON(!size);
|
||||||
|
|
||||||
|
/* out of range */
|
||||||
|
if (addr + size < bdata->node_boot_start ||
|
||||||
|
PFN_DOWN(addr) > bdata->node_low_pfn)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Round up to index to the range.
|
||||||
|
*/
|
||||||
|
if (addr > bdata->node_boot_start)
|
||||||
|
sidx= PFN_DOWN(addr - bdata->node_boot_start);
|
||||||
|
else
|
||||||
|
sidx = 0;
|
||||||
|
|
||||||
|
eidx = PFN_UP(addr + size - bdata->node_boot_start);
|
||||||
|
if (eidx > bdata->node_low_pfn - PFN_DOWN(bdata->node_boot_start))
|
||||||
|
eidx = bdata->node_low_pfn - PFN_DOWN(bdata->node_boot_start);
|
||||||
|
|
||||||
|
for (i = sidx; i < eidx; i++) {
|
||||||
if (test_and_set_bit(i, bdata->node_bootmem_map)) {
|
if (test_and_set_bit(i, bdata->node_bootmem_map)) {
|
||||||
#ifdef CONFIG_DEBUG_BOOTMEM
|
#ifdef CONFIG_DEBUG_BOOTMEM
|
||||||
printk("hm, page %08lx reserved twice.\n", i*PAGE_SIZE);
|
printk("hm, page %08lx reserved twice.\n", i*PAGE_SIZE);
|
||||||
#endif
|
#endif
|
||||||
if (flags & BOOTMEM_EXCLUSIVE) {
|
|
||||||
ret = -EBUSY;
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return 0;
|
|
||||||
|
|
||||||
err:
|
|
||||||
/* unreserve memory we accidentally reserved */
|
|
||||||
for (i--; i >= sidx; i--)
|
|
||||||
clear_bit(i, bdata->node_bootmem_map);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __init free_bootmem_core(bootmem_data_t *bdata, unsigned long addr,
|
static void __init free_bootmem_core(bootmem_data_t *bdata, unsigned long addr,
|
||||||
|
@ -415,6 +445,11 @@ unsigned long __init init_bootmem_node(pg_data_t *pgdat, unsigned long freepfn,
|
||||||
void __init reserve_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
|
void __init reserve_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
|
||||||
unsigned long size, int flags)
|
unsigned long size, int flags)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = can_reserve_bootmem_core(pgdat->bdata, physaddr, size, flags);
|
||||||
|
if (ret < 0)
|
||||||
|
return;
|
||||||
reserve_bootmem_core(pgdat->bdata, physaddr, size, flags);
|
reserve_bootmem_core(pgdat->bdata, physaddr, size, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -440,7 +475,18 @@ unsigned long __init init_bootmem(unsigned long start, unsigned long pages)
|
||||||
int __init reserve_bootmem(unsigned long addr, unsigned long size,
|
int __init reserve_bootmem(unsigned long addr, unsigned long size,
|
||||||
int flags)
|
int flags)
|
||||||
{
|
{
|
||||||
return reserve_bootmem_core(NODE_DATA(0)->bdata, addr, size, flags);
|
bootmem_data_t *bdata;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
list_for_each_entry(bdata, &bdata_list, list) {
|
||||||
|
ret = can_reserve_bootmem_core(bdata, addr, size, flags);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
list_for_each_entry(bdata, &bdata_list, list)
|
||||||
|
reserve_bootmem_core(bdata, addr, size, flags);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
#endif /* !CONFIG_HAVE_ARCH_BOOTMEM_NODE */
|
#endif /* !CONFIG_HAVE_ARCH_BOOTMEM_NODE */
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue