Skip to content

Commit

Permalink
mm/memremap.c: take a pgmap reference on page allocation
Browse files Browse the repository at this point in the history
ZONE_DEVICE pages have a struct dev_pagemap which is allocated by a
driver.  When the struct page is first allocated by the kernel in
memremap_pages() a reference is taken on the associated pagemap to ensure
it is not freed prior to the pages being freed.

Prior to 27674ef ("mm: remove the extra ZONE_DEVICE struct page
refcount") pages were considered free and returned to the driver when the
reference count dropped to one.  However the pagemap reference was not
dropped until the page reference count hit zero.  This would occur as part
of the final put_page() in memunmap_pages() which would wait for all pages
to be freed prior to returning.

When the extra refcount was removed the pagemap reference was no longer
being dropped in put_page().  Instead memunmap_pages() was changed to
explicitly drop the pagemap references.  This means that memunmap_pages()
can complete even though pages are still mapped by the kernel which can
lead to kernel crashes, particularly if a driver frees the pagemap.

To fix this drivers should take a pagemap reference when allocating the
page.  This reference can then be returned when the page is freed.

Link: https://lkml.kernel.org/r/12d155ec727935ebfbb4d639a03ab374917ea51b.1664366292.git-series.apopple@nvidia.com
Signed-off-by: Alistair Popple <[email protected]>
Fixes: 27674ef ("mm: remove the extra ZONE_DEVICE struct page refcount")
Cc: Jason Gunthorpe <[email protected]>
Cc: Felix Kuehling <[email protected]>
Cc: Alex Deucher <[email protected]>
Cc: Christian König <[email protected]>
Cc: Ben Skeggs <[email protected]>
Cc: Lyude Paul <[email protected]>
Cc: Ralph Campbell <[email protected]>
Cc: Alex Sierra <[email protected]>
Cc: John Hubbard <[email protected]>
Cc: Dan Williams <[email protected]>

Cc: David Hildenbrand <[email protected]>
Cc: "Huang, Ying" <[email protected]>
Cc: Matthew Wilcox <[email protected]>
Cc: Michael Ellerman <[email protected]>
Cc: Yang Shi <[email protected]>
Cc: Zi Yan <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
  • Loading branch information
apopple-nvidia authored and akpm00 committed Oct 13, 2022
1 parent ef23345 commit 0dc45ca
Showing 1 changed file with 19 additions and 6 deletions.
25 changes: 19 additions & 6 deletions mm/memremap.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,11 @@ void memunmap_pages(struct dev_pagemap *pgmap)
int i;

percpu_ref_kill(&pgmap->ref);
for (i = 0; i < pgmap->nr_range; i++)
percpu_ref_put_many(&pgmap->ref, pfn_len(pgmap, i));
if (pgmap->type != MEMORY_DEVICE_PRIVATE &&
pgmap->type != MEMORY_DEVICE_COHERENT)
for (i = 0; i < pgmap->nr_range; i++)
percpu_ref_put_many(&pgmap->ref, pfn_len(pgmap, i));

wait_for_completion(&pgmap->done);

for (i = 0; i < pgmap->nr_range; i++)
Expand Down Expand Up @@ -264,7 +267,9 @@ static int pagemap_range(struct dev_pagemap *pgmap, struct mhp_params *params,
memmap_init_zone_device(&NODE_DATA(nid)->node_zones[ZONE_DEVICE],
PHYS_PFN(range->start),
PHYS_PFN(range_len(range)), pgmap);
percpu_ref_get_many(&pgmap->ref, pfn_len(pgmap, range_id));
if (pgmap->type != MEMORY_DEVICE_PRIVATE &&
pgmap->type != MEMORY_DEVICE_COHERENT)
percpu_ref_get_many(&pgmap->ref, pfn_len(pgmap, range_id));
return 0;

err_add_memory:
Expand Down Expand Up @@ -502,16 +507,24 @@ void free_zone_device_page(struct page *page)
page->mapping = NULL;
page->pgmap->ops->page_free(page);

/*
* Reset the page count to 1 to prepare for handing out the page again.
*/
if (page->pgmap->type != MEMORY_DEVICE_PRIVATE &&
page->pgmap->type != MEMORY_DEVICE_COHERENT)
/*
* Reset the page count to 1 to prepare for handing out the page
* again.
*/
set_page_count(page, 1);
else
put_dev_pagemap(page->pgmap);
}

void zone_device_page_init(struct page *page)
{
/*
* Drivers shouldn't be allocating pages after calling
* memunmap_pages().
*/
WARN_ON_ONCE(!percpu_ref_tryget_live(&page->pgmap->ref));
set_page_count(page, 1);
lock_page(page);
}
Expand Down

0 comments on commit 0dc45ca

Please sign in to comment.