diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/page_alloc.c | 60 |
1 files changed, 59 insertions, 1 deletions
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 26c9939857fa..8d9a1eb9fbba 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -104,6 +104,7 @@ int min_free_kbytes = 1024; | |||
104 | 104 | ||
105 | unsigned long __meminitdata nr_kernel_pages; | 105 | unsigned long __meminitdata nr_kernel_pages; |
106 | unsigned long __meminitdata nr_all_pages; | 106 | unsigned long __meminitdata nr_all_pages; |
107 | static unsigned long __initdata dma_reserve; | ||
107 | 108 | ||
108 | #ifdef CONFIG_ARCH_POPULATES_NODE_MAP | 109 | #ifdef CONFIG_ARCH_POPULATES_NODE_MAP |
109 | /* | 110 | /* |
@@ -2213,6 +2214,20 @@ unsigned long __init zone_absent_pages_in_node(int nid, | |||
2213 | arch_zone_lowest_possible_pfn[zone_type], | 2214 | arch_zone_lowest_possible_pfn[zone_type], |
2214 | arch_zone_highest_possible_pfn[zone_type]); | 2215 | arch_zone_highest_possible_pfn[zone_type]); |
2215 | } | 2216 | } |
2217 | |||
2218 | /* Return the zone index a PFN is in */ | ||
2219 | int memmap_zone_idx(struct page *lmem_map) | ||
2220 | { | ||
2221 | int i; | ||
2222 | unsigned long phys_addr = virt_to_phys(lmem_map); | ||
2223 | unsigned long pfn = phys_addr >> PAGE_SHIFT; | ||
2224 | |||
2225 | for (i = 0; i < MAX_NR_ZONES; i++) | ||
2226 | if (pfn < arch_zone_highest_possible_pfn[i]) | ||
2227 | break; | ||
2228 | |||
2229 | return i; | ||
2230 | } | ||
2216 | #else | 2231 | #else |
2217 | static inline unsigned long zone_spanned_pages_in_node(int nid, | 2232 | static inline unsigned long zone_spanned_pages_in_node(int nid, |
2218 | unsigned long zone_type, | 2233 | unsigned long zone_type, |
@@ -2230,6 +2245,11 @@ static inline unsigned long zone_absent_pages_in_node(int nid, | |||
2230 | 2245 | ||
2231 | return zholes_size[zone_type]; | 2246 | return zholes_size[zone_type]; |
2232 | } | 2247 | } |
2248 | |||
2249 | static inline int memmap_zone_idx(struct page *lmem_map) | ||
2250 | { | ||
2251 | return MAX_NR_ZONES; | ||
2252 | } | ||
2233 | #endif | 2253 | #endif |
2234 | 2254 | ||
2235 | static void __init calculate_node_totalpages(struct pglist_data *pgdat, | 2255 | static void __init calculate_node_totalpages(struct pglist_data *pgdat, |
@@ -2274,12 +2294,35 @@ static void __meminit free_area_init_core(struct pglist_data *pgdat, | |||
2274 | 2294 | ||
2275 | for (j = 0; j < MAX_NR_ZONES; j++) { | 2295 | for (j = 0; j < MAX_NR_ZONES; j++) { |
2276 | struct zone *zone = pgdat->node_zones + j; | 2296 | struct zone *zone = pgdat->node_zones + j; |
2277 | unsigned long size, realsize; | 2297 | unsigned long size, realsize, memmap_pages; |
2278 | 2298 | ||
2279 | size = zone_spanned_pages_in_node(nid, j, zones_size); | 2299 | size = zone_spanned_pages_in_node(nid, j, zones_size); |
2280 | realsize = size - zone_absent_pages_in_node(nid, j, | 2300 | realsize = size - zone_absent_pages_in_node(nid, j, |
2281 | zholes_size); | 2301 | zholes_size); |
2282 | 2302 | ||
2303 | /* | ||
2304 | * Adjust realsize so that it accounts for how much memory | ||
2305 | * is used by this zone for memmap. This affects the watermark | ||
2306 | * and per-cpu initialisations | ||
2307 | */ | ||
2308 | memmap_pages = (size * sizeof(struct page)) >> PAGE_SHIFT; | ||
2309 | if (realsize >= memmap_pages) { | ||
2310 | realsize -= memmap_pages; | ||
2311 | printk(KERN_DEBUG | ||
2312 | " %s zone: %lu pages used for memmap\n", | ||
2313 | zone_names[j], memmap_pages); | ||
2314 | } else | ||
2315 | printk(KERN_WARNING | ||
2316 | " %s zone: %lu pages exceeds realsize %lu\n", | ||
2317 | zone_names[j], memmap_pages, realsize); | ||
2318 | |||
2319 | /* Account for reserved DMA pages */ | ||
2320 | if (j == ZONE_DMA && realsize > dma_reserve) { | ||
2321 | realsize -= dma_reserve; | ||
2322 | printk(KERN_DEBUG " DMA zone: %lu pages reserved\n", | ||
2323 | dma_reserve); | ||
2324 | } | ||
2325 | |||
2283 | if (!is_highmem_idx(j)) | 2326 | if (!is_highmem_idx(j)) |
2284 | nr_kernel_pages += realsize; | 2327 | nr_kernel_pages += realsize; |
2285 | nr_all_pages += realsize; | 2328 | nr_all_pages += realsize; |
@@ -2596,6 +2639,21 @@ void __init free_area_init_nodes(unsigned long *max_zone_pfn) | |||
2596 | } | 2639 | } |
2597 | #endif /* CONFIG_ARCH_POPULATES_NODE_MAP */ | 2640 | #endif /* CONFIG_ARCH_POPULATES_NODE_MAP */ |
2598 | 2641 | ||
2642 | /** | ||
2643 | * set_dma_reserve - Account the specified number of pages reserved in ZONE_DMA | ||
2644 | * @new_dma_reserve - The number of pages to mark reserved | ||
2645 | * | ||
2646 | * The per-cpu batchsize and zone watermarks are determined by present_pages. | ||
2647 | * In the DMA zone, a significant percentage may be consumed by kernel image | ||
2648 | * and other unfreeable allocations which can skew the watermarks badly. This | ||
2649 | * function may optionally be used to account for unfreeable pages in | ||
2650 | * ZONE_DMA. The effect will be lower watermarks and smaller per-cpu batchsize | ||
2651 | */ | ||
2652 | void __init set_dma_reserve(unsigned long new_dma_reserve) | ||
2653 | { | ||
2654 | dma_reserve = new_dma_reserve; | ||
2655 | } | ||
2656 | |||
2599 | #ifndef CONFIG_NEED_MULTIPLE_NODES | 2657 | #ifndef CONFIG_NEED_MULTIPLE_NODES |
2600 | static bootmem_data_t contig_bootmem_data; | 2658 | static bootmem_data_t contig_bootmem_data; |
2601 | struct pglist_data contig_page_data = { .bdata = &contig_bootmem_data }; | 2659 | struct pglist_data contig_page_data = { .bdata = &contig_bootmem_data }; |