svn commit: r320775 - head/sys/compat/linuxkpi/common/src
Hans Petter Selasky
hselasky at FreeBSD.org
Fri Jul 7 13:44:15 UTC 2017
Author: hselasky
Date: Fri Jul 7 13:44:14 2017
New Revision: 320775
URL: https://svnweb.freebsd.org/changeset/base/320775
Log:
Complete r320189 which allows a NULL VM fault handler in the LinuxKPI.
Instead of mapping a dummy page upon a page fault, map the page
pointed to by the physical address given by IDX_TO_OFF(vmap->vm_pfn).
To simplify the implementation use OBJT_DEVICE to implement our own
linux_cdev_pager_fault() instead of using the existing
linux_cdev_pager_populate().
Some minor code factoring while at it.
Reviewed by: markj @
MFC after: 1 week
Sponsored by: Mellanox Technologies
Modified:
head/sys/compat/linuxkpi/common/src/linux_compat.c
Modified: head/sys/compat/linuxkpi/common/src/linux_compat.c
==============================================================================
--- head/sys/compat/linuxkpi/common/src/linux_compat.c Fri Jul 7 13:15:00 2017 (r320774)
+++ head/sys/compat/linuxkpi/common/src/linux_compat.c Fri Jul 7 13:44:14 2017 (r320775)
@@ -474,11 +474,57 @@ linux_file_free(struct linux_file *filp)
}
static int
+linux_cdev_pager_fault(vm_object_t vm_obj, vm_ooffset_t offset, int prot,
+ vm_page_t *mres)
+{
+ struct vm_area_struct *vmap;
+
+ vmap = linux_cdev_handle_find(vm_obj->handle);
+
+ MPASS(vmap != NULL);
+ MPASS(vmap->vm_private_data == vm_obj->handle);
+
+ if (likely(vmap->vm_ops != NULL && offset < vmap->vm_len)) {
+ vm_paddr_t paddr = IDX_TO_OFF(vmap->vm_pfn) + offset;
+ vm_page_t page;
+
+ if (((*mres)->flags & PG_FICTITIOUS) != 0) {
+ /*
+ * If the passed in result page is a fake
+ * page, update it with the new physical
+ * address.
+ */
+ page = *mres;
+ vm_page_updatefake(page, paddr, vm_obj->memattr);
+ } else {
+ /*
+ * Replace the passed in "mres" page with our
+ * own fake page and free up the all of the
+ * original pages.
+ */
+ VM_OBJECT_WUNLOCK(vm_obj);
+ page = vm_page_getfake(paddr, vm_obj->memattr);
+ VM_OBJECT_WLOCK(vm_obj);
+
+ vm_page_replace_checked(page, vm_obj,
+ (*mres)->pindex, *mres);
+
+ vm_page_lock(*mres);
+ vm_page_free(*mres);
+ vm_page_unlock(*mres);
+ *mres = page;
+ }
+ page->valid = VM_PAGE_BITS_ALL;
+ return (VM_PAGER_OK);
+ }
+ return (VM_PAGER_FAIL);
+}
+
+static int
linux_cdev_pager_populate(vm_object_t vm_obj, vm_pindex_t pidx, int fault_type,
vm_prot_t max_prot, vm_pindex_t *first, vm_pindex_t *last)
{
struct vm_area_struct *vmap;
- struct vm_fault vmf;
int err;
linux_set_current(curthread);
@@ -488,18 +534,20 @@ linux_cdev_pager_populate(vm_object_t vm_obj, vm_pinde
MPASS(vmap != NULL);
MPASS(vmap->vm_private_data == vm_obj->handle);
- /* fill out VM fault structure */
- vmf.virtual_address = (void *)((uintptr_t)pidx << PAGE_SHIFT);
- vmf.flags = (fault_type & VM_PROT_WRITE) ? FAULT_FLAG_WRITE : 0;
- vmf.pgoff = 0;
- vmf.page = NULL;
-
VM_OBJECT_WUNLOCK(vm_obj);
down_write(&vmap->vm_mm->mmap_sem);
- if (unlikely(vmap->vm_ops == NULL || vmap->vm_ops->fault == NULL)) {
+ if (unlikely(vmap->vm_ops == NULL)) {
err = VM_FAULT_SIGBUS;
} else {
+ struct vm_fault vmf;
+
+ /* fill out VM fault structure */
+ vmf.virtual_address = (void *)((uintptr_t)pidx << PAGE_SHIFT);
+ vmf.flags = (fault_type & VM_PROT_WRITE) ? FAULT_FLAG_WRITE : 0;
+ vmf.pgoff = 0;
+ vmf.page = NULL;
+
vmap->vm_pfn_count = 0;
vmap->vm_pfn_pcount = &vmap->vm_pfn_count;
vmap->vm_obj = vm_obj;
@@ -631,10 +679,19 @@ linux_cdev_pager_dtor(void *handle)
linux_cdev_handle_free(vmap);
}
-static struct cdev_pager_ops linux_cdev_pager_ops = {
+static struct cdev_pager_ops linux_cdev_pager_ops[2] = {
+ {
+ /* OBJT_MGTDEVICE */
.cdev_pg_populate = linux_cdev_pager_populate,
.cdev_pg_ctor = linux_cdev_pager_ctor,
.cdev_pg_dtor = linux_cdev_pager_dtor
+ },
+ {
+ /* OBJT_DEVICE */
+ .cdev_pg_fault = linux_cdev_pager_fault,
+ .cdev_pg_ctor = linux_cdev_pager_ctor,
+ .cdev_pg_dtor = linux_cdev_pager_dtor
+ },
};
static int
@@ -1184,8 +1241,15 @@ linux_dev_mmap_single(struct cdev *dev, vm_ooffset_t *
vmap = linux_cdev_handle_insert(vm_private_data, vmap);
- *object = cdev_pager_allocate(vm_private_data, OBJT_MGTDEVICE,
- &linux_cdev_pager_ops, size, nprot, *offset, curthread->td_ucred);
+ if (vmap->vm_ops->fault == NULL) {
+ *object = cdev_pager_allocate(vm_private_data, OBJT_DEVICE,
+ &linux_cdev_pager_ops[1], size, nprot, *offset,
+ curthread->td_ucred);
+ } else {
+ *object = cdev_pager_allocate(vm_private_data, OBJT_MGTDEVICE,
+ &linux_cdev_pager_ops[0], size, nprot, *offset,
+ curthread->td_ucred);
+ }
if (*object == NULL) {
linux_cdev_handle_remove(vmap);
@@ -1196,7 +1260,8 @@ linux_dev_mmap_single(struct cdev *dev, vm_ooffset_t *
struct sglist *sg;
sg = sglist_alloc(1, M_WAITOK);
- sglist_append_phys(sg, (vm_paddr_t)vmap->vm_pfn << PAGE_SHIFT, vmap->vm_len);
+ sglist_append_phys(sg,
+ (vm_paddr_t)vmap->vm_pfn << PAGE_SHIFT, vmap->vm_len);
*object = vm_pager_allocate(OBJT_SG, sg, vmap->vm_len,
nprot, 0, curthread->td_ucred);
More information about the svn-src-all
mailing list