diff options
Diffstat (limited to 'mm/page_alloc.c')
| -rw-r--r-- | mm/page_alloc.c | 57 |
1 files changed, 42 insertions, 15 deletions
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 9f8a97b9a350..3f8bce264df6 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
| @@ -2317,6 +2317,21 @@ void free_pages(unsigned long addr, unsigned int order) | |||
| 2317 | 2317 | ||
| 2318 | EXPORT_SYMBOL(free_pages); | 2318 | EXPORT_SYMBOL(free_pages); |
| 2319 | 2319 | ||
| 2320 | static void *make_alloc_exact(unsigned long addr, unsigned order, size_t size) | ||
| 2321 | { | ||
| 2322 | if (addr) { | ||
| 2323 | unsigned long alloc_end = addr + (PAGE_SIZE << order); | ||
| 2324 | unsigned long used = addr + PAGE_ALIGN(size); | ||
| 2325 | |||
| 2326 | split_page(virt_to_page((void *)addr), order); | ||
| 2327 | while (used < alloc_end) { | ||
| 2328 | free_page(used); | ||
| 2329 | used += PAGE_SIZE; | ||
| 2330 | } | ||
| 2331 | } | ||
| 2332 | return (void *)addr; | ||
| 2333 | } | ||
| 2334 | |||
| 2320 | /** | 2335 | /** |
| 2321 | * alloc_pages_exact - allocate an exact number physically-contiguous pages. | 2336 | * alloc_pages_exact - allocate an exact number physically-contiguous pages. |
| 2322 | * @size: the number of bytes to allocate | 2337 | * @size: the number of bytes to allocate |
| @@ -2336,22 +2351,33 @@ void *alloc_pages_exact(size_t size, gfp_t gfp_mask) | |||
| 2336 | unsigned long addr; | 2351 | unsigned long addr; |
| 2337 | 2352 | ||
| 2338 | addr = __get_free_pages(gfp_mask, order); | 2353 | addr = __get_free_pages(gfp_mask, order); |
| 2339 | if (addr) { | 2354 | return make_alloc_exact(addr, order, size); |
| 2340 | unsigned long alloc_end = addr + (PAGE_SIZE << order); | ||
| 2341 | unsigned long used = addr + PAGE_ALIGN(size); | ||
| 2342 | |||
| 2343 | split_page(virt_to_page((void *)addr), order); | ||
| 2344 | while (used < alloc_end) { | ||
| 2345 | free_page(used); | ||
| 2346 | used += PAGE_SIZE; | ||
| 2347 | } | ||
| 2348 | } | ||
| 2349 | |||
| 2350 | return (void *)addr; | ||
| 2351 | } | 2355 | } |
| 2352 | EXPORT_SYMBOL(alloc_pages_exact); | 2356 | EXPORT_SYMBOL(alloc_pages_exact); |
| 2353 | 2357 | ||
| 2354 | /** | 2358 | /** |
| 2359 | * alloc_pages_exact_nid - allocate an exact number of physically-contiguous | ||
| 2360 | * pages on a node. | ||
| 2361 | * @nid: the preferred node ID where memory should be allocated | ||
| 2362 | * @size: the number of bytes to allocate | ||
| 2363 | * @gfp_mask: GFP flags for the allocation | ||
| 2364 | * | ||
| 2365 | * Like alloc_pages_exact(), but try to allocate on node nid first before falling | ||
| 2366 | * back. | ||
| 2367 | * Note this is not alloc_pages_exact_node() which allocates on a specific node, | ||
| 2368 | * but is not exact. | ||
| 2369 | */ | ||
| 2370 | void *alloc_pages_exact_nid(int nid, size_t size, gfp_t gfp_mask) | ||
| 2371 | { | ||
| 2372 | unsigned order = get_order(size); | ||
| 2373 | struct page *p = alloc_pages_node(nid, gfp_mask, order); | ||
| 2374 | if (!p) | ||
| 2375 | return NULL; | ||
| 2376 | return make_alloc_exact((unsigned long)page_address(p), order, size); | ||
| 2377 | } | ||
| 2378 | EXPORT_SYMBOL(alloc_pages_exact_nid); | ||
| 2379 | |||
| 2380 | /** | ||
| 2355 | * free_pages_exact - release memory allocated via alloc_pages_exact() | 2381 | * free_pages_exact - release memory allocated via alloc_pages_exact() |
| 2356 | * @virt: the value returned by alloc_pages_exact. | 2382 | * @virt: the value returned by alloc_pages_exact. |
| 2357 | * @size: size of allocation, same value as passed to alloc_pages_exact(). | 2383 | * @size: size of allocation, same value as passed to alloc_pages_exact(). |
| @@ -3564,7 +3590,7 @@ int zone_wait_table_init(struct zone *zone, unsigned long zone_size_pages) | |||
| 3564 | 3590 | ||
| 3565 | if (!slab_is_available()) { | 3591 | if (!slab_is_available()) { |
| 3566 | zone->wait_table = (wait_queue_head_t *) | 3592 | zone->wait_table = (wait_queue_head_t *) |
| 3567 | alloc_bootmem_node(pgdat, alloc_size); | 3593 | alloc_bootmem_node_nopanic(pgdat, alloc_size); |
| 3568 | } else { | 3594 | } else { |
| 3569 | /* | 3595 | /* |
| 3570 | * This case means that a zone whose size was 0 gets new memory | 3596 | * This case means that a zone whose size was 0 gets new memory |
| @@ -4141,7 +4167,8 @@ static void __init setup_usemap(struct pglist_data *pgdat, | |||
| 4141 | unsigned long usemapsize = usemap_size(zonesize); | 4167 | unsigned long usemapsize = usemap_size(zonesize); |
| 4142 | zone->pageblock_flags = NULL; | 4168 | zone->pageblock_flags = NULL; |
| 4143 | if (usemapsize) | 4169 | if (usemapsize) |
| 4144 | zone->pageblock_flags = alloc_bootmem_node(pgdat, usemapsize); | 4170 | zone->pageblock_flags = alloc_bootmem_node_nopanic(pgdat, |
| 4171 | usemapsize); | ||
| 4145 | } | 4172 | } |
| 4146 | #else | 4173 | #else |
| 4147 | static inline void setup_usemap(struct pglist_data *pgdat, | 4174 | static inline void setup_usemap(struct pglist_data *pgdat, |
| @@ -4307,7 +4334,7 @@ static void __init_refok alloc_node_mem_map(struct pglist_data *pgdat) | |||
| 4307 | size = (end - start) * sizeof(struct page); | 4334 | size = (end - start) * sizeof(struct page); |
| 4308 | map = alloc_remap(pgdat->node_id, size); | 4335 | map = alloc_remap(pgdat->node_id, size); |
| 4309 | if (!map) | 4336 | if (!map) |
| 4310 | map = alloc_bootmem_node(pgdat, size); | 4337 | map = alloc_bootmem_node_nopanic(pgdat, size); |
| 4311 | pgdat->node_mem_map = map + (pgdat->node_start_pfn - start); | 4338 | pgdat->node_mem_map = map + (pgdat->node_start_pfn - start); |
| 4312 | } | 4339 | } |
| 4313 | #ifndef CONFIG_NEED_MULTIPLE_NODES | 4340 | #ifndef CONFIG_NEED_MULTIPLE_NODES |
