Merge branch 'fixes-v5.7' into fixes
[linux-2.6-microblaze.git] / mm / migrate.c
index 7ded070..7160c15 100644 (file)
@@ -193,7 +193,7 @@ void putback_movable_pages(struct list_head *l)
                        put_page(page);
                } else {
                        mod_node_page_state(page_pgdat(page), NR_ISOLATED_ANON +
-                                       page_is_file_cache(page), -hpage_nr_pages(page));
+                                       page_is_file_lru(page), -hpage_nr_pages(page));
                        putback_lru_page(page);
                }
        }
@@ -243,11 +243,15 @@ static bool remove_migration_pte(struct page *page, struct vm_area_struct *vma,
                entry = pte_to_swp_entry(*pvmw.pte);
                if (is_write_migration_entry(entry))
                        pte = maybe_mkwrite(pte, vma);
+               else if (pte_swp_uffd_wp(*pvmw.pte))
+                       pte = pte_mkuffd_wp(pte);
 
                if (unlikely(is_zone_device_page(new))) {
                        if (is_device_private_page(new)) {
                                entry = make_device_private_entry(new, pte_write(pte));
                                pte = swp_entry_to_pte(entry);
+                               if (pte_swp_uffd_wp(*pvmw.pte))
+                                       pte = pte_mkuffd_wp(pte);
                        }
                }
 
@@ -647,6 +651,14 @@ void migrate_page_states(struct page *newpage, struct page *page)
        if (PageWriteback(newpage))
                end_page_writeback(newpage);
 
+       /*
+        * PG_readahead shares the same bit with PG_reclaim.  The above
+        * end_page_writeback() may clear PG_readahead mistakenly, so set the
+        * bit after that.
+        */
+       if (PageReadahead(page))
+               SetPageReadahead(newpage);
+
        copy_page_owner(page, newpage);
 
        mem_cgroup_migrate(page, newpage);
@@ -1211,7 +1223,7 @@ out:
                 */
                if (likely(!__PageMovable(page)))
                        mod_node_page_state(page_pgdat(page), NR_ISOLATED_ANON +
-                                       page_is_file_cache(page), -hpage_nr_pages(page));
+                                       page_is_file_lru(page), -hpage_nr_pages(page));
        }
 
        /*
@@ -1518,9 +1530,6 @@ static int do_move_pages_to_node(struct mm_struct *mm,
 {
        int err;
 
-       if (list_empty(pagelist))
-               return 0;
-
        err = migrate_pages(pagelist, alloc_new_node_page, NULL, node,
                        MIGRATE_SYNC, MR_SYSCALL);
        if (err)
@@ -1587,7 +1596,7 @@ static int add_page_for_migration(struct mm_struct *mm, unsigned long addr,
                err = 1;
                list_add_tail(&head->lru, pagelist);
                mod_node_page_state(page_pgdat(head),
-                       NR_ISOLATED_ANON + page_is_file_cache(head),
+                       NR_ISOLATED_ANON + page_is_file_lru(head),
                        hpage_nr_pages(head));
        }
 out_putpage:
@@ -1602,6 +1611,32 @@ out:
        return err;
 }
 
+static int move_pages_and_store_status(struct mm_struct *mm, int node,
+               struct list_head *pagelist, int __user *status,
+               int start, int i, unsigned long nr_pages)
+{
+       int err;
+
+       if (list_empty(pagelist))
+               return 0;
+
+       err = do_move_pages_to_node(mm, pagelist, node);
+       if (err) {
+               /*
+                * Positive err means the number of failed
+                * pages to migrate.  Since we are going to
+                * abort and return the number of non-migrated
+                * pages, so need to incude the rest of the
+                * nr_pages that have not been attempted as
+                * well.
+                */
+               if (err > 0)
+                       err += nr_pages - i - 1;
+               return err;
+       }
+       return store_status(status, start, node, i - start);
+}
+
 /*
  * Migrate an array of page address onto an array of nodes and fill
  * the corresponding array of status.
@@ -1645,21 +1680,8 @@ static int do_pages_move(struct mm_struct *mm, nodemask_t task_nodes,
                        current_node = node;
                        start = i;
                } else if (node != current_node) {
-                       err = do_move_pages_to_node(mm, &pagelist, current_node);
-                       if (err) {
-                               /*
-                                * Positive err means the number of failed
-                                * pages to migrate.  Since we are going to
-                                * abort and return the number of non-migrated
-                                * pages, so need to incude the rest of the
-                                * nr_pages that have not been attempted as
-                                * well.
-                                */
-                               if (err > 0)
-                                       err += nr_pages - i - 1;
-                               goto out;
-                       }
-                       err = store_status(status, start, current_node, i - start);
+                       err = move_pages_and_store_status(mm, current_node,
+                                       &pagelist, status, start, i, nr_pages);
                        if (err)
                                goto out;
                        start = i;
