diff options
-rw-r--r-- | include/linux/mm.h | 7 | ||||
-rw-r--r-- | mm/page_alloc.c | 17 |
2 files changed, 16 insertions, 8 deletions
diff --git a/include/linux/mm.h b/include/linux/mm.h index e2fa375e478e..697c6bf248c2 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h | |||
@@ -465,10 +465,13 @@ static inline unsigned long page_zonenum(struct page *page) | |||
465 | struct zone; | 465 | struct zone; |
466 | extern struct zone *zone_table[]; | 466 | extern struct zone *zone_table[]; |
467 | 467 | ||
468 | static inline int page_zone_id(struct page *page) | ||
469 | { | ||
470 | return (page->flags >> ZONETABLE_PGSHIFT) & ZONETABLE_MASK; | ||
471 | } | ||
468 | static inline struct zone *page_zone(struct page *page) | 472 | static inline struct zone *page_zone(struct page *page) |
469 | { | 473 | { |
470 | return zone_table[(page->flags >> ZONETABLE_PGSHIFT) & | 474 | return zone_table[page_zone_id(page)]; |
471 | ZONETABLE_MASK]; | ||
472 | } | 475 | } |
473 | 476 | ||
474 | static inline unsigned long page_to_nid(struct page *page) | 477 | static inline unsigned long page_to_nid(struct page *page) |
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 253a450c400d..fd631c2536a5 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -286,22 +286,27 @@ __find_combined_index(unsigned long page_idx, unsigned int order) | |||
286 | * we can do coalesce a page and its buddy if | 286 | * we can do coalesce a page and its buddy if |
287 | * (a) the buddy is not in a hole && | 287 | * (a) the buddy is not in a hole && |
288 | * (b) the buddy is in the buddy system && | 288 | * (b) the buddy is in the buddy system && |
289 | * (c) a page and its buddy have the same order. | 289 | * (c) a page and its buddy have the same order && |
290 | * (d) a page and its buddy are in the same zone. | ||
290 | * | 291 | * |
291 | * For recording whether a page is in the buddy system, we use PG_buddy. | 292 | * For recording whether a page is in the buddy system, we use PG_buddy. |
292 | * Setting, clearing, and testing PG_buddy is serialized by zone->lock. | 293 | * Setting, clearing, and testing PG_buddy is serialized by zone->lock. |
293 | * | 294 | * |
294 | * For recording page's order, we use page_private(page). | 295 | * For recording page's order, we use page_private(page). |
295 | */ | 296 | */ |
296 | static inline int page_is_buddy(struct page *page, int order) | 297 | static inline int page_is_buddy(struct page *page, struct page *buddy, |
298 | int order) | ||
297 | { | 299 | { |
298 | #ifdef CONFIG_HOLES_IN_ZONE | 300 | #ifdef CONFIG_HOLES_IN_ZONE |
299 | if (!pfn_valid(page_to_pfn(page))) | 301 | if (!pfn_valid(page_to_pfn(buddy))) |
300 | return 0; | 302 | return 0; |
301 | #endif | 303 | #endif |
302 | 304 | ||
303 | if (PageBuddy(page) && page_order(page) == order) { | 305 | if (page_zone_id(page) != page_zone_id(buddy)) |
304 | BUG_ON(page_count(page) != 0); | 306 | return 0; |
307 | |||
308 | if (PageBuddy(buddy) && page_order(buddy) == order) { | ||
309 | BUG_ON(page_count(buddy) != 0); | ||
305 | return 1; | 310 | return 1; |
306 | } | 311 | } |
307 | return 0; | 312 | return 0; |
@@ -352,7 +357,7 @@ static inline void __free_one_page(struct page *page, | |||
352 | struct page *buddy; | 357 | struct page *buddy; |
353 | 358 | ||
354 | buddy = __page_find_buddy(page, page_idx, order); | 359 | buddy = __page_find_buddy(page, page_idx, order); |
355 | if (!page_is_buddy(buddy, order)) | 360 | if (!page_is_buddy(page, buddy, order)) |
356 | break; /* Move the buddy up one level. */ | 361 | break; /* Move the buddy up one level. */ |
357 | 362 | ||
358 | list_del(&buddy->lru); | 363 | list_del(&buddy->lru); |