Skip to content

Commit

Permalink
mm/gup: longterm pin migration cleanup
Browse files Browse the repository at this point in the history
When pages are longterm pinned, we must migrated them out of movable zone.
The function that migrates them has a hidden loop with goto.  The loop is
to retry on isolation failures, and after successful migration.

Make this code better by moving this loop to the caller.

Link: https://lkml.kernel.org/r/[email protected]
Signed-off-by: Pavel Tatashin <[email protected]>
Reviewed-by: Jason Gunthorpe <[email protected]>
Cc: Dan Williams <[email protected]>
Cc: David Hildenbrand <[email protected]>
Cc: David Rientjes <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Ira Weiny <[email protected]>
Cc: James Morris <[email protected]>
Cc: Jason Gunthorpe <[email protected]>
Cc: John Hubbard <[email protected]>
Cc: Joonsoo Kim <[email protected]>
Cc: Matthew Wilcox <[email protected]>
Cc: Mel Gorman <[email protected]>
Cc: Michal Hocko <[email protected]>
Cc: Michal Hocko <[email protected]>
Cc: Mike Kravetz <[email protected]>
Cc: Oscar Salvador <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Sasha Levin <[email protected]>
Cc: Steven Rostedt (VMware) <[email protected]>
Cc: Tyler Hicks <[email protected]>
Cc: Vlastimil Babka <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
soleen authored and torvalds committed May 5, 2021
1 parent 24dc20c commit f68749e
Showing 1 changed file with 37 additions and 56 deletions.
93 changes: 37 additions & 56 deletions mm/gup.c
Original file line number Diff line number Diff line change
Expand Up @@ -1602,27 +1602,28 @@ struct page *get_dump_page(unsigned long addr)
#endif /* CONFIG_ELF_CORE */

#ifdef CONFIG_MIGRATION
static long check_and_migrate_movable_pages(struct mm_struct *mm,
unsigned long start,
unsigned long nr_pages,
/*
* Check whether all pages are pinnable, if so return number of pages. If some
* pages are not pinnable, migrate them, and unpin all pages. Return zero if
* pages were migrated, or if some pages were not successfully isolated.
* Return negative error if migration fails.
*/
static long check_and_migrate_movable_pages(unsigned long nr_pages,
struct page **pages,
struct vm_area_struct **vmas,
unsigned int gup_flags)
{
unsigned long i, isolation_error_count;
bool drain_allow;
unsigned long i;
unsigned long isolation_error_count = 0;
bool drain_allow = true;
LIST_HEAD(movable_page_list);
long ret = nr_pages;
struct page *prev_head, *head;
long ret = 0;
struct page *prev_head = NULL;
struct page *head;
struct migration_target_control mtc = {
.nid = NUMA_NO_NODE,
.gfp_mask = GFP_USER | __GFP_NOWARN,
};

check_again:
prev_head = NULL;
isolation_error_count = 0;
drain_allow = true;
for (i = 0; i < nr_pages; i++) {
head = compound_head(pages[i]);
if (head == prev_head)
Expand Down Expand Up @@ -1660,47 +1661,27 @@ static long check_and_migrate_movable_pages(struct mm_struct *mm,
* in the correct zone.
*/
if (list_empty(&movable_page_list) && !isolation_error_count)
return ret;
return nr_pages;

if (gup_flags & FOLL_PIN) {
unpin_user_pages(pages, nr_pages);
} else {
for (i = 0; i < nr_pages; i++)
put_page(pages[i]);
}
if (!list_empty(&movable_page_list)) {
/*
* drop the above get_user_pages reference.
*/
if (gup_flags & FOLL_PIN)
unpin_user_pages(pages, nr_pages);
else
for (i = 0; i < nr_pages; i++)
put_page(pages[i]);

ret = migrate_pages(&movable_page_list, alloc_migration_target,
NULL, (unsigned long)&mtc, MIGRATE_SYNC,
MR_LONGTERM_PIN);
if (ret) {
if (!list_empty(&movable_page_list))
putback_movable_pages(&movable_page_list);
return ret > 0 ? -ENOMEM : ret;
}

/* We unpinned pages before migration, pin them again */
ret = __get_user_pages_locked(mm, start, nr_pages, pages, vmas,
NULL, gup_flags);
if (ret <= 0)
return ret;
nr_pages = ret;
if (ret && !list_empty(&movable_page_list))
putback_movable_pages(&movable_page_list);
}

/*
* check again because pages were unpinned, and we also might have
* had isolation errors and need more pages to migrate.
*/
goto check_again;
return ret > 0 ? -ENOMEM : ret;
}
#else
static long check_and_migrate_movable_pages(struct mm_struct *mm,
unsigned long start,
unsigned long nr_pages,
static long check_and_migrate_movable_pages(unsigned long nr_pages,
struct page **pages,
struct vm_area_struct **vmas,
unsigned int gup_flags)
{
return nr_pages;
Expand All @@ -1718,22 +1699,22 @@ static long __gup_longterm_locked(struct mm_struct *mm,
struct vm_area_struct **vmas,
unsigned int gup_flags)
{
unsigned long flags = 0;
unsigned int flags;
long rc;

if (gup_flags & FOLL_LONGTERM)
flags = memalloc_pin_save();

rc = __get_user_pages_locked(mm, start, nr_pages, pages, vmas, NULL,
gup_flags);
if (!(gup_flags & FOLL_LONGTERM))
return __get_user_pages_locked(mm, start, nr_pages, pages, vmas,
NULL, gup_flags);
flags = memalloc_pin_save();
do {
rc = __get_user_pages_locked(mm, start, nr_pages, pages, vmas,
NULL, gup_flags);
if (rc <= 0)
break;
rc = check_and_migrate_movable_pages(rc, pages, gup_flags);
} while (!rc);
memalloc_pin_restore(flags);

if (gup_flags & FOLL_LONGTERM) {
if (rc > 0)
rc = check_and_migrate_movable_pages(mm, start, rc,
pages, vmas,
gup_flags);
memalloc_pin_restore(flags);
}
return rc;
}

Expand Down

0 comments on commit f68749e

Please sign in to comment.