* 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:
parent
d60cbb92f9
commit
8d9c021816
@ -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.
|
||||
*
|
||||
|
@ -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 { };
|
||||
|
@ -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
|
||||
|
@ -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 **);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user