Message ID | 20210119043920.155044-3-pasha.tatashin@soleen.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | prohibit pinning pages in ZONE_MOVABLE | expand |
On Mon, Jan 18, 2021 at 11:39:08PM -0500, Pavel Tatashin wrote: > When pages are isolated in check_and_migrate_movable_pages() we skip > compound number of pages at a time. However, as Jason noted, it is > not necessary correct that pages[i] corresponds to the pages that > we skipped. This is because it is possible that the addresses in > this range had split_huge_pmd()/split_huge_pud(), and these functions > do not update the compound page metadata. > > The problem can be reproduced if something like this occurs: > > 1. User faulted huge pages. > 2. split_huge_pmd() was called for some reason > 3. User has unmapped some sub-pages in the range > 4. User tries to longterm pin the addresses. > > The resulting pages[i] might end-up having pages which are not compound > size page aligned. > > Fixes: aa712399c1e8 ("mm/gup: speed up check_and_migrate_cma_pages() on huge page") > > Reported-by: Jason Gunthorpe <jgg@nvidia.com> No new line after fixes > Signed-off-by: Pavel Tatashin <pasha.tatashin@soleen.com> > mm/gup.c | 19 +++++++------------ > 1 file changed, 7 insertions(+), 12 deletions(-) Looks good Reviewed-by: Jason Gunthorpe <jgg@nvidia.com> Thanks, Jason
diff --git a/mm/gup.c b/mm/gup.c index 24f25b1e9103..16f10d5a9eb6 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -1556,26 +1556,23 @@ static long check_and_migrate_cma_pages(struct mm_struct *mm, unsigned int gup_flags) { unsigned long i; - unsigned long step; bool drain_allow = true; bool migrate_allow = true; LIST_HEAD(cma_page_list); long ret = nr_pages; + struct page *prev_head, *head; struct migration_target_control mtc = { .nid = NUMA_NO_NODE, .gfp_mask = GFP_USER | __GFP_NOWARN, }; check_again: - for (i = 0; i < nr_pages;) { - - struct page *head = compound_head(pages[i]); - - /* - * gup may start from a tail page. Advance step by the left - * part. - */ - step = compound_nr(head) - (pages[i] - head); + prev_head = NULL; + for (i = 0; i < nr_pages; i++) { + head = compound_head(pages[i]); + if (head == prev_head) + continue; + prev_head = head; /* * If we get a page from the CMA zone, since we are going to * be pinning these entries, we might as well move them out @@ -1599,8 +1596,6 @@ static long check_and_migrate_cma_pages(struct mm_struct *mm, } } } - - i += step; } if (!list_empty(&cma_page_list)) {
When pages are isolated in check_and_migrate_movable_pages() we skip compound number of pages at a time. However, as Jason noted, it is not necessary correct that pages[i] corresponds to the pages that we skipped. This is because it is possible that the addresses in this range had split_huge_pmd()/split_huge_pud(), and these functions do not update the compound page metadata. The problem can be reproduced if something like this occurs: 1. User faulted huge pages. 2. split_huge_pmd() was called for some reason 3. User has unmapped some sub-pages in the range 4. User tries to longterm pin the addresses. The resulting pages[i] might end-up having pages which are not compound size page aligned. Fixes: aa712399c1e8 ("mm/gup: speed up check_and_migrate_cma_pages() on huge page") Reported-by: Jason Gunthorpe <jgg@nvidia.com> Signed-off-by: Pavel Tatashin <pasha.tatashin@soleen.com> --- mm/gup.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-)