Page MenuHomeFreeBSD

D59883.1794327999.diff
No OneTemporary

Authored By
Unknown
Size
5 KB
Referenced Files
None
Subscribers
None

D59883.1794327999.diff

diff --git a/sys/compat/linuxkpi/common/include/linux/mm.h b/sys/compat/linuxkpi/common/include/linux/mm.h
--- a/sys/compat/linuxkpi/common/include/linux/mm.h
+++ b/sys/compat/linuxkpi/common/include/linux/mm.h
@@ -221,6 +221,9 @@
lkpi_vmf_insert_pfn_prot_locked(struct vm_area_struct *vma, unsigned long addr,
unsigned long pfn, pgprot_t prot);
+vm_fault_t lkpi_vmf_insert_special_pte_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)
diff --git a/sys/compat/linuxkpi/common/src/linux_page.c b/sys/compat/linuxkpi/common/src/linux_page.c
--- a/sys/compat/linuxkpi/common/src/linux_page.c
+++ b/sys/compat/linuxkpi/common/src/linux_page.c
@@ -647,6 +647,62 @@
return (0);
}
+/*
+ * A special PTE is an unmanaged mapping, with no PV tracking for
+ * the target page.
+ *
+ * The function inserts a fake page with phys_addr set to the requested
+ * pfn into the vma backing object. It is the caller's duty to ensure
+ * that the mappings are removed before the real page is reused. The
+ * real page might belong to a different object, in which case the fake
+ * page's phys_addr equals that page's phys_addr, or the fake page may
+ * alias it through an aperture.
+ */
+vm_fault_t
+lkpi_vmf_insert_special_pte_locked(struct vm_area_struct *vma,
+ unsigned long addr, unsigned long pfn, pgprot_t prot)
+{
+ struct pctrie_iter pages;
+ vm_object_t vm_obj;
+ vm_page_t fake_page, page;
+ vm_pindex_t pindex;
+
+ if (addr < vma->vm_start || addr >= vma->vm_end)
+ return (VM_FAULT_SIGBUS);
+
+ vm_obj = vma->vm_obj;
+ VM_OBJECT_ASSERT_WLOCKED(vm_obj);
+ MPASS(vm_obj->type == OBJT_MGTDEVICE);
+
+ vm_page_iter_init(&pages, vm_obj);
+ pindex = OFF_TO_IDX(addr - vma->vm_start);
+ if (vma->vm_pfn_count == 0)
+ vma->vm_pfn_first = pindex;
+
+ page = vm_page_grab_iter(vm_obj, pindex, VM_ALLOC_NOCREAT, &pages);
+ if (page == NULL) {
+ fake_page = vm_page_getfake_nowait(IDX_TO_OFF(pfn),
+ pgprot2cachemode(prot));
+ if (fake_page == NULL)
+ return (VM_FAULT_OOM);
+ fake_page->oflags |= VPO_FAKE_OWNED;
+ if (vm_page_iter_insert(fake_page, vm_obj, pindex, &pages) !=
+ 0) {
+ vm_page_putfake(fake_page);
+ return (VM_FAULT_OOM);
+ }
+ vm_page_valid(fake_page);
+ } else {
+ /*
+ * A page is already resident at pindex. Do not check
+ * that it maps the same pfn; the first insert wins.
+ */
+ pmap_page_set_memattr(page, pgprot2cachemode(prot));
+ }
+ vma->vm_pfn_count++;
+ return (VM_FAULT_NOPAGE);
+}
+
int
lkpi_io_mapping_map_user(struct io_mapping *iomap,
struct vm_area_struct *vma, unsigned long addr,
diff --git a/sys/vm/device_pager.c b/sys/vm/device_pager.c
--- a/sys/vm/device_pager.c
+++ b/sys/vm/device_pager.c
@@ -295,6 +295,10 @@
{
pmap_remove_all(m);
vm_page_iter_remove(pages, m);
+ if ((m->oflags & VPO_FAKE_OWNED) != 0) {
+ MPASS((m->flags & PG_FICTITIOUS) != 0);
+ vm_page_putfake(m);
+ }
}
void
diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c
--- a/sys/vm/vm_object.c
+++ b/sys/vm/vm_object.c
@@ -885,7 +885,10 @@
(p->ref_count & VPRC_OBJREF) != 0,
("%s: page %p is inconsistent", __func__, p));
p->object = NULL;
- if (vm_page_drop(p, VPRC_OBJREF) == VPRC_OBJREF) {
+ if ((p->oflags & VPO_FAKE_OWNED) != 0) {
+ MPASS((p->flags & PG_FICTITIOUS) != 0);
+ vm_page_putfake(p);
+ } else if (vm_page_drop(p, VPRC_OBJREF) == VPRC_OBJREF) {
KASSERT((object->flags & OBJ_UNMANAGED) != 0 ||
vm_page_astate_load(p).queue != PQ_NONE,
("%s: page %p does not belong to a queue", __func__, p));
diff --git a/sys/vm/vm_page.h b/sys/vm/vm_page.h
--- a/sys/vm/vm_page.h
+++ b/sys/vm/vm_page.h
@@ -286,6 +286,8 @@
#define VPO_SWAPSLEEP 0x02 /* waiting for swap to finish */
#define VPO_UNMANAGED 0x04 /* no PV management for page */
#define VPO_SWAPINPROG 0x08 /* swap I/O in progress on page */
+#define VPO_FAKE_OWNED 0x10 /* Fake page owned by the object,
+ putfake on removal */
/*
* Busy page implementation details.
@@ -592,6 +594,7 @@
int vm_page_free_pages_toq(struct spglist *free, bool update_wire_count);
void vm_page_free_zero(vm_page_t m);
vm_page_t vm_page_getfake(vm_paddr_t paddr, vm_memattr_t memattr);
+vm_page_t vm_page_getfake_nowait(vm_paddr_t paddr, vm_memattr_t memattr);
int vm_page_grab_zero_partial(vm_object_t object, vm_pindex_t pindex, int base,
int end);
vm_page_t vm_page_grab(vm_object_t, vm_pindex_t, int);
diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c
--- a/sys/vm/vm_page.c
+++ b/sys/vm/vm_page.c
@@ -1323,6 +1323,17 @@
#endif
}
+static vm_page_t
+vm_page_getfake_mallocf(vm_paddr_t paddr, vm_memattr_t memattr, int mallocf)
+{
+ vm_page_t m;
+
+ m = uma_zalloc(fakepg_zone, mallocf | M_ZERO);
+ if (m != NULL)
+ vm_page_initfake(m, paddr, memattr);
+ return (m);
+}
+
/*
* vm_page_getfake:
*
@@ -1333,11 +1344,13 @@
vm_page_t
vm_page_getfake(vm_paddr_t paddr, vm_memattr_t memattr)
{
- vm_page_t m;
+ return (vm_page_getfake_mallocf(paddr, memattr, M_WAITOK));
+}
- m = uma_zalloc(fakepg_zone, M_WAITOK | M_ZERO);
- vm_page_initfake(m, paddr, memattr);
- return (m);
+vm_page_t
+vm_page_getfake_nowait(vm_paddr_t paddr, vm_memattr_t memattr)
+{
+ return (vm_page_getfake_mallocf(paddr, memattr, M_NOWAIT));
}
void

File Metadata

Mime Type
text/plain
Expires
Tue, Nov 10, 4:26 PM (1 h, 17 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41643338
Default Alt Text
D59883.1794327999.diff (5 KB)

Event Timeline