drm/pagemap: Allocate folios when possible

If the order is greater than zero, allocate a folio when populating the
RAM PFNs instead of allocating individual pages one after the other. For
example if 2MB folios are used instead of 4KB pages, this reduces the
number of calls to the allocation API by 512.

v2:
- Use page order instead of extra argument (Matthew Brost)
- Allocate with folio_alloc() (Matthew Brost)
- Loop for mpages and free_pages based on order (Matthew Brost)

v3:
- Fix loops in drm_pagemap_migrate_populate_ram_pfn() (Matthew Brost)

v4:
- Use folio_trylock(), set local variable to NULL (Matthew Brost)

Cc: Matthew Brost <matthew.brost@intel.com>
Reviewed-by: Matthew Brost <matthew.brost@intel.com>
Acked-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Acked-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://lore.kernel.org/r/20250805140028.599361-5-francois.dugast@intel.com
Signed-off-by: Francois Dugast <francois.dugast@intel.com>
This commit is contained in:
Francois Dugast
2025-08-05 15:59:05 +02:00
parent d755ff6063
commit ddeda61360

View File

@@ -460,54 +460,80 @@ static int drm_pagemap_migrate_populate_ram_pfn(struct vm_area_struct *vas,
{
unsigned long i;
for (i = 0; i < npages; ++i, addr += PAGE_SIZE) {
struct page *page, *src_page;
for (i = 0; i < npages;) {
struct page *page = NULL, *src_page;
struct folio *folio;
unsigned int order = 0;
if (!(src_mpfn[i] & MIGRATE_PFN_MIGRATE))
continue;
goto next;
src_page = migrate_pfn_to_page(src_mpfn[i]);
if (!src_page)
continue;
goto next;
if (fault_page) {
if (src_page->zone_device_data !=
fault_page->zone_device_data)
continue;
goto next;
}
if (vas)
page = alloc_page_vma(GFP_HIGHUSER, vas, addr);
else
page = alloc_page(GFP_HIGHUSER);
order = folio_order(page_folio(src_page));
if (!page)
/* TODO: Support fallback to single pages if THP allocation fails */
if (vas)
folio = vma_alloc_folio(GFP_HIGHUSER, order, vas, addr);
else
folio = folio_alloc(GFP_HIGHUSER, order);
if (!folio)
goto free_pages;
page = folio_page(folio, 0);
mpfn[i] = migrate_pfn(page_to_pfn(page));
next:
if (page)
addr += page_size(page);
else
addr += PAGE_SIZE;
i += NR_PAGES(order);
}
for (i = 0; i < npages; ++i) {
for (i = 0; i < npages;) {
struct page *page = migrate_pfn_to_page(mpfn[i]);
unsigned int order = 0;
if (!page)
continue;
goto next_lock;
WARN_ON_ONCE(!trylock_page(page));
++*mpages;
WARN_ON_ONCE(!folio_trylock(page_folio(page)));
order = folio_order(page_folio(page));
*mpages += NR_PAGES(order);
next_lock:
i += NR_PAGES(order);
}
return 0;
free_pages:
for (i = 0; i < npages; ++i) {
for (i = 0; i < npages;) {
struct page *page = migrate_pfn_to_page(mpfn[i]);
unsigned int order = 0;
if (!page)
continue;
goto next_put;
put_page(page);
mpfn[i] = 0;
order = folio_order(page_folio(page));
next_put:
i += NR_PAGES(order);
}
return -ENOMEM;
}