* rework the page cache interaction a bit: cache metadata in the

kernel and flush it out all at once instead of continuous updating
* add support for delivering notifications to the file server about
  when a page was written to (but disabled by default for now).  the
  file server can use this to request flushing or invalidating the
  kernel page cache
This commit is contained in:
pooka 2007-03-20 10:21:58 +00:00
parent d60cbb92f9
commit 8d9c021816
7 changed files with 324 additions and 67 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: puffs_msgif.c,v 1.20 2007/03/14 12:13:58 pooka Exp $ */
/* $NetBSD: puffs_msgif.c,v 1.21 2007/03/20 10:21:58 pooka Exp $ */
/*
* Copyright (c) 2005, 2006, 2007 Antti Kantee. All Rights Reserved.
@ -33,7 +33,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: puffs_msgif.c,v 1.20 2007/03/14 12:13:58 pooka Exp $");
__KERNEL_RCSID(0, "$NetBSD: puffs_msgif.c,v 1.21 2007/03/20 10:21:58 pooka Exp $");
#include <sys/param.h>
#include <sys/fstrans.h>
@ -242,6 +242,21 @@ puffs_vntouser_faf(struct puffs_mount *pmp, int optype,
(void)touser(pmp, ppark, 0, NULL, NULL);
}
void
puffs_cacheop(struct puffs_mount *pmp, struct puffs_park *ppark,
struct puffs_cacheinfo *pcinfo, size_t pcilen, void *cookie)
{
ppark->park_preq = (struct puffs_req *)pcinfo;
ppark->park_preq->preq_opclass = PUFFSOP_CACHE | PUFFSOPFLAG_FAF;
ppark->park_preq->preq_optype = PCACHE_TYPE_WRITE; /* XXX */
ppark->park_preq->preq_cookie = cookie;
ppark->park_maxlen = ppark->park_copylen = pcilen;
(void)touser(pmp, ppark, 0, NULL, NULL);
}
/*
* Wait for the userspace ping-pong game in calling process context.
*

View File

@ -1,4 +1,4 @@
/* $NetBSD: puffs_msgif.h,v 1.19 2007/01/26 22:59:49 pooka Exp $ */
/* $NetBSD: puffs_msgif.h,v 1.20 2007/03/20 10:21:58 pooka Exp $ */
/*
* Copyright (c) 2005, 2006 Antti Kantee. All Rights Reserved.
@ -47,6 +47,7 @@
#define PUFFSOP_VFS 1
#define PUFFSOP_VN 2
#define PUFFSOP_CACHE 3
#define PUFFSOPFLAG_FAF 0x10 /* fire-and-forget */
#define PUFFSOP_OPCMASK 0x03
@ -244,11 +245,13 @@ struct puffs_sizeop {
* 2) page cache for one entire node
*/
/* XXX: only namecache DIR and ALL are currently implemented */
/* XXX: needs restructuring */
struct puffs_flush {
void *pf_cookie;
int pf_op;
off_t pf_start;
off_t pf_end;
};
#define PUFFS_INVAL_NAMECACHE_NODE 0
#define PUFFS_INVAL_NAMECACHE_DIR 1
@ -602,14 +605,32 @@ struct puffs_vnreq_mmap {
pid_t pvnr_pid; /* OUT */
};
/*
* For cache reports. Everything is always out-out-out, no replies
*/
struct puffs_cacherun {
off_t pcache_runstart;
off_t pcache_runend;
};
/* cache info. old used for write now */
struct puffs_cacheinfo {
struct puffs_req pcache_pr;
int pcache_type;
size_t pcache_nruns;
struct puffs_cacherun pcache_runs[0];
};
#define PCACHE_TYPE_READ 0
#define PCACHE_TYPE_WRITE 1
/* notyet */
#if 0
struct puffs_vnreq_kqfilter { };
struct puffs_vnreq_islocked { };
struct puffs_vnreq_lease { };
#endif
struct puffs_vnreq_getpages { };
struct puffs_vnreq_putpages { };
struct puffs_vnreq_getextattr { };
struct puffs_vnreq_setextattr { };
struct puffs_vnreq_listextattr { };

View File

