Skip to content

Commit 67e139b

Browse files
apopple-nvidiaakpm00
authored andcommitted
mm/gup.c: refactor check_and_migrate_movable_pages()
When pinning pages with FOLL_LONGTERM check_and_migrate_movable_pages() is called to migrate pages out of zones which should not contain any longterm pinned pages. When migration succeeds all pages will have been unpinned so pinning needs to be retried. Migration can also fail, in which case the pages will also have been unpinned but the operation should not be retried. If all pages are in the correct zone nothing will be unpinned and no retry is required. The logic in check_and_migrate_movable_pages() tracks unnecessary state and the return codes for each case are difficult to follow. Refactor the code to clean this up. No behaviour change is intended. [[email protected]: fix unused var warning] Link: https://lkml.kernel.org/r/19583d1df07fdcb99cfa05c265588a3fa58d1902.1661317396.git-series.apopple@nvidia.com Signed-off-by: Alistair Popple <[email protected]> Reviewed-by: John Hubbard <[email protected]> Cc: Alex Sierra <[email protected]> Cc: Dan Williams <[email protected]> Cc: David Hildenbrand <[email protected]> Cc: Felix Kuehling <[email protected]> Cc: Jason Gunthorpe <[email protected]> Cc: Logan Gunthorpe <[email protected]> Cc: Matthew Wilcox <[email protected]> Cc: Miaohe Lin <[email protected]> Cc: Muchun Song <[email protected]> Cc: Ralph Campbell <[email protected]> Cc: Shigeru Yoshida <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent f6d299e commit 67e139b

File tree

1 file changed

+111
-68
lines changed

1 file changed

+111
-68
lines changed

mm/gup.c

Lines changed: 111 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1927,19 +1927,16 @@ struct page *get_dump_page(unsigned long addr)
19271927

