X-Git-Url: http://pilppa.org/gitweb/?a=blobdiff_plain;f=mm%2Fbootmem.c;h=2ccea700968f7ecaaa265023e79e52d540a82871;hb=06b285dc3d6194abe79ab9dcaaab703d6f75627c;hp=d53112fcb4040a3a2ecf930e013eb9933bc6d34f;hpb=c226951b93f7cd7c3a10b17384535b617bd43fd0;p=linux-2.6-omap-h63xx.git diff --git a/mm/bootmem.c b/mm/bootmem.c index d53112fcb40..2ccea700968 100644 --- a/mm/bootmem.c +++ b/mm/bootmem.c @@ -27,8 +27,6 @@ unsigned long max_low_pfn; unsigned long min_low_pfn; unsigned long max_pfn; -EXPORT_UNUSED_SYMBOL(max_pfn); /* June 2006 */ - static LIST_HEAD(bdata_list); #ifdef CONFIG_CRASH_DUMP /* @@ -113,11 +111,12 @@ static unsigned long __init init_bootmem_core(pg_data_t *pgdat, * might be used for boot-time allocations - or it might get added * to the free page pool later on. */ -static void __init reserve_bootmem_core(bootmem_data_t *bdata, unsigned long addr, - unsigned long size) +static int __init reserve_bootmem_core(bootmem_data_t *bdata, + unsigned long addr, unsigned long size, int flags) { unsigned long sidx, eidx; unsigned long i; + int ret; /* * round up, partially reserved pages are considered @@ -126,6 +125,7 @@ static void __init reserve_bootmem_core(bootmem_data_t *bdata, unsigned long add BUG_ON(!size); BUG_ON(PFN_DOWN(addr) >= bdata->node_low_pfn); BUG_ON(PFN_UP(addr + size) > bdata->node_low_pfn); + BUG_ON(addr < bdata->node_boot_start); sidx = PFN_DOWN(addr - bdata->node_boot_start); eidx = PFN_UP(addr + size - bdata->node_boot_start); @@ -135,7 +135,20 @@ static void __init reserve_bootmem_core(bootmem_data_t *bdata, unsigned long add #ifdef CONFIG_DEBUG_BOOTMEM printk("hm, page %08lx reserved twice.\n", i*PAGE_SIZE); #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, @@ -144,21 +157,31 @@ static void __init free_bootmem_core(bootmem_data_t *bdata, unsigned long addr, unsigned long sidx, eidx; unsigned long i; + BUG_ON(!size); + + /* out range */ + if (addr + size < bdata->node_boot_start || + PFN_DOWN(addr) > bdata->node_low_pfn) + return; /* * round down end of usable mem, partially free pages are * considered reserved. */ - BUG_ON(!size); - BUG_ON(PFN_DOWN(addr + size) > bdata->node_low_pfn); - if (addr < bdata->last_success) + if (addr >= bdata->node_boot_start && addr < bdata->last_success) bdata->last_success = addr; /* - * Round up the beginning of the address. + * Round up to index to the range. */ - sidx = PFN_UP(addr) - PFN_DOWN(bdata->node_boot_start); + if (PFN_UP(addr) > PFN_DOWN(bdata->node_boot_start)) + sidx = PFN_UP(addr) - PFN_DOWN(bdata->node_boot_start); + else + sidx = 0; + eidx = PFN_DOWN(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 (unlikely(!test_and_clear_bit(i, bdata->node_bootmem_map))) @@ -196,6 +219,10 @@ __alloc_bootmem_core(struct bootmem_data *bdata, unsigned long size, if (limit && bdata->node_boot_start >= limit) return NULL; + /* on nodes without memory - bootmem_map is NULL */ + if (!bdata->node_bootmem_map) + return NULL; + end_pfn = bdata->node_low_pfn; limit = PFN_DOWN(limit); if (limit && end_pfn > limit) @@ -372,9 +399,9 @@ 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, - unsigned long size) + unsigned long size, int flags) { - reserve_bootmem_core(pgdat->bdata, physaddr, size); + reserve_bootmem_core(pgdat->bdata, physaddr, size, flags); } void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr, @@ -396,15 +423,18 @@ unsigned long __init init_bootmem(unsigned long start, unsigned long pages) } #ifndef CONFIG_HAVE_ARCH_BOOTMEM_NODE -void __init reserve_bootmem(unsigned long addr, unsigned long size) +int __init reserve_bootmem(unsigned long addr, unsigned long size, + int flags) { - reserve_bootmem_core(NODE_DATA(0)->bdata, addr, size); + return reserve_bootmem_core(NODE_DATA(0)->bdata, addr, size, flags); } #endif /* !CONFIG_HAVE_ARCH_BOOTMEM_NODE */ void __init free_bootmem(unsigned long addr, unsigned long size) { - free_bootmem_core(NODE_DATA(0)->bdata, addr, size); + bootmem_data_t *bdata; + list_for_each_entry(bdata, &bdata_list, list) + free_bootmem_core(bdata, addr, size); } unsigned long __init free_all_bootmem(void)