@ -1,4 +1,4 @@
/* $NetBSD: puffs_subr.c,v 1.24 2007/03/14 12:13:58 pooka Exp $ */
/* $NetBSD: puffs_subr.c,v 1.25 2007/03/20 10:21:59 pooka Exp $ */
/*
* Copyright (c) 2005, 2006 Antti Kantee. All Rights Reserved.
@ -33,7 +33,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: puffs_subr.c,v 1.24 2007/03/14 12:13:58 pooka Exp $");
__KERNEL_RCSID(0, "$NetBSD: puffs_subr.c,v 1.25 2007/03/20 10:21:59 pooka Exp $");
#include <sys/param.h>
#include <sys/conf.h>
@ -418,35 +418,31 @@ puffs_gop_markupdate(struct vnode *vp, int flags)
void
puffs_updatenode(struct vnode *vp, int flags)
{
struct puffs_node *pn;
struct timespec ts;
struct puffs_vnreq_setattr *setattr_arg;
if (flags == 0)
return;
setattr_arg = malloc(sizeof(struct puffs_vnreq_setattr), M_PUFFS,
M_NOWAIT | M_ZERO);
if (setattr_arg == NULL)
return; /* 2bad */
pn = VPTOPP(vp);
nanotime(&ts);
VATTR_NULL(&setattr_arg->pvnr_va);
if (flags & PUFFS_UPDATEATIME)
setattr_arg->pvnr_va.va_atime = ts;
if (flags & PUFFS_UPDATECTIME)
setattr_arg->pvnr_va.va_ctime = ts;
if (flags & PUFFS_UPDATEMTIME)
setattr_arg->pvnr_va.va_mtime = ts;
if (flags & PUFFS_UPDATESIZE)
setattr_arg->pvnr_va.va_size = vp->v_size;
setattr_arg->pvnr_pid = 0;
puffs_credcvt(&setattr_arg->pvnr_cred, NOCRED);
/* setattr_arg ownership shifted to callee */
puffs_vntouser_faf(MPTOPUFFSMP(vp->v_mount), PUFFS_VN_SETATTR,
setattr_arg, sizeof(struct puffs_vnreq_setattr), VPTOPNC(vp));
if (flags & PUFFS_UPDATEATIME) {
pn->pn_mc_atime = ts;
pn->pn_stat |= PNODE_METACACHE_ATIME;
}
if (flags & PUFFS_UPDATECTIME) {
pn->pn_mc_ctime = ts;
pn->pn_stat |= PNODE_METACACHE_CTIME;
}
if (flags & PUFFS_UPDATEMTIME) {
pn->pn_mc_mtime = ts;
pn->pn_stat |= PNODE_METACACHE_MTIME;
}
if (flags & PUFFS_UPDATESIZE) {
pn->pn_mc_size = vp->v_size;
pn->pn_stat |= PNODE_METACACHE_SIZE;
}
}
void

View File

