Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

drm/shmem-helper: Map huge pages in fault handler

Attempt a PMD sized PFN insertion into the VMA if the faulty address
of the fault handler is part of a huge page.

On builds with CONFIG_TRANSPARENT_HUGEPAGE enabled, if the mmap() user
address is PMD size aligned, if the GEM object is backed by shmem
buffers on mountpoints setting the 'huge=' option and if the shmem
backing store manages to allocate a huge folio, CPU mapping would then
benefit from significantly increased memcpy() performance. When these
conditions are met on a system with 2 MiB huge pages, an aligned copy
of 2 MiB would raise a single page fault instead of 4096.

v4:
- implement map_pages instead of huge_fault

v6:
- get rid of map_pages handler for now (keep it for another series
along with arm64 contpte support)

v11:
- remove page fault validity check helper
- rename drm_gem_shmem_map_pmd() to drm_gem_shmem_try_map_pmd()
- add Boris R-b

v12:
- move up ret var decl in fault handler to minimize diff

Signed-off-by: Loïc Molinari <loic.molinari@collabora.com>
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Link: https://patch.msgid.link/20251205182231.194072-3-loic.molinari@collabora.com
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>

authored by

Loïc Molinari and committed by
Boris Brezillon
211b9a39 9d2d4902

+32 -5
+32 -5
drivers/gpu/drm/drm_gem_shmem_helper.c
··· 567 567 } 568 568 EXPORT_SYMBOL_GPL(drm_gem_shmem_dumb_create); 569 569 570 + static bool drm_gem_shmem_try_map_pmd(struct vm_fault *vmf, unsigned long addr, 571 + struct page *page) 572 + { 573 + #ifdef CONFIG_ARCH_SUPPORTS_PMD_PFNMAP 574 + unsigned long pfn = page_to_pfn(page); 575 + unsigned long paddr = pfn << PAGE_SHIFT; 576 + bool aligned = (addr & ~PMD_MASK) == (paddr & ~PMD_MASK); 577 + 578 + if (aligned && 579 + pmd_none(*vmf->pmd) && 580 + folio_test_pmd_mappable(page_folio(page))) { 581 + pfn &= PMD_MASK >> PAGE_SHIFT; 582 + if (vmf_insert_pfn_pmd(vmf, pfn, false) == VM_FAULT_NOPAGE) 583 + return true; 584 + } 585 + #endif 586 + 587 + return false; 588 + } 589 + 570 590 static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf) 571 591 { 572 592 struct vm_area_struct *vma = vmf->vma; ··· 594 574 struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); 595 575 loff_t num_pages = obj->size >> PAGE_SHIFT; 596 576 vm_fault_t ret; 597 - struct page *page; 577 + struct page **pages = shmem->pages; 598 578 pgoff_t page_offset; 579 + unsigned long pfn; 599 580 600 581 /* Offset to faulty address in the VMA. */ 601 582 page_offset = vmf->pgoff - vma->vm_pgoff; ··· 607 586 drm_WARN_ON_ONCE(obj->dev, !shmem->pages) || 608 587 shmem->madv < 0) { 609 588 ret = VM_FAULT_SIGBUS; 610 - } else { 611 - page = shmem->pages[page_offset]; 612 - 613 - ret = vmf_insert_pfn(vma, vmf->address, page_to_pfn(page)); 589 + goto out; 614 590 } 615 591 592 + if (drm_gem_shmem_try_map_pmd(vmf, vmf->address, pages[page_offset])) { 593 + ret = VM_FAULT_NOPAGE; 594 + goto out; 595 + } 596 + 597 + pfn = page_to_pfn(pages[page_offset]); 598 + ret = vmf_insert_pfn(vma, vmf->address, pfn); 599 + 600 + out: 616 601 dma_resv_unlock(shmem->base.resv); 617 602 618 603 return ret;