@@ -1673,49 +1695,29 @@ static int do_pages_move(struct mm_struct *mm, nodemask_t task_nodes,
                err = add_page_for_migration(mm, addr, current_node,
                                &pagelist, flags & MPOL_MF_MOVE_ALL);
 
-               if (!err) {
-                       /* The page is already on the target node */
-                       err = store_status(status, i, current_node, 1);
-                       if (err)
-                               goto out_flush;
-                       continue;
-               } else if (err > 0) {
+               if (err > 0) {
                        /* The page is successfully queued for migration */
                        continue;
                }
 
-               err = store_status(status, i, err, 1);
+               /*
+                * If the page is already on the target node (!err), store the
+                * node, otherwise, store the err.
+                */
+               err = store_status(status, i, err ? : current_node, 1);
                if (err)
                        goto out_flush;
 
-               err = do_move_pages_to_node(mm, &pagelist, current_node);
-               if (err) {
-                       if (err > 0)
-                               err += nr_pages - i - 1;
+               err = move_pages_and_store_status(mm, current_node, &pagelist,
+                               status, start, i, nr_pages);
+               if (err)
                        goto out;
-               }
-               if (i > start) {
-                       err = store_status(status, start, current_node, i - start);
-                       if (err)
-                               goto out;
-               }
                current_node = NUMA_NO_NODE;
        }
 out_flush:
-       if (list_empty(&pagelist))
-               return err;
-
        /* Make sure we do not overwrite the existing error */
-       err1 = do_move_pages_to_node(mm, &pagelist, current_node);
-       /*
-        * Don't have to report non-attempted pages here since:
-        *     - If the above loop is done gracefully all pages have been
-        *       attempted.
-        *     - If the above loop is aborted it means a fatal error
-        *       happened, should return ret.
-        */
-       if (!err1)
-               err1 = store_status(status, start, current_node, i - start);
+       err1 = move_pages_and_store_status(mm, current_node, &pagelist,
+                               status, start, i, nr_pages);
        if (err >= 0)
                err = err1;
 out:
@@ -1957,7 +1959,7 @@ static int numamigrate_isolate_page(pg_data_t *pgdat, struct page *page)
                return 0;
        }
 
-       page_lru = page_is_file_cache(page);
+       page_lru = page_is_file_lru(page);
        mod_node_page_state(page_pgdat(page), NR_ISOLATED_ANON + page_lru,
                                hpage_nr_pages(page));
 
@@ -1993,7 +1995,7 @@ int migrate_misplaced_page(struct page *page, struct vm_area_struct *vma,
         * Don't migrate file pages that are mapped in multiple processes
         * with execute permissions as they are probably shared libraries.
         */
-       if (page_mapcount(page) != 1 && page_is_file_cache(page) &&
+       if (page_mapcount(page) != 1 && page_is_file_lru(page) &&
            (vma->vm_flags & VM_EXEC))
                goto out;
 
@@ -2001,7 +2003,7 @@ int migrate_misplaced_page(struct page *page, struct vm_area_struct *vma,
         * Also do not migrate dirty pages as not all filesystems can move
         * dirty pages in MIGRATE_ASYNC mode which is a waste of cycles.
         */
-       if (page_is_file_cache(page) && PageDirty(page))
+       if (page_is_file_lru(page) && PageDirty(page))
                goto out;
 
        isolated = numamigrate_isolate_page(pgdat, page);
@@ -2016,7 +2018,7 @@ int migrate_misplaced_page(struct page *page, struct vm_area_struct *vma,
                if (!list_empty(&migratepages)) {
                        list_del(&page->lru);
                        dec_node_page_state(page, NR_ISOLATED_ANON +
-                                       page_is_file_cache(page));
+                                       page_is_file_lru(page));
                        putback_lru_page(page);
                }
                isolated = 0;
@@ -2046,7 +2048,7 @@ int migrate_misplaced_transhuge_page(struct mm_struct *mm,
        pg_data_t *pgdat = NODE_DATA(node);
        int isolated = 0;
        struct page *new_page = NULL;
-       int page_lru = page_is_file_cache(page);
+       int page_lru = page_is_file_lru(page);
        unsigned long start = address & HPAGE_PMD_MASK;
 
        new_page = alloc_pages_node(node,
@@ -2340,6 +2342,8 @@ again:
                        swp_pte = swp_entry_to_pte(entry);
                        if (pte_soft_dirty(pte))
                                swp_pte = pte_swp_mksoft_dirty(swp_pte);
+                       if (pte_uffd_wp(pte))
+                               swp_pte = pte_swp_mkuffd_wp(swp_pte);
                        set_pte_at(mm, addr, ptep, swp_pte);
 
                        /*