On Sat, 4 Oct 2025 11:30:44 +0200 Loïc Molinari <[email protected]> wrote:
> This gives the mm subsystem the ability to propose the insertion of > PUD or PMD-sized mappings for the faulting addresses. > > On builds with CONFIG_TRANSPARENT_HUGEPAGE enabled, if the mmap() user > address is aligned to a huge page size, if the GEM object is backed by > shmem buffers on mount points setting the 'huge=' option and if the > shmem backing store manages to allocate a huge folio, the CPU mapping > will 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. > > v2: > - set ret to VM_FAULT_FALLBACK in default switch statement > - ifdef out paddr declaration > > Signed-off-by: Loïc Molinari <[email protected]> > Reviewed-by: Boris Brezillon <[email protected]> > Reported-by: kernel test robot <[email protected]> > Closes: > https://lore.kernel.org/oe-kbuild-all/[email protected]/ > Closes: > https://lore.kernel.org/oe-kbuild-all/[email protected]/ > Closes: > https://lore.kernel.org/oe-kbuild-all/[email protected]/ I'm not sure those Closes/Reported-by tags are needed when you fix bugs introduced in a previous revisions of the patchset. > --- > drivers/gpu/drm/drm_gem_shmem_helper.c | 56 ++++++++++++++++++++++++-- > 1 file changed, 52 insertions(+), 4 deletions(-) > > diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c > b/drivers/gpu/drm/drm_gem_shmem_helper.c > index 50594cf8e17c..22c4b09e10a3 100644 > --- a/drivers/gpu/drm/drm_gem_shmem_helper.c > +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c > @@ -573,7 +573,8 @@ int drm_gem_shmem_dumb_create(struct drm_file *file, > struct drm_device *dev, > } > EXPORT_SYMBOL_GPL(drm_gem_shmem_dumb_create); > > -static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf) > +static vm_fault_t drm_gem_shmem_huge_fault(struct vm_fault *vmf, > + unsigned int order) > { > struct vm_area_struct *vma = vmf->vma; > struct drm_gem_object *obj = vma->vm_private_data; > @@ -582,6 +583,10 @@ static vm_fault_t drm_gem_shmem_fault(struct vm_fault > *vmf) > vm_fault_t ret; > struct page *page; > pgoff_t page_offset; > + unsigned long pfn; > +#if defined(CONFIG_ARCH_SUPPORTS_PMD_PFNMAP) || > defined(CONFIG_ARCH_SUPPORTS_PUD_PFNMAP) > + unsigned long paddr; > +#endif > > /* We don't use vmf->pgoff since that has the fake offset */ > page_offset = (vmf->address - vma->vm_start) >> PAGE_SHIFT; > @@ -592,17 +597,57 @@ static vm_fault_t drm_gem_shmem_fault(struct vm_fault > *vmf) > drm_WARN_ON_ONCE(obj->dev, !shmem->pages) || > shmem->madv < 0) { > ret = VM_FAULT_SIGBUS; > - } else { > - page = shmem->pages[page_offset]; > + goto out; > + } > > - ret = vmf_insert_pfn(vma, vmf->address, page_to_pfn(page)); > + page = shmem->pages[page_offset]; > + pfn = page_to_pfn(page); > + > + switch (order) { > + case 0: > + ret = vmf_insert_pfn(vma, vmf->address, pfn); > + break; > + > +#ifdef CONFIG_ARCH_SUPPORTS_PMD_PFNMAP > + case PMD_ORDER: > + paddr = pfn << PAGE_SHIFT; > + if (((vmf->address & ~PMD_MASK) == (paddr & ~PMD_MASK)) && > + (folio_order(page_folio(page)) == PMD_ORDER)) > + ret = vmf_insert_pfn_pmd( > + vmf, pfn & (PMD_MASK >> PAGE_SHIFT), false); > + else > + ret = VM_FAULT_FALLBACK; > + break; > +#endif > + > +#ifdef CONFIG_ARCH_SUPPORTS_PUD_PFNMAP > + case PUD_ORDER: > + paddr = pfn << PAGE_SHIFT; > + if (((vmf->address & ~PUD_MASK) == (paddr & ~PUD_MASK)) && > + (folio_order(page_folio(page)) == PUD_ORDER)) > + ret = vmf_insert_pfn_pud( > + vmf, pfn & (PUD_MASK >> PAGE_SHIFT), false); > + else > + ret = VM_FAULT_FALLBACK; > + break; > +#endif > + > + default: > + ret = VM_FAULT_FALLBACK; > + break; > } > > + out: > dma_resv_unlock(shmem->base.resv); > > return ret; > } > > +static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf) > +{ > + return drm_gem_shmem_huge_fault(vmf, 0); > +} > + > static void drm_gem_shmem_vm_open(struct vm_area_struct *vma) > { > struct drm_gem_object *obj = vma->vm_private_data; > @@ -639,6 +684,9 @@ static void drm_gem_shmem_vm_close(struct vm_area_struct > *vma) > > const struct vm_operations_struct drm_gem_shmem_vm_ops = { > .fault = drm_gem_shmem_fault, > +#if defined(CONFIG_ARCH_SUPPORTS_PMD_PFNMAP) || > defined(CONFIG_ARCH_SUPPORTS_PUD_PFNMAP) > + .huge_fault = drm_gem_shmem_huge_fault, > +#endif > .open = drm_gem_shmem_vm_open, > .close = drm_gem_shmem_vm_close, > };
