Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit 57edfcf

Browse files
xzpeterakpm00
authored andcommitted
mm/gup: accelerate thp gup even for "pages != NULL"
The acceleration of THP was done with ctx.page_mask, however it'll be ignored if **pages is non-NULL. The old optimization was introduced in 2013 in 240aade ("mm: accelerate mm_populate() treatment of THP pages"). It didn't explain why we can't optimize the **pages non-NULL case. It's possible that at that time the major goal was for mm_populate() which should be enough back then. Optimize thp for all cases, by properly looping over each subpage, doing cache flushes, and boost refcounts / pincounts where needed in one go. This can be verified using gup_test below: # chrt -f 1 ./gup_test -m 512 -t -L -n 1024 -r 10 Before: 13992.50 ( +-8.75%) After: 378.50 (+-69.62%) Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Peter Xu <[email protected]> Reviewed-by: Lorenzo Stoakes <[email protected]> Cc: Andrea Arcangeli <[email protected]> Cc: David Hildenbrand <[email protected]> Cc: Hugh Dickins <[email protected]> Cc: James Houghton <[email protected]> Cc: Jason Gunthorpe <[email protected]> Cc: John Hubbard <[email protected]> Cc: Kirill A . Shutemov <[email protected]> Cc: Matthew Wilcox <[email protected]> Cc: Mike Kravetz <[email protected]> Cc: Mike Rapoport (IBM) <[email protected]> Cc: Vlastimil Babka <[email protected]> Cc: Yang Shi <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent ffe1e78 commit 57edfcf

File tree

1 file changed

+44
-7
lines changed

1 file changed

+44
-7
lines changed

mm/gup.c

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1282,16 +1282,53 @@ static long __get_user_pages(struct mm_struct *mm,
12821282
goto out;
12831283
}
12841284
next_page:
1285-
if (pages) {
1286-
pages[i] = page;
1287-
flush_anon_page(vma, page, start);
1288-
flush_dcache_page(page);
1289-
ctx.page_mask = 0;
1290-
}
1291-
12921285
page_increm = 1 + (~(start >> PAGE_SHIFT) & ctx.page_mask);
12931286
if (page_increm > nr_pages)
12941287
page_increm = nr_pages;
1288+
1289+
if (pages) {
1290+
struct page *subpage;
1291+
unsigned int j;
1292+
1293+
/*
1294+
* This must be a large folio (and doesn't need to
1295+
* be the whole folio; it can be part of it), do
1296+
* the refcount work for all the subpages too.
1297+
*
1298+
* NOTE: here the page may not be the head page
1299+
* e.g. when start addr is not thp-size aligned.
1300+
* try_grab_folio() should have taken care of tail
1301+
* pages.
1302+
*/
1303+
if (page_increm > 1) {
1304+
struct folio *folio;
1305+
1306+
/*
1307+
* Since we already hold refcount on the
1308+
* large folio, this should never fail.
1309+
*/
1310+
folio = try_grab_folio(page, page_increm - 1,
1311+
foll_flags);
1312+
if (WARN_ON_ONCE(!folio)) {
1313+
/*
1314+
* Release the 1st page ref if the
1315+
* folio is problematic, fail hard.
1316+
*/
1317+
gup_put_folio(page_folio(page), 1,
1318+
foll_flags);
1319+
ret = -EFAULT;
1320+
goto out;
1321+
}
1322+
}
1323+
1324+
for (j = 0; j < page_increm; j++) {
1325+
subpage = nth_page(page, j);
1326+
pages[i + j] = subpage;
1327+
flush_anon_page(vma, subpage, start + j * PAGE_SIZE);
1328+
flush_dcache_page(subpage);
1329+
}
1330+
}
1331+
12951332
i += page_increm;
12961333
start += page_increm * PAGE_SIZE;
12971334
nr_pages -= page_increm;

0 commit comments

Comments
 (0)