Linux 6.9-rc1
[linux-2.6-microblaze.git] / mm / page_isolation.c
index 9d73dc3..a5c8fa4 100644 (file)
@@ -37,8 +37,8 @@ static struct page *has_unmovable_pages(unsigned long start_pfn, unsigned long e
        struct zone *zone = page_zone(page);
        unsigned long pfn;
 
-       VM_BUG_ON(ALIGN_DOWN(start_pfn, pageblock_nr_pages) !=
-                 ALIGN_DOWN(end_pfn - 1, pageblock_nr_pages));
+       VM_BUG_ON(pageblock_start_pfn(start_pfn) !=
+                 pageblock_start_pfn(end_pfn - 1));
 
        if (is_migrate_cma_page(page)) {
                /*
@@ -79,17 +79,17 @@ static struct page *has_unmovable_pages(unsigned long start_pfn, unsigned long e
                 * handle each tail page individually in migration.
                 */
                if (PageHuge(page) || PageTransCompound(page)) {
-                       struct page *head = compound_head(page);
+                       struct folio *folio = page_folio(page);
                        unsigned int skip_pages;
 
                        if (PageHuge(page)) {
-                               if (!hugepage_migration_supported(page_hstate(head)))
+                               if (!hugepage_migration_supported(folio_hstate(folio)))
                                        return page;
-                       } else if (!PageLRU(head) && !__PageMovable(head)) {
+                       } else if (!folio_test_lru(folio) && !__folio_test_movable(folio)) {
                                return page;
                        }
 
-                       skip_pages = compound_nr(head) - (page - head);
+                       skip_pages = folio_nr_pages(folio) - folio_page_idx(folio, page);
                        pfn += skip_pages - 1;
                        continue;
                }
@@ -172,7 +172,7 @@ static int set_migratetype_isolate(struct page *page, int migratetype, int isol_
         * to avoid redundant checks.
         */
        check_unmovable_start = max(page_to_pfn(page), start_pfn);
-       check_unmovable_end = min(ALIGN(page_to_pfn(page) + 1, pageblock_nr_pages),
+       check_unmovable_end = min(pageblock_end_pfn(page_to_pfn(page)),
                                  end_pfn);
 
        unmovable = has_unmovable_pages(check_unmovable_start, check_unmovable_end,
@@ -226,7 +226,7 @@ static void unset_migratetype_isolate(struct page *page, int migratetype)
         */
        if (PageBuddy(page)) {
                order = buddy_order(page);
-               if (order >= pageblock_order && order < MAX_ORDER - 1) {
+               if (order >= pageblock_order && order < MAX_PAGE_ORDER) {
                        buddy = find_buddy_page_pfn(page, page_to_pfn(page),
                                                    order, NULL);
                        if (buddy && !is_migrate_isolate_page(buddy)) {
@@ -288,12 +288,14 @@ __first_valid_page(unsigned long pfn, unsigned long nr_pages)
  * @isolate_before:    isolate the pageblock before the boundary_pfn
  * @skip_isolation:    the flag to skip the pageblock isolation in second
  *                     isolate_single_pageblock()
+ * @migratetype:       migrate type to set in error recovery.
  *
- * Free and in-use pages can be as big as MAX_ORDER-1 and contain more than one
+ * Free and in-use pages can be as big as MAX_PAGE_ORDER and contain more than one
  * pageblock. When not all pageblocks within a page are isolated at the same
  * time, free page accounting can go wrong. For example, in the case of
- * MAX_ORDER-1 = pageblock_order + 1, a MAX_ORDER-1 page has two pagelbocks.
- * [         MAX_ORDER-1         ]
+ * MAX_PAGE_ORDER = pageblock_order + 1, a MAX_PAGE_ORDER page has two
+ * pagelbocks.
+ * [      MAX_PAGE_ORDER         ]
  * [  pageblock0  |  pageblock1  ]
  * When either pageblock is isolated, if it is a free page, the page is not
  * split into separate migratetype lists, which is supposed to; if it is an
@@ -302,16 +304,16 @@ __first_valid_page(unsigned long pfn, unsigned long nr_pages)
  * the in-use page then splitting the free page.
  */
 static int isolate_single_pageblock(unsigned long boundary_pfn, int flags,
-                       gfp_t gfp_flags, bool isolate_before, bool skip_isolation)
+                       gfp_t gfp_flags, bool isolate_before, bool skip_isolation,
+                       int migratetype)
 {
-       unsigned char saved_mt;
        unsigned long start_pfn;
        unsigned long isolate_pageblock;
        unsigned long pfn;
        struct zone *zone;
        int ret;
 
-       VM_BUG_ON(!IS_ALIGNED(boundary_pfn, pageblock_nr_pages));
+       VM_BUG_ON(!pageblock_aligned(boundary_pfn));
 
        if (isolate_before)
                isolate_pageblock = boundary_pfn - pageblock_nr_pages;
@@ -328,13 +330,13 @@ static int isolate_single_pageblock(unsigned long boundary_pfn, int flags,
        start_pfn  = max(ALIGN_DOWN(isolate_pageblock, MAX_ORDER_NR_PAGES),
                                      zone->zone_start_pfn);
 
-       saved_mt = get_pageblock_migratetype(pfn_to_page(isolate_pageblock));
+       if (skip_isolation) {
+               int mt __maybe_unused = get_pageblock_migratetype(pfn_to_page(isolate_pageblock));
 
-       if (skip_isolation)
-               VM_BUG_ON(!is_migrate_isolate(saved_mt));
-       else {
-               ret = set_migratetype_isolate(pfn_to_page(isolate_pageblock), saved_mt, flags,
-                               isolate_pageblock, isolate_pageblock + pageblock_nr_pages);
+               VM_BUG_ON(!is_migrate_isolate(mt));
+       } else {
+               ret = set_migratetype_isolate(pfn_to_page(isolate_pageblock), migratetype,
+                               flags, isolate_pageblock, isolate_pageblock + pageblock_nr_pages);
 
                if (ret)
                        return ret;
@@ -432,7 +434,7 @@ static int isolate_single_pageblock(unsigned long boundary_pfn, int flags,
                                }
 
                                ret = __alloc_contig_migrate_range(&cc, head_pfn,
-                                                       head_pfn + nr_pages);
+                                                       head_pfn + nr_pages, page_mt);
 
                                /*
                                 * restore the page's migratetype so that it can
@@ -450,7 +452,7 @@ static int isolate_single_pageblock(unsigned long boundary_pfn, int flags,
                                 * the free page to the right migratetype list.
                                 *
                                 * head_pfn is not used here as a hugetlb page order
-                                * can be bigger than MAX_ORDER-1, but after it is
+                                * can be bigger than MAX_PAGE_ORDER, but after it is
                                 * freed, the free page order is not. Use pfn within
                                 * the range to find the head of the free page.
                                 */
@@ -458,7 +460,7 @@ static int isolate_single_pageblock(unsigned long boundary_pfn, int flags,
                                outer_pfn = pfn;
                                while (!PageBuddy(pfn_to_page(outer_pfn))) {
                                        /* stop if we cannot find the free page */
-                                       if (++order >= MAX_ORDER)
+                                       if (++order > MAX_PAGE_ORDER)
                                                goto failed;
                                        outer_pfn &= ~0UL << order;
                                }
@@ -475,15 +477,14 @@ static int isolate_single_pageblock(unsigned long boundary_pfn, int flags,
 failed:
        /* restore the original migratetype */
        if (!skip_isolation)
-               unset_migratetype_isolate(pfn_to_page(isolate_pageblock), saved_mt);
+               unset_migratetype_isolate(pfn_to_page(isolate_pageblock), migratetype);
        return -EBUSY;
 }
 
 /**
- * start_isolate_page_range() - make page-allocation-type of range of pages to
- * be MIGRATE_ISOLATE.
- * @start_pfn:         The lower PFN of the range to be isolated.
- * @end_pfn:           The upper PFN of the range to be isolated.
+ * start_isolate_page_range() - mark page range MIGRATE_ISOLATE
+ * @start_pfn:         The first PFN of the range to be isolated.
+ * @end_pfn:           The last PFN of the range to be isolated.
  * @migratetype:       Migrate type to set in error recovery.
  * @flags:             The following flags are allowed (they can be combined in
  *                     a bit mask)
@@ -531,13 +532,14 @@ int start_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn,
        unsigned long pfn;
        struct page *page;
        /* isolation is done at page block granularity */
-       unsigned long isolate_start = ALIGN_DOWN(start_pfn, pageblock_nr_pages);
-       unsigned long isolate_end = ALIGN(end_pfn, pageblock_nr_pages);
+       unsigned long isolate_start = pageblock_start_pfn(start_pfn);
+       unsigned long isolate_end = pageblock_align(end_pfn);
        int ret;
        bool skip_isolation = false;
 
        /* isolate [isolate_start, isolate_start + pageblock_nr_pages) pageblock */
-       ret = isolate_single_pageblock(isolate_start, flags, gfp_flags, false, skip_isolation);
+       ret = isolate_single_pageblock(isolate_start, flags, gfp_flags, false,
+                       skip_isolation, migratetype);
        if (ret)
                return ret;
 
@@ -545,7 +547,8 @@ int start_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn,
                skip_isolation = true;
 
        /* isolate [isolate_end - pageblock_nr_pages, isolate_end) pageblock */
-       ret = isolate_single_pageblock(isolate_end, flags, gfp_flags, true, skip_isolation);
+       ret = isolate_single_pageblock(isolate_end, flags, gfp_flags, true,
+                       skip_isolation, migratetype);
        if (ret) {
                unset_migratetype_isolate(pfn_to_page(isolate_start), migratetype);
                return ret;
@@ -568,17 +571,22 @@ int start_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn,
        return 0;
 }
 
-/*
- * Make isolated pages available again.
+/**
+ * undo_isolate_page_range - undo effects of start_isolate_page_range()
+ * @start_pfn:         The first PFN of the isolated range
+ * @end_pfn:           The last PFN of the isolated range
+ * @migratetype:       New migrate type to set on the range
+ *
+ * This finds every MIGRATE_ISOLATE page block in the given range
+ * and switches it to @migratetype.
  */
 void undo_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn,
                            int migratetype)
 {
        unsigned long pfn;
        struct page *page;
-       unsigned long isolate_start = ALIGN_DOWN(start_pfn, pageblock_nr_pages);
-       unsigned long isolate_end = ALIGN(end_pfn, pageblock_nr_pages);
-
+       unsigned long isolate_start = pageblock_start_pfn(start_pfn);
+       unsigned long isolate_end = pageblock_align(end_pfn);
 
        for (pfn = isolate_start;
             pfn < isolate_end;
@@ -629,7 +637,21 @@ __test_page_isolated_in_pageblock(unsigned long pfn, unsigned long end_pfn,
        return pfn;
 }
 
-/* Caller should ensure that requested range is in a single zone */
+/**
+ * test_pages_isolated - check if pageblocks in range are isolated
+ * @start_pfn:         The first PFN of the isolated range
+ * @end_pfn:           The first PFN *after* the isolated range
+ * @isol_flags:                Testing mode flags
+ *
+ * This tests if all in the specified range are free.
+ *
+ * If %MEMORY_OFFLINE is specified in @flags, it will consider
+ * poisoned and offlined pages free as well.
+ *
+ * Caller must ensure the requested range doesn't span zones.
+ *
+ * Returns 0 if true, -EBUSY if one or more pages are in use.
+ */
 int test_pages_isolated(unsigned long start_pfn, unsigned long end_pfn,
                        int isol_flags)
 {
@@ -639,8 +661,8 @@ int test_pages_isolated(unsigned long start_pfn, unsigned long end_pfn,
        int ret;
 
        /*
-        * Note: pageblock_nr_pages != MAX_ORDER. Then, chunks of free pages
-        * are not aligned to pageblock_nr_pages.
+        * Note: pageblock_nr_pages != MAX_PAGE_ORDER. Then, chunks of free
+        * pages are not aligned to pageblock_nr_pages.
         * Then we just check migratetype first.
         */
        for (pfn = start_pfn; pfn < end_pfn; pfn += pageblock_nr_pages) {