@ -1,4 +1,4 @@
/* $NetBSD: puffs_sys.h,v 1.26 2007/03/14 12:13:58 pooka Exp $ */
/* $NetBSD: puffs_sys.h,v 1.27 2007/03/20 10:21:59 pooka Exp $ */
/*
* Copyright (c) 2005, 2006 Antti Kantee. All Rights Reserved.
@ -134,6 +134,8 @@ extern int puffsdebug; /* puffs_subr.c */
#define PUFFS_DOCACHE(pmp) (((pmp)->pmp_flags & PUFFS_KFLAG_NOCACHE) == 0)
#define PUFFS_WCACHEINFO(pmp) 0
TAILQ_HEAD(puffs_wq, puffs_park);
LIST_HEAD(puffs_node_hashlist, puffs_node);
struct puffs_mount {
@ -169,12 +171,16 @@ struct puffs_mount {
#define PUFFSTAT_RUNNING 2
#define PUFFSTAT_DYING 3 /* Do you want your possessions identified? */
#define PNODE_NOREFS 0x01 /* vnode inactive, no backend reference */
#define PNODE_SUSPEND 0x02 /* issue all operations as FAF */
#if 0
#define PNODE_LOCKED 0x0
#define PNODE_WANTED 0x0
#endif
#define PNODE_METACACHE_ATIME 0x10 /* cache atime metadata */
#define PNODE_METACACHE_CTIME 0x20 /* cache atime metadata */
#define PNODE_METACACHE_MTIME 0x40 /* cache atime metadata */
#define PNODE_METACACHE_SIZE 0x80 /* cache atime metadata */
#define PNODE_METACACHE_MASK 0xf0
struct puffs_node {
struct genfs_node pn_gnode; /* genfs glue */
@ -182,6 +188,12 @@ struct puffs_node {
struct vnode *pn_vp; /* backpointer to vnode */
uint32_t pn_stat; /* node status */
/* metacache */
struct timespec pn_mc_atime;
struct timespec pn_mc_ctime;
struct timespec pn_mc_mtime;
u_quad_t pn_mc_size;
LIST_ENTRY(puffs_node) pn_hashent;
};
@ -199,6 +211,10 @@ int puffs_vntouser_req(struct puffs_mount *, int, void *, size_t,
void *, uint64_t, struct vnode *, struct vnode *);
int puffs_vntouser_adjbuf(struct puffs_mount *, int, void **, size_t *,
size_t, void *, struct vnode *, struct vnode *);
void puffs_vntouser_faf(struct puffs_mount *, int, void *, size_t, void *);
void puffs_cacheop(struct puffs_mount *, struct puffs_park *,
struct puffs_cacheinfo *, size_t, void *);
struct puffs_park *puffs_cacheop_alloc(void);
int puffs_getvnode(struct mount *, void *, enum vtype, voff_t, dev_t,
struct vnode **);

View File

@ -1,4 +1,4 @@
/* $NetBSD: puffs_transport.c,v 1.8 2007/02/16 17:23:59 hannken Exp $ */
/* $NetBSD: puffs_transport.c,v 1.9 2007/03/20 10:21:59 pooka Exp $ */
/*
* Copyright (c) 2006 Antti Kantee. All Rights Reserved.
@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: puffs_transport.c,v 1.8 2007/02/16 17:23:59 hannken Exp $");
__KERNEL_RCSID(0, "$NetBSD: puffs_transport.c,v 1.9 2007/03/20 10:21:59 pooka Exp $");
#include <sys/param.h>
#include <sys/conf.h>
@ -364,6 +364,19 @@ puffs_flush(struct puffs_mount *pmp, struct puffs_flush *pf)
cache_purge1(vp, NULL, PURGE_CHILDREN);
break;
#if 0
case PUFFS_INVAL_PAGECACHE_NODE_RANGE:
simple_lock(&vp->v_uobj.vmobjlock);
/* XXX: validate args? */
rv = VOP_PUTPAGES(vp, pf->pf_start, pf->pf_end, PGO_FREE);
break;
#endif
case PUFFS_INVAL_PAGECACHE_NODE:
simple_lock(&vp->v_uobj.vmobjlock);
rv = VOP_PUTPAGES(vp, 0, 0, PGO_FREE | PGO_ALLPAGES);
break;
default:
rv = EINVAL;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: puffs_vfsops.c,v 1.29 2007/03/13 14:16:07 ad Exp $ */
/* $NetBSD: puffs_vfsops.c,v 1.30 2007/03/20 10:21:59 pooka Exp $ */
/*
* Copyright (c) 2005, 2006 Antti Kantee. All Rights Reserved.
@ -33,7 +33,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: puffs_vfsops.c,v 1.29 2007/03/13 14:16:07 ad Exp $");
__KERNEL_RCSID(0, "$NetBSD: puffs_vfsops.c,v 1.30 2007/03/20 10:21:59 pooka Exp $");
#include <sys/param.h>
#include <sys/mount.h>
@ -433,11 +433,12 @@ puffs_statvfs(struct mount *mp, struct statvfs *sbp, struct lwp *l)
}
static int
pageflush(struct mount *mp, int waitfor, int suspending)
pageflush(struct mount *mp, kauth_cred_t cred,
int waitfor, int suspending, struct lwp *l)
{
struct puffs_node *pn;
struct vnode *vp, *nvp;
int error, rv, ppflags;
int error, rv;
KASSERT(((waitfor == MNT_WAIT) && suspending) == 0);
KASSERT((suspending == 0)
@ -445,9 +446,6 @@ pageflush(struct mount *mp, int waitfor, int suspending)
&& fstrans_getstate(mp) == FSTRANS_SUSPENDING));
error = 0;
ppflags = PGO_CLEANIT | PGO_ALLPAGES;
if (waitfor == MNT_WAIT)
ppflags |= PGO_SYNCIO;
/*
* Sync all cached data from regular vnodes (which are not
@ -520,10 +518,12 @@ pageflush(struct mount *mp, int waitfor, int suspending)
* storage.
* TODO: Maybe also hint the user server of this twist?
*/
simple_lock(&vp->v_interlock);
if (suspending || waitfor == MNT_LAZY)
if (suspending || waitfor == MNT_LAZY) {
simple_lock(&vp->v_interlock);
pn->pn_stat |= PNODE_SUSPEND;
rv = VOP_PUTPAGES(vp, 0, 0, ppflags);
simple_unlock(&vp->v_interlock);
}
rv = VOP_FSYNC(vp, cred, waitfor, 0, 0, l);
if (suspending || waitfor == MNT_LAZY) {
simple_lock(&vp->v_interlock);
pn->pn_stat &= ~PNODE_SUSPEND;
@ -547,7 +547,7 @@ puffs_sync(struct mount *mp, int waitfor, struct kauth_cred *cred,
PUFFS_VFSREQ(sync);
error = pageflush(mp, waitfor, 0);
error = pageflush(mp, cred, waitfor, 0, l);
/* sync fs */
sync_arg.pvfsr_waitfor = waitfor;
@ -633,7 +633,7 @@ puffs_suspendctl(struct mount *mp, int cmd)
break;
puffs_suspendtouser(pmp, PUFFS_SUSPEND_START);
error = pageflush(mp, 0, 1);
error = pageflush(mp, FSCRED, 0, 1, curlwp);
if (error == 0)
error = fstrans_setstate(mp, FSTRANS_SUSPENDED);

View File

@ -1,4 +1,4 @@
/* $NetBSD: puffs_vnops.c,v 1.53 2007/03/14 12:13:58 pooka Exp $ */
/* $NetBSD: puffs_vnops.c,v 1.54 2007/03/20 10:21:59 pooka Exp $ */
/*
* Copyright (c) 2005, 2006 Antti Kantee. All Rights Reserved.
@ -33,7 +33,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: puffs_vnops.c,v 1.53 2007/03/14 12:13:58 pooka Exp $");
__KERNEL_RCSID(0, "$NetBSD: puffs_vnops.c,v 1.54 2007/03/20 10:21:59 pooka Exp $");
#include <sys/param.h>
#include <sys/fstrans.h>
@ -81,6 +81,7 @@ int puffs_advlock(void *);
int puffs_strategy(void *);
int puffs_bmap(void *);
int puffs_mmap(void *);
int puffs_getpages(void *);
int puffs_spec_read(void *);
int puffs_spec_write(void *);
@ -284,7 +285,6 @@ const struct vnodeopv_entry_desc puffs_msgop_entries[] = {
{ &vop_write_desc, puffs_write }, /* write */
{ &vop_fcntl_desc, puffs_fcntl }, /* fcntl */
{ &vop_ioctl_desc, puffs_ioctl }, /* ioctl */
{ &vop_fsync_desc, puffs_fsync }, /* fsync */
{ &vop_seek_desc, puffs_seek }, /* seek */
{ &vop_remove_desc, puffs_remove }, /* remove */
{ &vop_link_desc, puffs_link }, /* link */
@ -298,7 +298,7 @@ const struct vnodeopv_entry_desc puffs_msgop_entries[] = {
{ &vop_islocked_desc, puffs_islocked }, /* islocked */
{ &vop_pathconf_desc, puffs_pathconf }, /* pathconf */
{ &vop_advlock_desc, puffs_advlock }, /* advlock */
{ &vop_getpages_desc, genfs_getpages }, /* getpages */
{ &vop_getpages_desc, puffs_getpages }, /* getpages */
{ NULL, NULL }
};
const struct vnodeopv_desc puffs_msgop_opv_desc =
@ -691,11 +691,16 @@ puffs_getattr(void *v)
struct lwp *a_l;
} */ *ap = v;
struct mount *mp;
struct vnode *vp;
struct vattr *vap;
struct puffs_node *pn;
int error;
PUFFS_VNREQ(getattr);
mp = ap->a_vp->v_mount;
vp = ap->a_vp;
mp = vp->v_mount;
vap = ap->a_vap;
vattr_null(&getattr_arg.pvnr_va);
puffs_credcvt(&getattr_arg.pvnr_cred, ap->a_cred);
@ -707,19 +712,28 @@ puffs_getattr(void *v)
* around with VXLOCK and therefore breaks vn_lock(). Proper
* fix pending.
*/
error = puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_GETATTR,
&getattr_arg, sizeof(getattr_arg), VPTOPNC(ap->a_vp),
NULL /* XXXseeabove: should be LOCKEDVP(ap->a_vp) */, NULL);
error = puffs_vntouser(MPTOPUFFSMP(vp->v_mount), PUFFS_VN_GETATTR,
&getattr_arg, sizeof(getattr_arg), VPTOPNC(vp),
NULL /* XXXseeabove: should be LOCKEDVP(vp) */, NULL);
if (error)
return error;
(void)memcpy(ap->a_vap, &getattr_arg.pvnr_va, sizeof(struct vattr));
(void) memcpy(vap, &getattr_arg.pvnr_va, sizeof(struct vattr));
vap->va_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
/*
* fill in information userspace does not have
* XXX: but would it be better to do fsid at the generic level?
*/
ap->a_vap->va_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
pn = VPTOPP(vp);
if (pn->pn_stat & PNODE_METACACHE_ATIME)
vap->va_atime = pn->pn_mc_atime;
if (pn->pn_stat & PNODE_METACACHE_CTIME)
vap->va_ctime = pn->pn_mc_ctime;
if (pn->pn_stat & PNODE_METACACHE_MTIME)
vap->va_mtime = pn->pn_mc_mtime;
if (pn->pn_stat & PNODE_METACACHE_SIZE) {
vap->va_size = pn->pn_mc_size;
} else {
if (getattr_arg.pvnr_va.va_size != VNOVAL)
uvm_vnp_setsize(vp, getattr_arg.pvnr_va.va_size);
}
return 0;
}
@ -944,6 +958,7 @@ puffs_fsync(void *v)
off_t a_offhi;
struct lwp *a_l;
} */ *ap = v;
struct vattr va;
struct puffs_mount *pmp;
struct puffs_vnreq_fsync *fsync_argp;
struct vnode *vp;
@ -956,13 +971,31 @@ puffs_fsync(void *v)
pn = VPTOPP(vp);
pmp = MPTOPUFFSMP(vp->v_mount);
pflags = PGO_CLEANIT;
if (ap->a_flags & FSYNC_WAIT)
pflags |= PGO_SYNCIO;
/* flush out information from our metacache */
if (pn->pn_stat & PNODE_METACACHE_MASK) {
vattr_null(&va);
if (pn->pn_stat & PNODE_METACACHE_ATIME)
va.va_atime = pn->pn_mc_atime;
if (pn->pn_stat & PNODE_METACACHE_CTIME)
va.va_ctime = pn->pn_mc_ctime;
if (pn->pn_stat & PNODE_METACACHE_MTIME)
va.va_mtime = pn->pn_mc_ctime;
if (pn->pn_stat & PNODE_METACACHE_SIZE)
va.va_size = pn->pn_mc_size;
error = VOP_SETATTR(vp, &va, FSCRED, NULL);
if (error)
return error;
pn->pn_stat &= ~PNODE_METACACHE_MASK;
}
/*
* flush pages to avoid being overly dirty
*/
pflags = PGO_CLEANIT;
if (ap->a_flags & FSYNC_WAIT)
pflags |= PGO_SYNCIO;
simple_lock(&vp->v_interlock);
error = VOP_PUTPAGES(vp, trunc_page(ap->a_offlo),
round_page(ap->a_offhi), pflags);
@ -1164,6 +1197,13 @@ puffs_link(void *v)
error = puffs_vntouser(MPTOPUFFSMP(ap->a_dvp->v_mount), PUFFS_VN_LINK,
&link_arg, sizeof(link_arg), VPTOPNC(ap->a_dvp), ap->a_dvp, NULL);
/*
* XXX: stay in touch with the cache. I don't like this, but
* don't have a better solution either. See also puffs_rename().
*/
if (error == 0)
puffs_updatenode(ap->a_vp, PUFFS_UPDATECTIME);
vput(ap->a_dvp);
return error;
@ -1275,6 +1315,13 @@ puffs_rename(void *v)
PUFFS_VN_RENAME, &rename_arg, sizeof(rename_arg),
VPTOPNC(ap->a_fdvp), NULL, NULL);
/*
* XXX: stay in touch with the cache. I don't like this, but
* don't have a better solution either. See also puffs_link().
*/
if (error == 0)
puffs_updatenode(ap->a_fvp, PUFFS_UPDATECTIME);
out:
if (ap->a_tvp != NULL)
vput(ap->a_tvp);
@ -1824,6 +1871,29 @@ puffs_strategy(void *v)
(void)memcpy(bp->b_data, read_argp->pvnr_data, moved);
bp->b_resid = bp->b_bcount - moved;
} else {
/*
* make pages read-only before we write them if we want
* write caching info
*/
if (PUFFS_WCACHEINFO(pmp)) {
struct uvm_object *uobj = &vp->v_uobj;
int npages = (bp->b_bcount + PAGE_SIZE-1) >> PAGE_SHIFT;
struct vm_page *vmp;
int i;
for (i = 0; i < npages; i++) {
vmp= uvm_pageratop((vaddr_t)bp->b_data
+ (i << PAGE_SHIFT));
DPRINTF(("puffs_strategy: write-protecting "
"vp %p page %p, offset %" PRId64"\n",
vp, vmp, vmp->offset));
simple_lock(&uobj->vmobjlock);
vmp->flags |= PG_RDONLY;
pmap_page_protect(vmp, VM_PROT_READ);
simple_unlock(&uobj->vmobjlock);
}
}
argsize = sizeof(struct puffs_vnreq_write) + bp->b_bcount;
write_argp = malloc(argsize, M_PUFFS, M_NOWAIT | M_ZERO);
if (write_argp == NULL) {
@ -1951,6 +2021,132 @@ puffs_bmap(void *v)
return 0;
}
/*
* Handle getpages faults in puffs. We let genfs_getpages() do most
* of the dirty work, but we come in this route to do accounting tasks.
* If the user server has specified functions for cache notifications
* about reads and/or writes, we record which type of operation we got,
* for which page range, and proceed to issue a FAF notification to the
* server about it.
*/
int
puffs_getpages(void *v)
{
struct vop_getpages_args /* {
const struct vnodeop_desc *a_desc;
struct vnode *a_vp;
voff_t a_offset;
struct vm_page **a_m;
int *a_count;
int a_centeridx;
vm_prot_t a_access_type;
int a_advice;
int a_flags;
} */ *ap = v;
struct puffs_mount *pmp;
struct vnode *vp;
struct vm_page **pgs;
struct puffs_park *ppark = NULL;
struct puffs_cacheinfo *pcinfo = NULL;
struct puffs_cacherun *pcrun;
size_t runsizes;
int i, npages, si, streakon;
int error, locked, write;
pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
npages = *ap->a_count;
pgs = ap->a_m;
vp = ap->a_vp;
locked = (ap->a_flags & PGO_LOCKED) != 0;
write = (ap->a_access_type & VM_PROT_WRITE) != 0;
/* ccg xnaht - gets Wuninitialized wrong */
pcrun = NULL;
runsizes = 0;
if (write && PUFFS_WCACHEINFO(pmp)) {
/* allocate worst-case memory */
runsizes = ((npages / 2) + 1) * sizeof(struct puffs_cacherun);
pcinfo = malloc(sizeof(struct puffs_cacheinfo) + runsizes,
M_PUFFS, M_ZERO | locked ? M_NOWAIT : M_WAITOK);
/*
* can't block if we're locked and can't mess up caching
* information for fs server. so come back later, please
*/
if (pcinfo == NULL) {
error = ENOMEM;
goto out;
}
ppark = malloc(sizeof(struct puffs_park), M_PUFFS, M_NOWAIT);
if (ppark == NULL) {
error = ENOMEM;
goto out;
}
pcrun = pcinfo->pcache_runs;
}
error = genfs_getpages(v);
if (error)
goto out;
if (PUFFS_WCACHEINFO(pmp) == 0)
goto out;
/*
* Let's see whose fault it was and inform the user server of
* possibly read/written pages. Map pages from read faults
* strictly read-only, since otherwise we might miss info on
* when the page is actually write-faulted to.
*/
if (!locked)
simple_lock(&vp->v_uobj.vmobjlock);
for (i = 0, si = 0, streakon = 0; i < npages; i++) {
if (pgs[i] == NULL || pgs[i] == PGO_DONTCARE) {
if (streakon && write) {
streakon = 0;
pcrun[si].pcache_runend
= trunc_page(pgs[i]->offset) + PAGE_MASK;
si++;
}
continue;
}
if (streakon == 0 && write) {
streakon = 1;
pcrun[si].pcache_runstart = pgs[i]->offset;
}
if (!write)
pgs[i]->flags |= PG_RDONLY;
}
/* was the last page part of our streak? */
if (streakon) {
pcrun[si].pcache_runend
= trunc_page(pgs[i-1]->offset) + PAGE_MASK;
si++;
}
if (!locked)
simple_unlock(&vp->v_uobj.vmobjlock);
KASSERT(si <= (npages / 2) + 1);
/* send results to userspace */
if (write)
puffs_cacheop(pmp, ppark, pcinfo,
sizeof(struct puffs_cacheinfo) + runsizes, VPTOPNC(vp));
out:
if (error) {
if (pcinfo != NULL)
free(pcinfo, M_PUFFS);
if (ppark != NULL)
free(ppark, M_PUFFS);
}
return error;
}
int
puffs_lock(void *v)