diff options
Diffstat (limited to 'mm/page_alloc.c')
-rw-r--r-- | mm/page_alloc.c | 26 |
1 files changed, 19 insertions, 7 deletions
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index b0647b515277..088712f2ac02 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -81,6 +81,7 @@ int min_free_kbytes = 1024; | |||
81 | unsigned long __initdata nr_kernel_pages; | 81 | unsigned long __initdata nr_kernel_pages; |
82 | unsigned long __initdata nr_all_pages; | 82 | unsigned long __initdata nr_all_pages; |
83 | 83 | ||
84 | #ifdef CONFIG_DEBUG_VM | ||
84 | static int page_outside_zone_boundaries(struct zone *zone, struct page *page) | 85 | static int page_outside_zone_boundaries(struct zone *zone, struct page *page) |
85 | { | 86 | { |
86 | int ret = 0; | 87 | int ret = 0; |
@@ -122,6 +123,13 @@ static int bad_range(struct zone *zone, struct page *page) | |||
122 | return 0; | 123 | return 0; |
123 | } | 124 | } |
124 | 125 | ||
126 | #else | ||
127 | static inline int bad_range(struct zone *zone, struct page *page) | ||
128 | { | ||
129 | return 0; | ||
130 | } | ||
131 | #endif | ||
132 | |||
125 | static void bad_page(const char *function, struct page *page) | 133 | static void bad_page(const char *function, struct page *page) |
126 | { | 134 | { |
127 | printk(KERN_EMERG "Bad page state at %s (in process '%s', page %p)\n", | 135 | printk(KERN_EMERG "Bad page state at %s (in process '%s', page %p)\n", |
@@ -255,14 +263,20 @@ __find_combined_index(unsigned long page_idx, unsigned int order) | |||
255 | /* | 263 | /* |
256 | * This function checks whether a page is free && is the buddy | 264 | * This function checks whether a page is free && is the buddy |
257 | * we can do coalesce a page and its buddy if | 265 | * we can do coalesce a page and its buddy if |
258 | * (a) the buddy is free && | 266 | * (a) the buddy is not in a hole && |
259 | * (b) the buddy is on the buddy system && | 267 | * (b) the buddy is free && |
260 | * (c) a page and its buddy have the same order. | 268 | * (c) the buddy is on the buddy system && |
269 | * (d) a page and its buddy have the same order. | ||
261 | * for recording page's order, we use page_private(page) and PG_private. | 270 | * for recording page's order, we use page_private(page) and PG_private. |
262 | * | 271 | * |
263 | */ | 272 | */ |
264 | static inline int page_is_buddy(struct page *page, int order) | 273 | static inline int page_is_buddy(struct page *page, int order) |
265 | { | 274 | { |
275 | #ifdef CONFIG_HOLES_IN_ZONE | ||
276 | if (!pfn_valid(page_to_pfn(page))) | ||
277 | return 0; | ||
278 | #endif | ||
279 | |||
266 | if (PagePrivate(page) && | 280 | if (PagePrivate(page) && |
267 | (page_order(page) == order) && | 281 | (page_order(page) == order) && |
268 | page_count(page) == 0) | 282 | page_count(page) == 0) |
@@ -314,17 +328,15 @@ static inline void __free_pages_bulk (struct page *page, | |||
314 | struct free_area *area; | 328 | struct free_area *area; |
315 | struct page *buddy; | 329 | struct page *buddy; |
316 | 330 | ||
317 | combined_idx = __find_combined_index(page_idx, order); | ||
318 | buddy = __page_find_buddy(page, page_idx, order); | 331 | buddy = __page_find_buddy(page, page_idx, order); |
319 | |||
320 | if (bad_range(zone, buddy)) | ||
321 | break; | ||
322 | if (!page_is_buddy(buddy, order)) | 332 | if (!page_is_buddy(buddy, order)) |
323 | break; /* Move the buddy up one level. */ | 333 | break; /* Move the buddy up one level. */ |
334 | |||
324 | list_del(&buddy->lru); | 335 | list_del(&buddy->lru); |
325 | area = zone->free_area + order; | 336 | area = zone->free_area + order; |
326 | area->nr_free--; | 337 | area->nr_free--; |
327 | rmv_page_order(buddy); | 338 | rmv_page_order(buddy); |
339 | combined_idx = __find_combined_index(page_idx, order); | ||
328 | page = page + (combined_idx - page_idx); | 340 | page = page + (combined_idx - page_idx); |
329 | page_idx = combined_idx; | 341 | page_idx = combined_idx; |
330 | order++; | 342 | order++; |