Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Revert "mm: compaction: handle incorrect MIGRATE_UNMOVABLE type pageblocks"

This reverts commit 5ceb9ce6fe9462a298bb2cd5c9f1ca6cb80a0199.

That commit seems to be the cause of the mm compation list corruption
issues that Dave Jones reported. The locking (or rather, absense
there-of) is dubious, as is the use of the 'page' variable once it has
been found to be outside the pageblock range.

So revert it for now, we can re-visit this for 3.6. If we even need to:
as Minchan Kim says, "The patch wasn't a bug fix and even test workload
was very theoretical".

Reported-and-tested-by: Dave Jones <davej@redhat.com>
Acked-by: Hugh Dickins <hughd@google.com>
Acked-by: KOSAKI Motohiro <kosaki.motohiro@gmail.com>
Acked-by: Minchan Kim <minchan@kernel.org>
Cc: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
Cc: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

+28 -150
-19
include/linux/compaction.h
··· 1 1 #ifndef _LINUX_COMPACTION_H 2 2 #define _LINUX_COMPACTION_H 3 3 4 - #include <linux/node.h> 5 - 6 4 /* Return values for compact_zone() and try_to_compact_pages() */ 7 5 /* compaction didn't start as it was not possible or direct reclaim was more suitable */ 8 6 #define COMPACT_SKIPPED 0 ··· 10 12 #define COMPACT_PARTIAL 2 11 13 /* The full zone was compacted */ 12 14 #define COMPACT_COMPLETE 3 13 - 14 - /* 15 - * compaction supports three modes 16 - * 17 - * COMPACT_ASYNC_MOVABLE uses asynchronous migration and only scans 18 - * MIGRATE_MOVABLE pageblocks as migration sources and targets. 19 - * COMPACT_ASYNC_UNMOVABLE uses asynchronous migration and only scans 20 - * MIGRATE_MOVABLE pageblocks as migration sources. 21 - * MIGRATE_UNMOVABLE pageblocks are scanned as potential migration 22 - * targets and convers them to MIGRATE_MOVABLE if possible 23 - * COMPACT_SYNC uses synchronous migration and scans all pageblocks 24 - */ 25 - enum compact_mode { 26 - COMPACT_ASYNC_MOVABLE, 27 - COMPACT_ASYNC_UNMOVABLE, 28 - COMPACT_SYNC, 29 - }; 30 15 31 16 #ifdef CONFIG_COMPACTION 32 17 extern int sysctl_compact_memory;
+23 -119
mm/compaction.c
··· 236 236 */ 237 237 while (unlikely(too_many_isolated(zone))) { 238 238 /* async migration should just abort */ 239 - if (cc->mode != COMPACT_SYNC) 239 + if (!cc->sync) 240 240 return 0; 241 241 242 242 congestion_wait(BLK_RW_ASYNC, HZ/10); ··· 304 304 * satisfies the allocation 305 305 */ 306 306 pageblock_nr = low_pfn >> pageblock_order; 307 - if (cc->mode != COMPACT_SYNC && 308 - last_pageblock_nr != pageblock_nr && 307 + if (!cc->sync && last_pageblock_nr != pageblock_nr && 309 308 !migrate_async_suitable(get_pageblock_migratetype(page))) { 310 309 low_pfn += pageblock_nr_pages; 311 310 low_pfn = ALIGN(low_pfn, pageblock_nr_pages) - 1; ··· 325 326 continue; 326 327 } 327 328 328 - if (cc->mode != COMPACT_SYNC) 329 + if (!cc->sync) 329 330 mode |= ISOLATE_ASYNC_MIGRATE; 330 331 331 332 lruvec = mem_cgroup_page_lruvec(page, zone); ··· 360 361 361 362 #endif /* CONFIG_COMPACTION || CONFIG_CMA */ 362 363 #ifdef CONFIG_COMPACTION 363 - /* 364 - * Returns true if MIGRATE_UNMOVABLE pageblock was successfully 365 - * converted to MIGRATE_MOVABLE type, false otherwise. 366 - */ 367 - static bool rescue_unmovable_pageblock(struct page *page) 368 - { 369 - unsigned long pfn, start_pfn, end_pfn; 370 - struct page *start_page, *end_page; 371 364 372 - pfn = page_to_pfn(page); 373 - start_pfn = pfn & ~(pageblock_nr_pages - 1); 374 - end_pfn = start_pfn + pageblock_nr_pages; 375 - 376 - start_page = pfn_to_page(start_pfn); 377 - end_page = pfn_to_page(end_pfn); 378 - 379 - /* Do not deal with pageblocks that overlap zones */ 380 - if (page_zone(start_page) != page_zone(end_page)) 381 - return false; 382 - 383 - for (page = start_page, pfn = start_pfn; page < end_page; pfn++, 384 - page++) { 385 - if (!pfn_valid_within(pfn)) 386 - continue; 387 - 388 - if (PageBuddy(page)) { 389 - int order = page_order(page); 390 - 391 - pfn += (1 << order) - 1; 392 - page += (1 << order) - 1; 393 - 394 - continue; 395 - } else if (page_count(page) == 0 || PageLRU(page)) 396 - continue; 397 - 398 - return false; 399 - } 400 - 401 - set_pageblock_migratetype(page, MIGRATE_MOVABLE); 402 - move_freepages_block(page_zone(page), page, MIGRATE_MOVABLE); 403 - return true; 404 - } 405 - 406 - enum smt_result { 407 - GOOD_AS_MIGRATION_TARGET, 408 - FAIL_UNMOVABLE_TARGET, 409 - FAIL_BAD_TARGET, 410 - }; 411 - 412 - /* 413 - * Returns GOOD_AS_MIGRATION_TARGET if the page is within a block 414 - * suitable for migration to, FAIL_UNMOVABLE_TARGET if the page 415 - * is within a MIGRATE_UNMOVABLE block, FAIL_BAD_TARGET otherwise. 416 - */ 417 - static enum smt_result suitable_migration_target(struct page *page, 418 - struct compact_control *cc) 365 + /* Returns true if the page is within a block suitable for migration to */ 366 + static bool suitable_migration_target(struct page *page) 419 367 { 420 368 421 369 int migratetype = get_pageblock_migratetype(page); 422 370 423 371 /* Don't interfere with memory hot-remove or the min_free_kbytes blocks */ 424 372 if (migratetype == MIGRATE_ISOLATE || migratetype == MIGRATE_RESERVE) 425 - return FAIL_BAD_TARGET; 373 + return false; 426 374 427 375 /* If the page is a large free page, then allow migration */ 428 376 if (PageBuddy(page) && page_order(page) >= pageblock_order) 429 - return GOOD_AS_MIGRATION_TARGET; 377 + return true; 430 378 431 379 /* If the block is MIGRATE_MOVABLE or MIGRATE_CMA, allow migration */ 432 - if (cc->mode != COMPACT_ASYNC_UNMOVABLE && 433 - migrate_async_suitable(migratetype)) 434 - return GOOD_AS_MIGRATION_TARGET; 435 - 436 - if (cc->mode == COMPACT_ASYNC_MOVABLE && 437 - migratetype == MIGRATE_UNMOVABLE) 438 - return FAIL_UNMOVABLE_TARGET; 439 - 440 - if (cc->mode != COMPACT_ASYNC_MOVABLE && 441 - migratetype == MIGRATE_UNMOVABLE && 442 - rescue_unmovable_pageblock(page)) 443 - return GOOD_AS_MIGRATION_TARGET; 380 + if (migrate_async_suitable(migratetype)) 381 + return true; 444 382 445 383 /* Otherwise skip the block */ 446 - return FAIL_BAD_TARGET; 384 + return false; 447 385 } 448 386 449 387 /* ··· 414 478 zone_end_pfn = zone->zone_start_pfn + zone->spanned_pages; 415 479 416 480 /* 417 - * isolate_freepages() may be called more than once during 418 - * compact_zone_order() run and we want only the most recent 419 - * count. 420 - */ 421 - cc->nr_pageblocks_skipped = 0; 422 - 423 - /* 424 481 * Isolate free pages until enough are available to migrate the 425 482 * pages on cc->migratepages. We stop searching if the migrate 426 483 * and free page scanners meet or enough free pages are isolated. ··· 421 492 for (; pfn > low_pfn && cc->nr_migratepages > nr_freepages; 422 493 pfn -= pageblock_nr_pages) { 423 494 unsigned long isolated; 424 - enum smt_result ret; 425 495 426 496 if (!pfn_valid(pfn)) 427 497 continue; ··· 437 509 continue; 438 510 439 511 /* Check the block is suitable for migration */ 440 - ret = suitable_migration_target(page, cc); 441 - if (ret != GOOD_AS_MIGRATION_TARGET) { 442 - if (ret == FAIL_UNMOVABLE_TARGET) 443 - cc->nr_pageblocks_skipped++; 512 + if (!suitable_migration_target(page)) 444 513 continue; 445 - } 514 + 446 515 /* 447 516 * Found a block suitable for isolating free pages from. Now 448 517 * we disabled interrupts, double check things are ok and ··· 448 523 */ 449 524 isolated = 0; 450 525 spin_lock_irqsave(&zone->lock, flags); 451 - ret = suitable_migration_target(page, cc); 452 - if (ret == GOOD_AS_MIGRATION_TARGET) { 526 + if (suitable_migration_target(page)) { 453 527 end_pfn = min(pfn + pageblock_nr_pages, zone_end_pfn); 454 528 isolated = isolate_freepages_block(pfn, end_pfn, 455 529 freelist, false); 456 530 nr_freepages += isolated; 457 - } else if (ret == FAIL_UNMOVABLE_TARGET) 458 - cc->nr_pageblocks_skipped++; 531 + } 459 532 spin_unlock_irqrestore(&zone->lock, flags); 460 533 461 534 /* ··· 685 762 686 763 nr_migrate = cc->nr_migratepages; 687 764 err = migrate_pages(&cc->migratepages, compaction_alloc, 688 - (unsigned long)&cc->freepages, false, 689 - (cc->mode == COMPACT_SYNC) ? MIGRATE_SYNC_LIGHT 690 - : MIGRATE_ASYNC); 765 + (unsigned long)cc, false, 766 + cc->sync ? MIGRATE_SYNC_LIGHT : MIGRATE_ASYNC); 691 767 update_nr_listpages(cc); 692 768 nr_remaining = cc->nr_migratepages; 693 769 ··· 715 793 716 794 static unsigned long compact_zone_order(struct zone *zone, 717 795 int order, gfp_t gfp_mask, 718 - enum compact_mode mode, 719 - unsigned long *nr_pageblocks_skipped) 796 + bool sync) 720 797 { 721 798 struct compact_control cc = { 722 799 .nr_freepages = 0, ··· 723 802 .order = order, 724 803 .migratetype = allocflags_to_migratetype(gfp_mask), 725 804 .zone = zone, 726 - .mode = mode, 805 + .sync = sync, 727 806 }; 728 - unsigned long rc; 729 - 730 807 INIT_LIST_HEAD(&cc.freepages); 731 808 INIT_LIST_HEAD(&cc.migratepages); 732 809 733 - rc = compact_zone(zone, &cc); 734 - *nr_pageblocks_skipped = cc.nr_pageblocks_skipped; 735 - 736 - return rc; 810 + return compact_zone(zone, &cc); 737 811 } 738 812 739 813 int sysctl_extfrag_threshold = 500; ··· 753 837 struct zoneref *z; 754 838 struct zone *zone; 755 839 int rc = COMPACT_SKIPPED; 756 - unsigned long nr_pageblocks_skipped; 757 - enum compact_mode mode; 758 840 759 841 /* 760 842 * Check whether it is worth even starting compaction. The order check is ··· 769 855 nodemask) { 770 856 int status; 771 857 772 - mode = sync ? COMPACT_SYNC : COMPACT_ASYNC_MOVABLE; 773 - retry: 774 - status = compact_zone_order(zone, order, gfp_mask, mode, 775 - &nr_pageblocks_skipped); 858 + status = compact_zone_order(zone, order, gfp_mask, sync); 776 859 rc = max(status, rc); 777 860 778 861 /* If a normal allocation would succeed, stop compacting */ 779 862 if (zone_watermark_ok(zone, order, low_wmark_pages(zone), 0, 0)) 780 863 break; 781 - 782 - if (rc == COMPACT_COMPLETE && mode == COMPACT_ASYNC_MOVABLE) { 783 - if (nr_pageblocks_skipped) { 784 - mode = COMPACT_ASYNC_UNMOVABLE; 785 - goto retry; 786 - } 787 - } 788 864 } 789 865 790 866 return rc; ··· 808 904 if (ok && cc->order > zone->compact_order_failed) 809 905 zone->compact_order_failed = cc->order + 1; 810 906 /* Currently async compaction is never deferred. */ 811 - else if (!ok && cc->mode == COMPACT_SYNC) 907 + else if (!ok && cc->sync) 812 908 defer_compaction(zone, cc->order); 813 909 } 814 910 ··· 823 919 { 824 920 struct compact_control cc = { 825 921 .order = order, 826 - .mode = COMPACT_ASYNC_MOVABLE, 922 + .sync = false, 827 923 }; 828 924 829 925 return __compact_pgdat(pgdat, &cc); ··· 833 929 { 834 930 struct compact_control cc = { 835 931 .order = -1, 836 - .mode = COMPACT_SYNC, 932 + .sync = true, 837 933 }; 838 934 839 935 return __compact_pgdat(NODE_DATA(nid), &cc);
+1 -8
mm/internal.h
··· 94 94 /* 95 95 * in mm/page_alloc.c 96 96 */ 97 - extern void set_pageblock_migratetype(struct page *page, int migratetype); 98 - extern int move_freepages_block(struct zone *zone, struct page *page, 99 - int migratetype); 100 97 extern void __free_pages_bootmem(struct page *page, unsigned int order); 101 98 extern void prep_compound_page(struct page *page, unsigned long order); 102 99 #ifdef CONFIG_MEMORY_FAILURE ··· 101 104 #endif 102 105 103 106 #if defined CONFIG_COMPACTION || defined CONFIG_CMA 104 - #include <linux/compaction.h> 105 107 106 108 /* 107 109 * in mm/compaction.c ··· 119 123 unsigned long nr_migratepages; /* Number of pages to migrate */ 120 124 unsigned long free_pfn; /* isolate_freepages search base */ 121 125 unsigned long migrate_pfn; /* isolate_migratepages search base */ 122 - enum compact_mode mode; /* Compaction mode */ 126 + bool sync; /* Synchronous migration */ 123 127 124 128 int order; /* order a direct compactor needs */ 125 129 int migratetype; /* MOVABLE, RECLAIMABLE etc */ 126 130 struct zone *zone; 127 - 128 - /* Number of UNMOVABLE destination pageblocks skipped during scan */ 129 - unsigned long nr_pageblocks_skipped; 130 131 }; 131 132 132 133 unsigned long
+4 -4
mm/page_alloc.c
··· 219 219 220 220 int page_group_by_mobility_disabled __read_mostly; 221 221 222 - void set_pageblock_migratetype(struct page *page, int migratetype) 222 + static void set_pageblock_migratetype(struct page *page, int migratetype) 223 223 { 224 224 225 225 if (unlikely(page_group_by_mobility_disabled)) ··· 954 954 return pages_moved; 955 955 } 956 956 957 - int move_freepages_block(struct zone *zone, struct page *page, 958 - int migratetype) 957 + static int move_freepages_block(struct zone *zone, struct page *page, 958 + int migratetype) 959 959 { 960 960 unsigned long start_pfn, end_pfn; 961 961 struct page *start_page, *end_page; ··· 5651 5651 .nr_migratepages = 0, 5652 5652 .order = -1, 5653 5653 .zone = page_zone(pfn_to_page(start)), 5654 - .mode = COMPACT_SYNC, 5654 + .sync = true, 5655 5655 }; 5656 5656 INIT_LIST_HEAD(&cc.migratepages); 5657 5657