return false;
 }
 
+static bool
+__reset_isolation_pfn(struct zone *zone, unsigned long pfn, bool check_source,
+                                                       bool check_target)
+{
+       struct page *page = pfn_to_online_page(pfn);
+       struct page *end_page;
+       unsigned long block_pfn;
+
+       if (!page)
+               return false;
+       if (zone != page_zone(page))
+               return false;
+       if (pageblock_skip_persistent(page))
+               return false;
+
+       /*
+        * If skip is already cleared do no further checking once the
+        * restart points have been set.
+        */
+       if (check_source && check_target && !get_pageblock_skip(page))
+               return true;
+
+       /*
+        * If clearing skip for the target scanner, do not select a
+        * non-movable pageblock as the starting point.
+        */
+       if (!check_source && check_target &&
+           get_pageblock_migratetype(page) != MIGRATE_MOVABLE)
+               return false;
+
+       /*
+        * Only clear the hint if a sample indicates there is either a
+        * free page or an LRU page in the block. One or other condition
+        * is necessary for the block to be a migration source/target.
+        */
+       block_pfn = pageblock_start_pfn(pfn);
+       pfn = max(block_pfn, zone->zone_start_pfn);
+       page = pfn_to_page(pfn);
+       if (zone != page_zone(page))
+               return false;
+       pfn = block_pfn + pageblock_nr_pages;
+       pfn = min(pfn, zone_end_pfn(zone));
+       end_page = pfn_to_page(pfn);
+
+       do {
+               if (pfn_valid_within(pfn)) {
+                       if (check_source && PageLRU(page)) {
+                               clear_pageblock_skip(page);
+                               return true;
+                       }
+
+                       if (check_target && PageBuddy(page)) {
+                               clear_pageblock_skip(page);
+                               return true;
+                       }
+               }
+
+               page += (1 << PAGE_ALLOC_COSTLY_ORDER);
+               pfn += (1 << PAGE_ALLOC_COSTLY_ORDER);
+       } while (page < end_page);
+
+       return false;
+}
+
 /*
  * This function is called to clear all cached information on pageblocks that
  * should be skipped for page isolation when the migrate and free page scanner
  */
 static void __reset_isolation_suitable(struct zone *zone)
 {
-       unsigned long start_pfn = zone->zone_start_pfn;
-       unsigned long end_pfn = zone_end_pfn(zone);
-       unsigned long pfn;
+       unsigned long migrate_pfn = zone->zone_start_pfn;
+       unsigned long free_pfn = zone_end_pfn(zone);
+       unsigned long reset_migrate = free_pfn;
+       unsigned long reset_free = migrate_pfn;
+       bool source_set = false;
+       bool free_set = false;
 
-       zone->compact_blockskip_flush = false;
+       if (!zone->compact_blockskip_flush)
+               return;
 
-       /* Walk the zone and mark every pageblock as suitable for isolation */
-       for (pfn = start_pfn; pfn < end_pfn; pfn += pageblock_nr_pages) {
-               struct page *page;
+       zone->compact_blockskip_flush = false;
 
+       /*
+        * Walk the zone and update pageblock skip information. Source looks
+        * for PageLRU while target looks for PageBuddy. When the scanner
+        * is found, both PageBuddy and PageLRU are checked as the pageblock
+        * is suitable as both source and target.
+        */
+       for (; migrate_pfn < free_pfn; migrate_pfn += pageblock_nr_pages,
+                                       free_pfn -= pageblock_nr_pages) {
                cond_resched();
 
-               page = pfn_to_online_page(pfn);
-               if (!page)
-                       continue;
-               if (zone != page_zone(page))
-                       continue;
-               if (pageblock_skip_persistent(page))
-                       continue;
+               /* Update the migrate PFN */
+               if (__reset_isolation_pfn(zone, migrate_pfn, true, source_set) &&
+                   migrate_pfn < reset_migrate) {
+                       source_set = true;
+                       reset_migrate = migrate_pfn;
+                       zone->compact_init_migrate_pfn = reset_migrate;
+                       zone->compact_cached_migrate_pfn[0] = reset_migrate;
+                       zone->compact_cached_migrate_pfn[1] = reset_migrate;
+               }
 
-               clear_pageblock_skip(page);
+               /* Update the free PFN */
+               if (__reset_isolation_pfn(zone, free_pfn, free_set, true) &&
+                   free_pfn > reset_free) {
+                       free_set = true;
+                       reset_free = free_pfn;
+                       zone->compact_init_free_pfn = reset_free;
+                       zone->compact_cached_free_pfn = reset_free;
+               }
        }
 
-       reset_cached_positions(zone);
+       /* Leave no distance if no suitable block was reset */
+       if (reset_migrate >= reset_free) {
+               zone->compact_cached_migrate_pfn[0] = migrate_pfn;
+               zone->compact_cached_migrate_pfn[1] = migrate_pfn;
+               zone->compact_cached_free_pfn = free_pfn;
+       }
 }
 
 void reset_isolation_suitable(pg_data_t *pgdat)
         * If starting the scan, use a deeper search and use the highest
         * PFN found if a suitable one is not found.
         */
-       if (cc->free_pfn == pageblock_start_pfn(zone_end_pfn(cc->zone) - 1)) {
+       if (cc->free_pfn >= cc->zone->compact_init_free_pfn) {
                limit = pageblock_nr_pages >> 1;
                scan_start = true;
        }
                        cc->zone->compact_cached_migrate_pfn[1] = cc->migrate_pfn;
                }
 
-               if (cc->migrate_pfn == start_pfn)
+               if (cc->migrate_pfn <= cc->zone->compact_init_migrate_pfn)
                        cc->whole_zone = true;
        }