]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/blobdiff - mm/migrate.c
khugepaged: fix wrong result value for trace_mm_collapse_huge_page_isolate()
[mirror_ubuntu-focal-kernel.git] / mm / migrate.c
index 73d476d690b10555909b8ac3974a9077faec5cf0..c4c313e47f123456b2033ae2950a7f7789a9d8e7 100644 (file)
@@ -1516,9 +1516,11 @@ static int do_move_pages_to_node(struct mm_struct *mm,
 /*
  * Resolves the given address to a struct page, isolates it from the LRU and
  * puts it to the given pagelist.
- * Returns -errno if the page cannot be found/isolated or 0 when it has been
- * queued or the page doesn't need to be migrated because it is already on
- * the target node
+ * Returns:
+ *     errno - if the page cannot be found/isolated
+ *     0 - when it doesn't have to be migrated because it is already on the
+ *         target node
+ *     1 - when it has been queued
  */
 static int add_page_for_migration(struct mm_struct *mm, unsigned long addr,
                int node, struct list_head *pagelist, bool migrate_all)
@@ -1557,7 +1559,7 @@ static int add_page_for_migration(struct mm_struct *mm, unsigned long addr,
        if (PageHuge(page)) {
                if (PageHead(page)) {
                        isolate_huge_page(page, pagelist);
-                       err = 0;
+                       err = 1;
                }
        } else {
                struct page *head;
@@ -1567,7 +1569,7 @@ static int add_page_for_migration(struct mm_struct *mm, unsigned long addr,
                if (err)
                        goto out_putpage;
 
-               err = 0;
+               err = 1;
                list_add_tail(&head->lru, pagelist);
                mod_node_page_state(page_pgdat(head),
                        NR_ISOLATED_ANON + page_is_file_cache(head),
@@ -1612,7 +1614,7 @@ static int do_pages_move(struct mm_struct *mm, nodemask_t task_nodes,
                        goto out_flush;
                if (get_user(node, nodes + i))
                        goto out_flush;
-               addr = (unsigned long)p;
+               addr = (unsigned long)untagged_addr(p);
 
                err = -ENODEV;
                if (node < 0 || node >= MAX_NUMNODES)
@@ -1629,8 +1631,19 @@ static int do_pages_move(struct mm_struct *mm, nodemask_t task_nodes,
                        start = i;
                } else if (node != current_node) {
                        err = do_move_pages_to_node(mm, &pagelist, current_node);
-                       if (err)
+                       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);
                        if (err)
                                goto out;
@@ -1644,16 +1657,28 @@ 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)
+
+               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) {
+                       /* The page is successfully queued for migration */
+                       continue;
+               }
 
                err = store_status(status, i, err, 1);
                if (err)
                        goto out_flush;
 
                err = do_move_pages_to_node(mm, &pagelist, current_node);
-               if (err)
+               if (err) {
+                       if (err > 0)
+                               err += nr_pages - i - 1;
                        goto out;
+               }
                if (i > start) {
                        err = store_status(status, start, current_node, i - start);
                        if (err)
@@ -1667,9 +1692,16 @@ out_flush:
 
        /* 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);
-       if (!err)
+       if (err >= 0)
                err = err1;
 out:
        return err;