19281928
#ifdef CONFIG_MIGRATION
19291929
/*
1930-
* Check whether all pages are pinnable. If some pages are not pinnable migrate
1931-
* them and unpin all the pages. Returns -EAGAIN if pages were unpinned or zero
1932-
* if all pages are pinnable and in the right zone. Other errors indicate
1933-
* migration failure.
1930+
* Returns the number of collected pages. Return value is always >= 0.
19341931
*/
1935-
static long check_and_migrate_movable_pages(unsigned long nr_pages,
1936-
struct page **pages)
1932+
static unsigned long collect_longterm_unpinnable_pages(
1933+
struct list_head *movable_page_list,
1934+
unsigned long nr_pages,
1935+
struct page **pages)
19371936
{
1938-
unsigned long i;
1937+
unsigned long i, collected = 0;
19391938
struct folio *prev_folio = NULL;
1940-
LIST_HEAD(movable_page_list);
1941-
bool drain_allow = true, coherent_pages = false;
1942-
int ret = 0;
1939+
bool drain_allow = true;
19431940

19441941
for (i = 0; i < nr_pages; i++) {
19451942
struct folio *folio = page_folio(pages[i]);
@@ -1948,43 +1945,16 @@ static long check_and_migrate_movable_pages(unsigned long nr_pages,
19481945
continue;
19491946
prev_folio = folio;
19501947

1951-
/*
1952-
* Device coherent pages are managed by a driver and should not
1953-
* be pinned indefinitely as it prevents the driver moving the
1954-
* page. So when trying to pin with FOLL_LONGTERM instead try
1955-
* to migrate the page out of device memory.
1956-
*/
1957-
if (folio_is_device_coherent(folio)) {
1958-
/*
1959-
* We always want a new GUP lookup with device coherent
1960-
* pages.
1961-
*/
1962-
pages[i] = 0;
1963-
coherent_pages = true;
1948+
if (folio_is_longterm_pinnable(folio))
1949+
continue;
19641950

1965-
/*
1966-
* Migration will fail if the page is pinned, so convert
1967-
* the pin on the source page to a normal reference.
1968-
*/
1969-
get_page(&folio->page);
1970-
unpin_user_page(&folio->page);
1951+
collected++;
19711952

1972-
if (migrate_device_coherent_page(&folio->page)) {
1973-
ret = -EBUSY;
1974-
break;
1975-
}
1953+
if (folio_is_device_coherent(folio))
19761954
continue;
1977-
}
19781955

1979-
if (folio_is_longterm_pinnable(folio))
1980-
continue;
1981-
/*
1982-
* Try to move out any movable page before pinning the range.
1983-
*/
19841956
if (folio_test_hugetlb(folio)) {
1985-
if (isolate_hugetlb(&folio->page,
1986-
&movable_page_list))
1987-
ret = -EBUSY;
1957+
isolate_hugetlb(&folio->page, movable_page_list);
19881958
continue;
19891959
}
19901960

@@ -1993,53 +1963,118 @@ static long check_and_migrate_movable_pages(unsigned long nr_pages,
19931963
drain_allow = false;
19941964
}
19951965

1996-
if (folio_isolate_lru(folio)) {
1997-
ret = -EBUSY;
1966+
if (!folio_isolate_lru(folio))
19981967
continue;
1999-
}
2000-
list_add_tail(&folio->lru, &movable_page_list);
1968+
1969+
list_add_tail(&folio->lru, movable_page_list);
20011970
node_stat_mod_folio(folio,
20021971
NR_ISOLATED_ANON + folio_is_file_lru(folio),
20031972
folio_nr_pages(folio));
20041973
}
20051974

2006-
/*
2007-
* If list is empty, and no isolation errors, means that all pages are
2008-
* in the correct zone. If there were device coherent pages some pages
2009-
* have been unpinned.
2010-
*/
2011-
if (list_empty(&movable_page_list) && !ret && !coherent_pages)
2012-
return 0;
1975+
return collected;
1976+
}
1977+
1978+
/*
1979+
* Unpins all pages and migrates device coherent pages and movable_page_list.
1980+
* Returns -EAGAIN if all pages were successfully migrated or -errno for failure
1981+
* (or partial success).
1982+
*/
1983+
static int migrate_longterm_unpinnable_pages(
1984+
struct list_head *movable_page_list,
1985+
unsigned long nr_pages,
1986+
struct page **pages)
1987+
{
1988+
int ret;
1989+
unsigned long i;
20131990

2014-
/*
2015-
* Unpin all pages. If device coherent pages were found
2016-
* migrate_device_coherent_page() will have dropped the pin and set
2017-
* pages[i] == NULL.
2018-
*/
20191991
for (i = 0; i < nr_pages; i++) {
2020-
if (!pages[i])
1992+
struct folio *folio = page_folio(pages[i]);
1993+
1994+
if (folio_is_device_coherent(folio)) {
1995+
/*
1996+
* Migration will fail if the page is pinned, so convert
1997+
* the pin on the source page to a normal reference.
1998+
*/
1999+
pages[i] = NULL;
2000+
folio_get(folio);
2001+
gup_put_folio(folio, 1, FOLL_PIN);
2002+
2003+
if (migrate_device_coherent_page(&folio->page)) {
2004+
ret = -EBUSY;
2005+
goto err;
2006+
}
2007+
20212008
continue;
2009+
}
20222010

2011+
/*
2012+
* We can't migrate pages with unexpected references, so drop
2013+
* the reference obtained by __get_user_pages_locked().
2014+
* Migrating pages have been added to movable_page_list after
2015+
* calling folio_isolate_lru() which takes a reference so the
2016+
* page won't be freed if it's migrating.
2017+
*/
20232018
unpin_user_page(pages[i]);
2019+
pages[i] = NULL;
20242020
}
20252021

2026-
if (!list_empty(&movable_page_list)) {
2022+
if (!list_empty(movable_page_list)) {
20272023
struct migration_target_control mtc = {
20282024
.nid = NUMA_NO_NODE,
20292025
.gfp_mask = GFP_USER | __GFP_NOWARN,
20302026
};
20312027

2032-
ret = migrate_pages(&movable_page_list, alloc_migration_target,
2033-
NULL, (unsigned long)&mtc, MIGRATE_SYNC,
2034-
MR_LONGTERM_PIN, NULL);
2035-
if (ret > 0) /* number of pages not migrated */
2028+
if (migrate_pages(movable_page_list, alloc_migration_target,
2029+
NULL, (unsigned long)&mtc, MIGRATE_SYNC,
2030+
MR_LONGTERM_PIN, NULL)) {
20362031
ret = -ENOMEM;
2032+
goto err;
2033+
}
20372034
}
20382035

2039-
if (ret && !list_empty(&movable_page_list))
2040-
putback_movable_pages(&movable_page_list);
2036+
putback_movable_pages(movable_page_list);
2037+
2038+
return -EAGAIN;
20412039

2042-
return ret ? ret : -EAGAIN;
2040+
err:
2041+
for (i = 0; i < nr_pages; i++)
2042+
if (pages[i])
2043+
unpin_user_page(pages[i]);
2044+
putback_movable_pages(movable_page_list);
2045+
2046+
return ret;
2047+
}
2048+
2049+
/*
2050+
* Check whether all pages are *allowed* to be pinned. Rather confusingly, all
2051+
* pages in the range are required to be pinned via FOLL_PIN, before calling
2052+
* this routine.
2053+
*
2054+
* If any pages in the range are not allowed to be pinned, then this routine
2055+
* will migrate those pages away, unpin all the pages in the range and return
2056+
* -EAGAIN. The caller should re-pin the entire range with FOLL_PIN and then
2057+
* call this routine again.
2058+
*
2059+
* If an error other than -EAGAIN occurs, this indicates a migration failure.
2060+
* The caller should give up, and propagate the error back up the call stack.
2061+
*
2062+
* If everything is OK and all pages in the range are allowed to be pinned, then
2063+
* this routine leaves all pages pinned and returns zero for success.
2064+
*/
2065+
static long check_and_migrate_movable_pages(unsigned long nr_pages,
2066+
struct page **pages)
2067+
{
2068+
unsigned long collected;
2069+
LIST_HEAD(movable_page_list);
2070+
2071+
collected = collect_longterm_unpinnable_pages(&movable_page_list,
2072+
nr_pages, pages);
2073+
if (!collected)
2074+
return 0;
2075+
2076+
return migrate_longterm_unpinnable_pages(&movable_page_list, nr_pages,
2077+
pages);
20432078
}
20442079
#else
20452080
static long check_and_migrate_movable_pages(unsigned long nr_pages,
@@ -2066,7 +2101,15 @@ static long __gup_longterm_locked(struct mm_struct *mm,
20662101
if (!(gup_flags & FOLL_LONGTERM))
20672102
return __get_user_pages_locked(mm, start, nr_pages, pages, vmas,
20682103
NULL, gup_flags);
2069-
/* check_and_migrate_movable_pages() assumes pages have been pinned. */
2104+
2105+
/*
2106+
* If we get to this point then FOLL_LONGTERM is set, and FOLL_LONGTERM
2107+
* implies FOLL_PIN (although the reverse is not true). Therefore it is
2108+
* correct to unconditionally call check_and_migrate_movable_pages()
2109+
* which assumes pages have been pinned via FOLL_PIN.
2110+
*
2111+
* Enforce the above reasoning by asserting that FOLL_PIN is set.
2112+
*/
20702113
if (WARN_ON(!(gup_flags & FOLL_PIN)))
20712114
return -EINVAL;
20722115
flags = memalloc_pin_save();

0 commit comments

Comments
 (0)