LinuxKPI: Factor out vmf_insert_pfn_prot() routine

from GEM and TTM page fault handlers and move it in to base system. This
code is tightly integrated with LKPI mmap support to belong to drm-kmod.

As this routine requires associated vm_object to be locked, it got
additional _locked suffix.

Reviewed by:	hselasky, markj
MFC after:	2 weeks
Differential revision:	https://reviews.freebsd.org/D32068
This commit is contained in:
Vladimir Kondratyev 2021-09-29 23:13:41 +03:00
parent 7d92d48358
commit f6823dac8f
2 changed files with 55 additions and 0 deletions

View file

@ -82,6 +82,9 @@ CTASSERT((VM_PROT_ALL & -(1 << 8)) == 0);
#define VM_FAULT_RETRY (1 << 9)
#define VM_FAULT_FALLBACK (1 << 10)
#define VM_FAULT_ERROR (VM_FAULT_OOM | VM_FAULT_SIGBUS | VM_FAULT_SIGSEGV | \
VM_FAULT_HWPOISON |VM_FAULT_HWPOISON_LARGE | VM_FAULT_FALLBACK)
#define FAULT_FLAG_WRITE (1 << 0)
#define FAULT_FLAG_MKWRITE (1 << 1)
#define FAULT_FLAG_ALLOW_RETRY (1 << 2)
@ -183,6 +186,26 @@ io_remap_pfn_range(struct vm_area_struct *vma,
return (0);
}
vm_fault_t
lkpi_vmf_insert_pfn_prot_locked(struct vm_area_struct *vma, unsigned long addr,
unsigned long pfn, pgprot_t prot);
static inline vm_fault_t
vmf_insert_pfn_prot(struct vm_area_struct *vma, unsigned long addr,
unsigned long pfn, pgprot_t prot)
{
vm_fault_t ret;
VM_OBJECT_WLOCK(vma->vm_obj);
ret = lkpi_vmf_insert_pfn_prot_locked(vma, addr, pfn, prot);
VM_OBJECT_WUNLOCK(vma->vm_obj);
return (ret);
}
#define vmf_insert_pfn_prot(...) \
_Static_assert(false, \
"This function is always called in a loop. Consider using the locked version")
static inline int
apply_to_page_range(struct mm_struct *mm, unsigned long address,
unsigned long size, pte_fn_t fn, void *data)

View file

@ -275,3 +275,35 @@ is_vmalloc_addr(const void *addr)
{
return (vtoslab((vm_offset_t)addr & ~UMA_SLAB_MASK) != NULL);
}
vm_fault_t
lkpi_vmf_insert_pfn_prot_locked(struct vm_area_struct *vma, unsigned long addr,
unsigned long pfn, pgprot_t prot)
{
vm_object_t vm_obj = vma->vm_obj;
vm_page_t page;
vm_pindex_t pindex;
VM_OBJECT_ASSERT_WLOCKED(vm_obj);
pindex = OFF_TO_IDX(addr - vma->vm_start);
if (vma->vm_pfn_count == 0)
vma->vm_pfn_first = pindex;
MPASS(pindex <= OFF_TO_IDX(vma->vm_end));
retry:
page = vm_page_grab(vm_obj, pindex, VM_ALLOC_NOCREAT);
if (page == NULL) {
page = PHYS_TO_VM_PAGE(IDX_TO_OFF(pfn));
if (!vm_page_busy_acquire(page, VM_ALLOC_WAITFAIL))
goto retry;
if (vm_page_insert(page, vm_obj, pindex)) {
vm_page_xunbusy(page);
return (VM_FAULT_OOM);
}
vm_page_valid(page);
}
pmap_page_set_memattr(page, pgprot2cachemode(prot));
vma->vm_pfn_count++;
return (VM_FAULT_NOPAGE);
}