#define __LINUX_PAGEISOLATION_H
 
 
-bool has_unmovable_pages(struct zone *zone, struct page *page, int count);
+bool has_unmovable_pages(struct zone *zone, struct page *page, int count,
+                        bool skip_hwpoisoned_pages);
 void set_pageblock_migratetype(struct page *page, int migratetype);
 int move_freepages_block(struct zone *zone, struct page *page,
                                int migratetype);
  */
 int
 start_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn,
-                        unsigned migratetype);
+                        unsigned migratetype, bool skip_hwpoisoned_pages);
 
 /*
  * Changes MIGRATE_ISOLATE to MIGRATE_MOVABLE.
 /*
  * Test all pages in [start_pfn, end_pfn) are isolated or not.
  */
-int test_pages_isolated(unsigned long start_pfn, unsigned long end_pfn);
+int test_pages_isolated(unsigned long start_pfn, unsigned long end_pfn,
+                       bool skip_hwpoisoned_pages);
 
 /*
  * Internal functions. Changes pageblock's migrate type.
  */
-int set_migratetype_isolate(struct page *page);
+int set_migratetype_isolate(struct page *page, bool skip_hwpoisoned_pages);
 void unset_migratetype_isolate(struct page *page, unsigned migratetype);
 struct page *alloc_migrate_target(struct page *page, unsigned long private,
                                int **resultp);
 
         * Isolate the page, so that it doesn't get reallocated if it
         * was free.
         */
-       set_migratetype_isolate(p);
+       set_migratetype_isolate(p, true);
        /*
         * When the target page is a free hugepage, just remove it
         * from free hugepage list.
 
 {
        int ret;
        long offlined = *(long *)data;
-       ret = test_pages_isolated(start_pfn, start_pfn + nr_pages);
+       ret = test_pages_isolated(start_pfn, start_pfn + nr_pages, true);
        offlined = nr_pages;
        if (!ret)
                *(long *)data += offlined;
        nr_pages = end_pfn - start_pfn;
 
        /* set above range as isolated */
-       ret = start_isolate_page_range(start_pfn, end_pfn, MIGRATE_MOVABLE);
+       ret = start_isolate_page_range(start_pfn, end_pfn,
+                                      MIGRATE_MOVABLE, true);
        if (ret)
                goto out;
 
 
  * MIGRATE_MOVABLE block might include unmovable pages. It means you can't
  * expect this function should be exact.
  */
-bool has_unmovable_pages(struct zone *zone, struct page *page, int count)
+bool has_unmovable_pages(struct zone *zone, struct page *page, int count,
+                        bool skip_hwpoisoned_pages)
 {
        unsigned long pfn, iter, found;
        int mt;
                        continue;
                }
 
+               /*
+                * The HWPoisoned page may be not in buddy system, and
+                * page_count() is not 0.
+                */
+               if (skip_hwpoisoned_pages && PageHWPoison(page))
+                       continue;
+
                if (!PageLRU(page))
                        found++;
                /*
                        zone->zone_start_pfn + zone->spanned_pages <= pfn)
                return false;
 
-       return !has_unmovable_pages(zone, page, 0);
+       return !has_unmovable_pages(zone, page, 0, true);
 }
 
 #ifdef CONFIG_CMA
         */
 
        ret = start_isolate_page_range(pfn_max_align_down(start),
-                                      pfn_max_align_up(end), migratetype);
+                                      pfn_max_align_up(end), migratetype,
+                                      false);
        if (ret)
                return ret;
 
        }
 
        /* Make sure the range is really isolated. */
-       if (test_pages_isolated(outer_start, end)) {
+       if (test_pages_isolated(outer_start, end, false)) {
                pr_warn("alloc_contig_range test_pages_isolated(%lx, %lx) failed\n",
                       outer_start, end);
                ret = -EBUSY;
                        continue;
                }
                page = pfn_to_page(pfn);
+               /*
+                * The HWPoisoned page may be not in buddy system, and
+                * page_count() is not 0.
+                */
+               if (unlikely(!PageBuddy(page) && PageHWPoison(page))) {
+                       pfn++;
+                       SetPageReserved(page);
+                       continue;
+               }
+
                BUG_ON(page_count(page));
                BUG_ON(!PageBuddy(page));
                order = page_order(page);
 
        zone->nr_pageblock_isolate--;
 }
 
-int set_migratetype_isolate(struct page *page)
+int set_migratetype_isolate(struct page *page, bool skip_hwpoisoned_pages)
 {
        struct zone *zone;
        unsigned long flags, pfn;
         * FIXME: Now, memory hotplug doesn't call shrink_slab() by itself.
         * We just check MOVABLE pages.
         */
-       if (!has_unmovable_pages(zone, page, arg.pages_found))
+       if (!has_unmovable_pages(zone, page, arg.pages_found,
+                                skip_hwpoisoned_pages))
                ret = 0;
 
        /*
  * Returns 0 on success and -EBUSY if any part of range cannot be isolated.
  */
 int start_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn,
-                            unsigned migratetype)
+                            unsigned migratetype, bool skip_hwpoisoned_pages)
 {
        unsigned long pfn;
        unsigned long undo_pfn;
             pfn < end_pfn;
             pfn += pageblock_nr_pages) {
                page = __first_valid_page(pfn, pageblock_nr_pages);
-               if (page && set_migratetype_isolate(page)) {
+               if (page &&
+                   set_migratetype_isolate(page, skip_hwpoisoned_pages)) {
                        undo_pfn = pfn;
                        goto undo;
                }
  * Returns 1 if all pages in the range are isolated.
  */
 static int
-__test_page_isolated_in_pageblock(unsigned long pfn, unsigned long end_pfn)
+__test_page_isolated_in_pageblock(unsigned long pfn, unsigned long end_pfn,
+                                 bool skip_hwpoisoned_pages)
 {
        struct page *page;
 
                else if (page_count(page) == 0 &&
                        get_freepage_migratetype(page) == MIGRATE_ISOLATE)
                        pfn += 1;
+               else if (skip_hwpoisoned_pages && PageHWPoison(page)) {
+                       /*
+                        * The HWPoisoned page may be not in buddy
+                        * system, and page_count() is not 0.
+                        */
+                       pfn++;
+                       continue;
+               }
                else
                        break;
        }
        return 1;
 }
 
-int test_pages_isolated(unsigned long start_pfn, unsigned long end_pfn)
+int test_pages_isolated(unsigned long start_pfn, unsigned long end_pfn,
+                       bool skip_hwpoisoned_pages)
 {
        unsigned long pfn, flags;
        struct page *page;
        /* Check all pages are free or Marked as ISOLATED */
        zone = page_zone(page);
        spin_lock_irqsave(&zone->lock, flags);
-       ret = __test_page_isolated_in_pageblock(start_pfn, end_pfn);
+       ret = __test_page_isolated_in_pageblock(start_pfn, end_pfn,
+                                               skip_hwpoisoned_pages);
        spin_unlock_irqrestore(&zone->lock, flags);
        return ret ? 0 : -EBUSY;
 }