Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/uebayasi-xip]: src/sys/miscfs/genfs Implement XIP "putpages". Invalidat...
details: https://anonhg.NetBSD.org/src/rev/40f9c766165f
branches: uebayasi-xip
changeset: 751802:40f9c766165f
user: uebayasi <uebayasi%NetBSD.org@localhost>
date: Sun Sep 26 07:06:57 2010 +0000
description:
Implement XIP "putpages". Invalidate MMU mappings of pages at the
request of PGO_FREE. PGO_DEACTIVATE and PGO_CLEANIT do nothing, because
XIP pages are neither queued nor writable.
Allocate read-only "zero" page per vnode. Put it at offset 0 of vnode's
uvm_object. This per-vnode "zero" page is mapped to all hole pages of
the vnode. If one of its mapped pages are forced to be PGO_FREE'ed,
all the mappings are invalidated.
diffstat:
sys/miscfs/genfs/genfs_io.c | 187 +++++++++++++++++++++++++++++++++++++------
1 files changed, 160 insertions(+), 27 deletions(-)
diffs (273 lines):
diff -r a9240d2c8920 -r 40f9c766165f sys/miscfs/genfs/genfs_io.c
--- a/sys/miscfs/genfs/genfs_io.c Sun Sep 26 06:38:36 2010 +0000
+++ b/sys/miscfs/genfs/genfs_io.c Sun Sep 26 07:06:57 2010 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: genfs_io.c,v 1.36.2.23 2010/09/26 06:38:36 uebayasi Exp $ */
+/* $NetBSD: genfs_io.c,v 1.36.2.24 2010/09/26 07:06:57 uebayasi Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1993
@@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: genfs_io.c,v 1.36.2.23 2010/09/26 06:38:36 uebayasi Exp $");
+__KERNEL_RCSID(0, "$NetBSD: genfs_io.c,v 1.36.2.24 2010/09/26 07:06:57 uebayasi Exp $");
#include "opt_xip.h"
@@ -62,6 +62,10 @@
static int genfs_do_getpages(void *);
#ifdef XIP
static int genfs_do_getpages_xip(void *);
+static int genfs_do_getpages_xip1(struct vnode *, voff_t, struct vm_page **,
+ int *, int, vm_prot_t, int, int);
+static int genfs_do_putpages_xip(struct vnode *, off_t, off_t, int,
+ struct vm_page **);
#endif
static int genfs_do_directio(struct vmspace *, vaddr_t, size_t, struct vnode *,
off_t, enum uio_rw);
@@ -128,9 +132,8 @@
int a_advice;
int a_flags;
} */ * const ap = v;
- struct vnode * const vp = ap->a_vp;
- if ((vp->v_vflag & VV_XIP) != 0)
+ if ((ap->a_vp->v_vflag & VV_XIP) != 0)
return genfs_do_getpages_xip(v);
else
#endif
@@ -754,20 +757,6 @@
}
#ifdef XIP
-static struct uvm_object xip_zero_obj;
-static struct vm_page *xip_zero_page;
-
-static int
-xip_zero_page_init(void)
-{
-
- UVM_OBJ_INIT(&xip_zero_obj, NULL, 0);
- xip_zero_page = uvm_pagealloc(&xip_zero_obj, 0, NULL, UVM_PGA_ZERO);
- KASSERT(xip_zero_page != NULL);
- uvm_pagewire(xip_zero_page);
- return 0;
-}
-
/*
* genfs_do_getpages_xip
* Return "direct pages" of XIP vnode. The block addresses of XIP
@@ -791,18 +780,36 @@
int a_flags;
} */ * const ap = v;
- struct vnode * const vp = ap->a_vp;
- int *npagesp = ap->a_count;
- const off_t offset = ap->a_offset;
- struct vm_page **pps = ap->a_m;
+ return genfs_do_getpages_xip1(
+ ap->a_vp,
+ ap->a_offset,
+ ap->a_m,
+ ap->a_count,
+ ap->a_centeridx,
+ ap->a_access_type,
+ ap->a_advice,
+ ap->a_flags);
+}
+
+static int
+genfs_do_getpages_xip1(
+ struct vnode *vp,
+ voff_t offset,
+ struct vm_page **pps,
+ int *npagesp,
+ int centeridx,
+ vm_prot_t access_type,
+ int advice,
+ int flags)
+{
struct uvm_object * const uobj = &vp->v_uobj;
- const int flags = ap->a_flags;
int error;
off_t eof, sbkoff, ebkoff, off;
int npages;
int fs_bshift, fs_bsize, dev_bshift, dev_bsize;
int i;
+ struct vm_page *zero_page;
UVMHIST_FUNC("genfs_do_getpages_xip"); UVMHIST_CALLED(ubchist);
@@ -820,6 +827,8 @@
ebkoff = ((offset + PAGE_SIZE * npages) + (fs_bsize - 1)) &
~(fs_bsize - 1);
+ zero_page = NULL;
+
UVMHIST_LOG(ubchist, "xip npages=%d sbkoff=%lx ebkoff=%lx",
npages, (long)sbkoff, (long)ebkoff, 0);
@@ -847,10 +856,19 @@
* allocated and linearly ordered by physical address.
*/
if (blkno < 0) {
- static ONCE_DECL(xip_zero_page_inited);
+ zero_page = uvm_pagelookup(uobj, 0);
- RUN_ONCE(&xip_zero_page_inited, xip_zero_page_init);
- pps[i] = xip_zero_page;
+ if (zero_page == NULL) {
+ mutex_enter(&uobj->vmobjlock);
+ zero_page = uvm_pagealloc(uobj, 0, NULL,
+ UVM_PGA_ZERO);
+ mutex_exit(&uobj->vmobjlock);
+ KASSERT(zero_page != NULL);
+ mutex_enter(&uvm_pageqlock);
+ uvm_pagewire(zero_page);
+ mutex_exit(&uvm_pageqlock);
+ }
+ pps[i] = zero_page;
} else {
struct vm_physseg *seg;
daddr_t seg_off;
@@ -885,7 +903,7 @@
for (i = 0; i < npages; i++) {
struct vm_page *pg = pps[i];
- if (pg == xip_zero_page) {
+ if (pg == zero_page) {
} else {
KASSERT((pg->flags & PG_BUSY) == 0);
KASSERT((pg->flags & PG_RDONLY) != 0);
@@ -964,6 +982,12 @@
int a_flags;
} */ * const ap = v;
+#ifdef XIP
+ if ((ap->a_vp->v_vflag & VV_XIP) != 0)
+ return genfs_do_putpages_xip(ap->a_vp, ap->a_offlo, ap->a_offhi,
+ ap->a_flags, NULL);
+ else
+#endif
return genfs_do_putpages(ap->a_vp, ap->a_offlo, ap->a_offhi,
ap->a_flags, NULL);
}
@@ -1429,6 +1453,115 @@
return (error);
}
+#ifdef XIP
+int
+genfs_do_putpages_xip(struct vnode *vp, off_t startoff, off_t endoff,
+ int flags, struct vm_page **busypg)
+{
+ struct uvm_object *uobj = &vp->v_uobj;
+ struct genfs_node * const gp = VTOG(vp);
+
+ UVMHIST_FUNC("genfs_do_putpages_xip"); UVMHIST_CALLED(ubchist);
+
+ KASSERT(mutex_owned(&uobj->vmobjlock));
+ KASSERT((vp->v_iflag & VI_ONWORKLST) == 0);
+ KASSERT(vp->v_numoutput == 0);
+ KASSERT(gp->g_dirtygen == 0);
+
+ UVMHIST_LOG(ubchist, "vp %p pages %d off 0x%x len 0x%x",
+ vp, uobj->uo_npages, startoff, endoff - startoff);
+
+ /*
+ * XIP pages are read-only, and never become dirty. They're also never
+ * queued. PGO_DEACTIVATE and PGO_CLEANIT are meaningless for XIP
+ * pages, so we ignore them.
+ */
+ if ((flags & PGO_FREE) == 0)
+ goto done;
+
+ /*
+ * For PGO_FREE (or (PGO_CLEANIT | PGO_FREE)), we invalidate MMU
+ * mappings of both XIP pages and XIP zero pages.
+ *
+ * Zero page is freed when one of its mapped offset is freed, even if
+ * one file (vnode) has many holes and mapping its zero page to all
+ * of those hole pages.
+ *
+ * We don't know which pages are currently mapped in the given vp,
+ * because XIP pages are not added to vnode. What we can is to locate
+ * pages by querying the filesystem as done in getpages. Call
+ * genfs_do_getpages_xip().
+ */
+
+ off_t off, eof;
+ struct vm_page *zero_page;
+ bool put_zero_page;
+
+ off = trunc_page(startoff);
+ if (endoff == 0 || (flags & PGO_ALLPAGES))
+ GOP_SIZE(vp, vp->v_size, &eof, GOP_SIZE_MEM);
+ else
+ eof = endoff;
+
+ zero_page = uvm_pagelookup(uobj, 0);
+ KASSERT(zero_page != NULL || uobj->uo_npages == 0);
+ KASSERT(zero_page == NULL || uobj->uo_npages == 1);
+ put_zero_page = false;
+
+ while (off < eof) {
+ int npages, orignpages, error, i;
+ struct vm_page *pgs[maxpages], *pg;
+
+ npages = round_page(eof - off) >> PAGE_SHIFT;
+ if (npages > maxpages)
+ npages = maxpages;
+
+ orignpages = npages;
+ error = genfs_do_getpages_xip1(vp, off, pgs, &npages, 0,
+ VM_PROT_ALL, 0, PGO_LOCKED);
+ KASSERT(error == 0);
+ KASSERT(npages == orignpages);
+ for (i = 0; i < npages; i++) {
+ pg = pgs[i];
+ if (pg == NULL || pg == PGO_DONTCARE)
+ continue;
+ if (pg == zero_page) {
+ put_zero_page = true;
+ } else {
+ /*
+ * Freeing normal XIP pages; nothing to do.
+ */
+ pmap_page_protect(pg, VM_PROT_NONE);
+ KASSERT((pg->flags & PG_BUSY) != 0);
+ KASSERT((pg->flags & PG_RDONLY) != 0);
+ KASSERT((pg->flags & PG_CLEAN) != 0);
+ KASSERT((pg->flags & PG_FAKE) == 0);
+ KASSERT((pg->pqflags & PQ_FIXED) != 0);
+ pg->flags &= ~PG_BUSY;
+ }
+ }
+ off += npages << PAGE_SHIFT;
+ }
+
+ if (put_zero_page) {
+ /*
+ * Freeing an XIP zero page.
+ */
+ pmap_page_protect(zero_page, VM_PROT_NONE);
+ mutex_enter(&uvm_pageqlock);
+ uvm_pageunwire(zero_page);
+ mutex_exit(&uvm_pageqlock);
+ uvm_pagefree(zero_page);
+ }
+
+ KASSERT(uobj->uo_npages == 0);
+
+done:
+ mutex_exit(&uobj->vmobjlock);
+ return 0;
+}
+#endif
+
int
genfs_gop_write(struct vnode *vp, struct vm_page **pgs, int npages, int flags)
{
Home |
Main Index |
Thread Index |
Old Index