attach to genfs & support page cache. most noticeable effect is

mmap and therefore execution of binaries starting to work, some
speed improvements with large file I/O also.  caching semantics
and error case handling most likely need revisiting.
This commit is contained in:
pooka 2006-11-07 22:10:18 +00:00
parent e2c201cff5
commit b3bdf665dd
6 changed files with 523 additions and 159 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: puffs_msgif.c,v 1.3 2006/11/06 23:18:18 pooka Exp $ */
/* $NetBSD: puffs_msgif.c,v 1.4 2006/11/07 22:10:18 pooka Exp $ */
/*
* Copyright (c) 2005, 2006 Antti Kantee. All Rights Reserved.
@ -33,7 +33,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: puffs_msgif.c,v 1.3 2006/11/06 23:18:18 pooka Exp $");
__KERNEL_RCSID(0, "$NetBSD: puffs_msgif.c,v 1.4 2006/11/07 22:10:18 pooka Exp $");
#include <sys/param.h>
#include <sys/conf.h>
@ -56,10 +56,10 @@ __KERNEL_RCSID(0, "$NetBSD: puffs_msgif.c,v 1.3 2006/11/06 23:18:18 pooka Exp $"
* kernel-user-kernel waitqueues
*/
static int touser(struct puffs_mount *, struct puffs_park *, unsigned int,
static int touser(struct puffs_mount *, struct puffs_park *, uint64_t,
struct vnode *, struct vnode *);
unsigned int
uint64_t
puffs_getreqid(struct puffs_mount *pmp)
{
unsigned int rv;
@ -119,7 +119,7 @@ puffs_vntouser(struct puffs_mount *pmp, int optype,
*/
int
puffs_vntouser_req(struct puffs_mount *pmp, int optype,
void *kbuf, size_t buflen, void *cookie, unsigned int reqid,
void *kbuf, size_t buflen, void *cookie, uint64_t reqid,
struct vnode *vp1, struct vnode *vp2)
{
struct puffs_park park;
@ -167,6 +167,33 @@ puffs_vntouser_adjbuf(struct puffs_mount *pmp, int optype,
return error;
}
/*
* Notice: kbuf will be free'd later. I must be allocated from the
* kernel heap and it's ownership is shifted to this function from
* now on, i.e. the caller is not allowed to use it anymore!
*/
void
puffs_vntouser_faf(struct puffs_mount *pmp, int optype,
void *kbuf, size_t buflen, void *cookie)
{
struct puffs_park *ppark;
/* XXX: is it allowable to sleep here? */
ppark = malloc(sizeof(struct puffs_park), M_PUFFS, M_NOWAIT | M_ZERO);
if (ppark == NULL)
return; /* 2bad */
ppark->park_opclass = PUFFSOP_VN | PUFFSOPFLAG_FAF;
ppark->park_optype = optype;
ppark->park_cookie = cookie;
ppark->park_kernbuf = kbuf;
ppark->park_buflen = buflen;
ppark->park_copylen = buflen;
(void)touser(pmp, ppark, 0, NULL, NULL);
}
/*
* Wait for the userspace ping-pong game in calling process context.
*
@ -178,7 +205,7 @@ puffs_vntouser_adjbuf(struct puffs_mount *pmp, int optype,
* there's a slight ugly-factor also, but let's not worry about that.
*/
static int
touser(struct puffs_mount *pmp, struct puffs_park *park, unsigned int reqid,
touser(struct puffs_mount *pmp, struct puffs_park *ppark, uint64_t reqid,
struct vnode *vp1, struct vnode *vp2)
{
@ -189,9 +216,9 @@ touser(struct puffs_mount *pmp, struct puffs_park *park, unsigned int reqid,
return ENXIO;
}
park->park_id = reqid;
ppark->park_id = reqid;
TAILQ_INSERT_TAIL(&pmp->pmp_req_touser, park, park_entries);
TAILQ_INSERT_TAIL(&pmp->pmp_req_touser, ppark, park_entries);
pmp->pmp_req_touser_waiters++;
/*
@ -213,14 +240,16 @@ touser(struct puffs_mount *pmp, struct puffs_park *park, unsigned int reqid,
/*
* XXX: does releasing the lock here cause trouble? Can't hold
* it, because otherwise the below would cause locking against
* oneself-problems in the kqueue stuff
* oneself-problems in the kqueue stuff. yes, it is a
* theoretical race, so it must be solved
*/
simple_unlock(&pmp->pmp_lock);
wakeup(&pmp->pmp_req_touser);
selnotify(pmp->pmp_sel, 0);
ltsleep(park, PUSER, "puffs1", 0, NULL);
if (PUFFSOP_WANTREPLY(ppark->park_opclass))
ltsleep(ppark, PUSER, "puffs1", 0, NULL);
#if 0
/* relock */
@ -230,7 +259,7 @@ touser(struct puffs_mount *pmp, struct puffs_park *park, unsigned int reqid,
KASSERT(vn_lock(vp2, LK_EXCLUSIVE | LK_RETRY) == 0);
#endif
return park->park_rv;
return ppark->park_rv;
}
/*
@ -751,9 +780,15 @@ puffsgetop(struct puffs_mount *pmp, struct puffs_req *preq, int nonblock)
simple_unlock(&pmp->pmp_lock);
return error;
}
simple_lock(&pmp->pmp_lock);
TAILQ_INSERT_TAIL(&pmp->pmp_req_replywait, park, park_entries);
simple_unlock(&pmp->pmp_lock);
if (PUFFSOP_WANTREPLY(park->park_opclass)) {
simple_lock(&pmp->pmp_lock);
TAILQ_INSERT_TAIL(&pmp->pmp_req_replywait, park, park_entries);
simple_unlock(&pmp->pmp_lock);
} else {
free(park->park_kernbuf, M_PUFFS);
free(park, M_PUFFS);
}
return 0;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: puffs_msgif.h,v 1.4 2006/10/26 22:52:47 pooka Exp $ */
/* $NetBSD: puffs_msgif.h,v 1.5 2006/11/07 22:10:18 pooka Exp $ */
/*
* Copyright (c) 2005, 2006 Antti Kantee. All Rights Reserved.
@ -47,6 +47,11 @@
#define PUFFSOP_VFS 1
#define PUFFSOP_VN 2
#define PUFFSOPFLAG_FAF 0x10 /* fire-and-forget */
#define PUFFSOP_OPCMASK 0x03
#define PUFFSOP_OPCLASS(a) ((a) & PUFFSOP_OPCMASK)
#define PUFFSOP_WANTREPLY(a) (((a) & PUFFSOPFLAG_FAF) == 0)
enum {
PUFFS_VFS_MOUNT, PUFFS_VFS_START, PUFFS_VFS_UNMOUNT,
@ -224,6 +229,7 @@ struct puffs_vnreq_lookup {
struct puffs_cn pvnr_cn; /* OUT */
void *pvnr_newnode; /* IN */
enum vtype pvnr_vtype; /* IN */
voff_t pvnr_size; /* IN */
dev_t pvnr_rdev; /* IN */
};

View File

@ -1,4 +1,4 @@
/* $NetBSD: puffs_subr.c,v 1.6 2006/10/27 19:54:34 pooka Exp $ */
/* $NetBSD: puffs_subr.c,v 1.7 2006/11/07 22:10:18 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.6 2006/10/27 19:54:34 pooka Exp $");
__KERNEL_RCSID(0, "$NetBSD: puffs_subr.c,v 1.7 2006/11/07 22:10:18 pooka Exp $");
#include <sys/param.h>
#include <sys/conf.h>
@ -47,17 +47,31 @@ __KERNEL_RCSID(0, "$NetBSD: puffs_subr.c,v 1.6 2006/10/27 19:54:34 pooka Exp $")
#include <fs/puffs/puffs_msgif.h>
#include <fs/puffs/puffs_sys.h>
#include <miscfs/genfs/genfs_node.h>
#include <miscfs/specfs/specdev.h>
POOL_INIT(puffs_pnpool, sizeof(struct puffs_node), 0, 0, 0, "puffspnpl",
&pool_allocator_nointr);
static void puffs_gop_size(struct vnode *, off_t, off_t *, int);
static void puffs_gop_markupdate(struct vnode *, int);
static const struct genfs_ops puffs_genfsops = {
.gop_size = puffs_gop_size,
.gop_write = genfs_gop_write,
.gop_markupdate = puffs_gop_markupdate,
#if 0
.gop_alloc, should ask userspace
#endif
};
/*
* Grab a vnode, intialize all the puffs-dependant stuff.
*/
int
puffs_getvnode(struct mount *mp, void *cookie, enum vtype type,
dev_t rdev, struct vnode **vpp)
voff_t vsize, dev_t rdev, struct vnode **vpp)
{
struct puffs_mount *pmp;
struct vnode *vp, *nvp;
@ -142,11 +156,16 @@ puffs_getvnode(struct mount *mp, void *cookie, enum vtype type,
vp->v_mount = mp;
}
break;
case VFIFO:
vp->v_op = puffs_fifoop_p;
break;
case VDIR:
case VREG:
uvm_vnp_setsize(vp, vsize);
break;
case VDIR:
case VLNK:
case VSOCK:
break;
@ -165,6 +184,7 @@ puffs_getvnode(struct mount *mp, void *cookie, enum vtype type,
vp->v_type = type;
pnode->pn_vp = vp;
genfs_node_init(vp, &puffs_genfsops);
*vpp = vp;
DPRINTF(("new vnode at %p, pnode %p, cookie %p\n", vp,
@ -187,7 +207,7 @@ puffs_newnode(struct mount *mp, struct vnode *dvp, struct vnode **vpp,
return error;
}
error = puffs_getvnode(dvp->v_mount, cookie, type, rdev, &vp);
error = puffs_getvnode(dvp->v_mount, cookie, type, 0, rdev, &vp);
if (error)
return error;
@ -297,3 +317,59 @@ puffs_lwp2pid(struct lwp *l)
return l ? l->l_proc->p_pid : 0;
}
static void
puffs_gop_size(struct vnode *vp __unused, off_t size, off_t *eobp,
int flags __unused)
{
*eobp = size;
}
static void
puffs_gop_markupdate(struct vnode *vp, int flags)
{
int uflags = 0;
if (flags & GOP_UPDATE_ACCESSED)
uflags |= PUFFS_UPDATEATIME;
if (flags & GOP_UPDATE_MODIFIED)
uflags |= PUFFS_UPDATEMTIME;
puffs_updatenode(vp, uflags);
}
void
puffs_updatenode(struct vnode *vp, int flags)
{
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 */
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));
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: puffs_sys.h,v 1.5 2006/11/06 23:18:18 pooka Exp $ */
/* $NetBSD: puffs_sys.h,v 1.6 2006/11/07 22:10:18 pooka Exp $ */
/*
* Copyright (c) 2005, 2006 Antti Kantee. All Rights Reserved.
@ -45,6 +45,8 @@
#include <fs/puffs/puffs_msgif.h>
#include <miscfs/genfs/genfs_node.h>
extern int (**puffs_vnodeop_p)(void *);
extern int (**puffs_specop_p)(void *);
extern int (**puffs_fifoop_p)(void *);
@ -141,6 +143,8 @@ struct puffs_mount {
#define PNODE_LOCKED 0x02
#define PNODE_WANTED 0x04
struct puffs_node {
struct genfs_node pn_gnode; /* genfs glue */
void *pn_cookie; /* userspace pnode cookie */
struct vnode *pn_vp; /* backpointer to vnode */
uint32_t pn_stat; /* node status */
@ -153,13 +157,13 @@ int puffs_start2(struct puffs_mount *, struct puffs_vfsreq_start *);
int puffs_vfstouser(struct puffs_mount *, int, void *, size_t);
int puffs_vntouser(struct puffs_mount *, int, void *, size_t, void *,
struct vnode *, struct vnode *);
void puffs_vntouser_faf(struct puffs_mount *, int, void *, size_t, void *);
int puffs_vntouser_req(struct puffs_mount *, int, void *, size_t,
void *, unsigned int,
struct vnode *, struct vnode *);
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 *);
int puffs_getvnode(struct mount *, void *, enum vtype, dev_t,
int puffs_getvnode(struct mount *, void *, enum vtype, voff_t, dev_t,
struct vnode **);
int puffs_newnode(struct mount *, struct vnode *, struct vnode **,
void *, struct componentname *, enum vtype, dev_t);
@ -169,10 +173,16 @@ void puffs_makecn(struct puffs_cn *, const struct componentname *);
void puffs_credcvt(struct puffs_cred *, kauth_cred_t);
pid_t puffs_lwp2pid(struct lwp *);
void puffs_updatenode(struct vnode *, int);
#define PUFFS_UPDATEATIME 0x01
#define PUFFS_UPDATECTIME 0x02
#define PUFFS_UPDATEMTIME 0x04
#define PUFFS_UPDATESIZE 0x08
int puffs_setpmp(pid_t, int, struct puffs_mount *);
void puffs_nukebypmp(struct puffs_mount *);
unsigned int puffs_getreqid(struct puffs_mount *);
uint64_t puffs_getreqid(struct puffs_mount *);
void puffs_userdead(struct puffs_mount *);
extern int (**puffs_vnodeop_p)(void *);

View File

@ -1,4 +1,4 @@
/* $NetBSD: puffs_vfsops.c,v 1.5 2006/11/06 11:44:54 pooka Exp $ */
/* $NetBSD: puffs_vfsops.c,v 1.6 2006/11/07 22:10:18 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.5 2006/11/06 11:44:54 pooka Exp $");
__KERNEL_RCSID(0, "$NetBSD: puffs_vfsops.c,v 1.6 2006/11/07 22:10:18 pooka Exp $");
#include <sys/param.h>
#include <sys/mount.h>
@ -104,7 +104,11 @@ puffs_mount(struct mount *mp, const char *path, void *data,
MALLOC(pmp, struct puffs_mount *, sizeof(struct puffs_mount),
M_PUFFS, M_WAITOK | M_ZERO);
mp->mnt_fs_bshift = DEV_BSHIFT;
mp->mnt_dev_bshift = DEV_BSHIFT;
mp->mnt_flag &= ~MNT_LOCAL; /* we don't really know, so ... */
mp->mnt_data = pmp;
pmp->pmp_status = PUFFSTAT_MOUNTING;
pmp->pmp_nextreq = 0;
pmp->pmp_mp = mp;
@ -278,7 +282,7 @@ puffs_root(struct mount *mp, struct vnode **vpp)
* So, didn't have the magic root vnode available.
* No matter, grab another an stuff it with the cookie.
*/
if (puffs_getvnode(mp, pmp->pmp_rootcookie, VDIR, 0, &vp))
if (puffs_getvnode(mp, pmp->pmp_rootcookie, VDIR, 0, 0, &vp))
panic("sloppy programming");
simple_lock(&pmp->pmp_lock);

View File

@ -1,4 +1,4 @@
/* $NetBSD: puffs_vnops.c,v 1.7 2006/10/27 19:01:48 pooka Exp $ */
/* $NetBSD: puffs_vnops.c,v 1.8 2006/11/07 22:10:18 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.7 2006/10/27 19:01:48 pooka Exp $");
__KERNEL_RCSID(0, "$NetBSD: puffs_vnops.c,v 1.8 2006/11/07 22:10:18 pooka Exp $");
#include <sys/param.h>
#include <sys/vnode.h>
@ -77,12 +77,10 @@ int puffs_inactive(void *);
int puffs_print(void *);
int puffs_pathconf(void *);
int puffs_advlock(void *);
int puffs_strategy(void *);
int puffs_bmap(void *);
/* Need to support */
#define puffs_putpages puffs_generic
#define puffs_getpages puffs_generic
/* VOP_LEASE() not included */
int puffs_generic(void *);
@ -141,21 +139,19 @@ const struct vnodeopv_entry_desc puffs_vnodeop_entries[] = {
{ &vop_reclaim_desc, puffs_reclaim }, /* reclaim */
{ &vop_lock_desc, puffs_lock }, /* lock */
{ &vop_unlock_desc, puffs_unlock }, /* unlock */
{ &vop_bmap_desc, genfs_eopnotsupp }, /* bmap */
{ &vop_strategy_desc, genfs_eopnotsupp }, /* strategy */
{ &vop_bmap_desc, puffs_bmap }, /* bmap */
{ &vop_strategy_desc, puffs_strategy }, /* strategy */
{ &vop_print_desc, puffs_print }, /* print */
{ &vop_islocked_desc, puffs_islocked }, /* islocked */
{ &vop_pathconf_desc, puffs_pathconf }, /* pathconf */
{ &vop_advlock_desc, puffs_advlock }, /* advlock */
{ &vop_bwrite_desc, genfs_nullop }, /* bwrite */
#if 0
{ &vop_getpages_desc, puffs_getpages }, /* getpages */
#endif
{ &vop_putpages_desc, genfs_null_putpages }, /* putpages */
{ &vop_getpages_desc, genfs_getpages }, /* getpages */
{ &vop_putpages_desc, genfs_putpages }, /* putpages */
{ &vop_mmap_desc, genfs_mmap }, /* mmap */
{ &vop_poll_desc, genfs_eopnotsupp }, /* poll XXX */
{ &vop_poll_desc, genfs_eopnotsupp }, /* kqfilter XXX */
{ &vop_mmap_desc, genfs_eopnotsupp }, /* mmap XXX */
{ NULL, NULL }
};
const struct vnodeopv_desc puffs_vnodeop_opv_desc =
@ -378,7 +374,7 @@ puffs_lookup(void *v)
if (!vp) {
error = puffs_getvnode(dvp->v_mount,
lookup_arg.pvnr_newnode, lookup_arg.pvnr_vtype,
lookup_arg.pvnr_rdev, &vp);
lookup_arg.pvnr_size, lookup_arg.pvnr_rdev, &vp);
if (error) {
if (cnp->cn_flags & ISDOTDOT)
if (vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY) != 0)
@ -527,7 +523,6 @@ puffs_access(void *v)
kauth_cred_t a_cred;
struct lwp *a_l;
} */ *ap = v;
int error;
PUFFS_VNREQ(access);
@ -535,21 +530,8 @@ puffs_access(void *v)
access_arg.pvnr_pid = puffs_lwp2pid(ap->a_l);
puffs_credcvt(&access_arg.pvnr_cred, ap->a_cred);
error = puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_ACCESS,
return puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_ACCESS,
&access_arg, sizeof(access_arg), VPTOPNC(ap->a_vp), ap->a_vp, NULL);
if (error)
return error;
/*
* XXXtothepeople: no execute permissions yet. Otherwise
* all hell will break loose if we try to execute a file
* without VOP_GETPAGES support. It is forthcoming, just
* not there yet ...
*/
if (ap->a_mode == VEXEC && ap->a_vp->v_type != VDIR)
return EACCES;
return 0;
}
int
@ -584,15 +566,6 @@ puffs_getattr(void *v)
(void)memcpy(ap->a_vap, &getattr_arg.pvnr_va, sizeof(struct vattr));
/*
* XXXtothepeople: adjust the return value so that we don't
* advertise execute bits. Otherwise all hell will break
* loose if we try to execute a file without VOP_GETPAGES
* support. It is forthcoming, just not there yet ...
*/
if (ap->a_vp->v_type != VDIR)
ap->a_vap->va_mode &= ~0111;
return 0;
}
@ -606,6 +579,7 @@ puffs_setattr(void *v)
kauth_cred_t a_cred;
struct lwp *a_l;
} */ *ap = v;
int error;
PUFFS_VNREQ(setattr);
@ -613,9 +587,16 @@ puffs_setattr(void *v)
puffs_credcvt(&setattr_arg.pvnr_cred, ap->a_cred);
setattr_arg.pvnr_pid = puffs_lwp2pid(ap->a_l);
return puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_SETATTR,
error = puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_SETATTR,
&setattr_arg, sizeof(setattr_arg), VPTOPNC(ap->a_vp),
ap->a_vp, NULL);
if (error)
return error;
if (ap->a_vap->va_size != VNOVAL)
uvm_vnp_setsize(ap->a_vp, ap->a_vap->va_size);
return 0;
}
int
@ -637,6 +618,11 @@ puffs_revoke(void *v)
return genfs_revoke(v);
}
/*
* There is no technical need to have this travel to userspace
* synchronously. So once async reply support is in place, make this
* async.
*/
int
puffs_inactive(void *v)
{
@ -819,21 +805,59 @@ puffs_fsync(void *v)
off_t a_offhi;
struct lwp *a_l;
} */ *ap = v;
struct puffs_vnreq_fsync *fsync_argp;
struct vnode *vp;
int pflags, error;
PUFFS_VNREQ(fsync);
puffs_credcvt(&fsync_arg.pvnr_cred, ap->a_cred);
fsync_arg.pvnr_flags = ap->a_flags;
fsync_arg.pvnr_offlo = ap->a_offlo;
fsync_arg.pvnr_offhi = ap->a_offhi;
fsync_arg.pvnr_pid = puffs_lwp2pid(ap->a_l);
vp = ap->a_vp;
pflags = PGO_CLEANIT;
if (ap->a_flags & FSYNC_WAIT) {
pflags |= PGO_SYNCIO;
fsync_argp = &fsync_arg;
} else {
fsync_argp = malloc(sizeof(struct puffs_vnreq_fsync),
M_PUFFS, M_ZERO | M_NOWAIT);
if (fsync_argp == NULL)
return ENOMEM;
}
/*
* flush pages to avoid being overly dirty
*/
simple_lock(&vp->v_interlock);
error = VOP_PUTPAGES(vp, trunc_page(ap->a_offlo),
round_page(ap->a_offhi), pflags);
if (error)
return error;
puffs_credcvt(&fsync_argp->pvnr_cred, ap->a_cred);
fsync_argp->pvnr_flags = ap->a_flags;
fsync_argp->pvnr_offlo = ap->a_offlo;
fsync_argp->pvnr_offhi = ap->a_offhi;
fsync_argp->pvnr_pid = puffs_lwp2pid(ap->a_l);
/*
* XXX: see comment at puffs_getattr about locking
*
* If we are not required to wait, do a FAF operation.
* Otherwise block here.
*/
return puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_FSYNC,
&fsync_arg, sizeof(fsync_arg), VPTOPNC(ap->a_vp),
NULL /* XXXshouldbe: ap->a_vp */, NULL);
if (ap->a_flags & FSYNC_WAIT) {
error = puffs_vntouser(MPTOPUFFSMP(vp->v_mount),
PUFFS_VN_FSYNC, fsync_argp, sizeof(*fsync_argp),
VPTOPNC(vp), NULL /* XXXshouldbe: vp */, NULL);
} else {
/* FAF is always "succesful" */
error = 0;
puffs_vntouser_faf(MPTOPUFFSMP(vp->v_mount),
PUFFS_VN_FSYNC, fsync_argp, sizeof(*fsync_argp),
VPTOPNC(vp));
}
return error;
}
int
@ -1102,52 +1126,98 @@ puffs_read(void *v)
} */ *ap = v;
struct puffs_vnreq_read *read_argp;
struct puffs_mount *pmp;
struct vnode *vp;
struct uio *uio;
void *win;
size_t tomove, argsize;
vsize_t bytelen;
int error;
uio = ap->a_uio;
pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
argsize = sizeof(struct puffs_vnreq_read);
read_argp = malloc(argsize, M_PUFFS, M_WAITOK | M_ZERO);
vp = ap->a_vp;
read_argp = NULL;
error = 0;
while (uio->uio_resid > 0) {
read_argp->pvnr_ioflag = ap->a_ioflag;
read_argp->pvnr_resid = tomove;
read_argp->pvnr_offset = uio->uio_offset;
puffs_credcvt(&read_argp->pvnr_cred, ap->a_cred);
argsize = sizeof(struct puffs_vnreq_read);
error = puffs_vntouser_adjbuf(pmp, PUFFS_VN_READ,
(void **)&read_argp, &argsize,
sizeof(struct puffs_vnreq_read), VPTOPNC(ap->a_vp),
ap->a_vp, NULL);
if (error)
goto out;
/* std sanity */
if (uio->uio_resid == 0)
return 0;
if (uio->uio_offset < 0)
return EINVAL;
if (read_argp->pvnr_resid > tomove) {
error = EINVAL;
goto out;
if (vp->v_type == VREG) {
const int advice = IO_ADV_DECODE(ap->a_ioflag);
while (uio->uio_resid > 0) {
bytelen = MIN(uio->uio_resid,
vp->v_size - uio->uio_offset);
if (bytelen == 0)
break;
win = ubc_alloc(&vp->v_uobj, uio->uio_offset,
&bytelen, advice, UBC_READ);
error = uiomove(win, bytelen, uio);
ubc_release(win, UBC_WANT_UNMAP(vp) ? UBC_UNMAP : 0);
if (error)
break;
}
error = uiomove(read_argp->pvnr_data,
tomove - read_argp->pvnr_resid, uio);
if ((vp->v_mount->mnt_flag & MNT_NOATIME) == 0)
puffs_updatenode(vp, PUFFS_UPDATEATIME);
} else {
#ifdef DIAGNOSTIC
if (!(vp->v_type == VDIR || vp->v_type == VLNK))
panic("puffs_read: bad vnode type %d\n", vp->v_type);
#endif
/*
* in case the file is out of juice, resid from userspace
* is != 0. and the error-case is quite obvious
* in case it's not a regular file, do it in the
* old-fashioned style, i.e. explicit read without going
* through the page cache.
*
* XXX: this path is not really tested now
*/
if (error || read_argp->pvnr_resid)
goto out;
pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
argsize = sizeof(struct puffs_vnreq_read);
read_argp = malloc(argsize, M_PUFFS, M_WAITOK | M_ZERO);
error = 0;
while (uio->uio_resid > 0) {
read_argp->pvnr_ioflag = ap->a_ioflag;
read_argp->pvnr_resid = tomove;
read_argp->pvnr_offset = uio->uio_offset;
puffs_credcvt(&read_argp->pvnr_cred, ap->a_cred);
argsize = sizeof(struct puffs_vnreq_read);
error = puffs_vntouser_adjbuf(pmp, PUFFS_VN_READ,
(void **)&read_argp, &argsize,
sizeof(struct puffs_vnreq_read), VPTOPNC(ap->a_vp),
ap->a_vp, NULL);
if (error)
break;
if (read_argp->pvnr_resid > tomove) {
error = EINVAL;
break;
}
error = uiomove(read_argp->pvnr_data,
tomove - read_argp->pvnr_resid, uio);
/*
* in case the file is out of juice, resid from
* userspace is != 0. and the error-case is
* quite obvious
*/
if (error || read_argp->pvnr_resid)
break;
tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
}
}
out:
free(read_argp, M_PUFFS);
if (read_argp)
free(read_argp, M_PUFFS);
return error;
}
@ -1164,53 +1234,133 @@ puffs_write(void *v)
struct puffs_vnreq_write *write_argp;
struct puffs_mount *pmp;
struct uio *uio;
struct vnode *vp;
void *win;
size_t tomove, argsize;
int error;
off_t oldoff, newoff, origoff;
vsize_t bytelen;
int error, uflags;
int async;
vp = ap->a_vp;
uio = ap->a_uio;
async = vp->v_mount->mnt_flag & MNT_ASYNC;
error = uflags = 0;
write_argp = NULL;
pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
argsize = sizeof(struct puffs_vnreq_write) + tomove;
write_argp = malloc(argsize, M_PUFFS, M_WAITOK | M_ZERO);
if (vp->v_type == VREG) {
/*
* userspace *should* be allowed to control this,
* but with UBC it's a bit unclear how to handle it
*/
if (ap->a_ioflag & IO_APPEND)
uio->uio_offset = vp->v_size;
error = 0;
while (uio->uio_resid > 0) {
write_argp->pvnr_ioflag = ap->a_ioflag;
write_argp->pvnr_resid = tomove;
write_argp->pvnr_offset = uio->uio_offset;
puffs_credcvt(&write_argp->pvnr_cred, ap->a_cred);
error = uiomove(write_argp->pvnr_data, tomove, ap->a_uio);
if (error)
goto out;
origoff = uio->uio_offset;
while (uio->uio_resid > 0) {
uflags |= PUFFS_UPDATECTIME;
uflags |= PUFFS_UPDATEMTIME;
oldoff = uio->uio_offset;
bytelen = uio->uio_resid;
error = puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount),
PUFFS_VN_WRITE, write_argp, argsize, VPTOPNC(ap->a_vp),
ap->a_vp, NULL);
if (error) {
/* restore uiomove */
uio->uio_resid += tomove;
uio->uio_offset -= tomove;
goto out;
}
if (write_argp->pvnr_resid > tomove) {
error = EINVAL;
goto out;
win = ubc_alloc(&vp->v_uobj, oldoff, &bytelen,
UVM_ADV_NORMAL, UBC_WRITE);
error = uiomove(win, bytelen, uio);
/*
* did we grow the file?
* XXX: should probably ask userspace to extend
* it's idea of the *first* before growing it
* here. Or we need some mechanism to "rollback"
* in case putpages fails.
*/
newoff = oldoff + bytelen;
if (vp->v_size < newoff) {
uflags |= PUFFS_UPDATESIZE;
uvm_vnp_setsize(vp, newoff);
/*
* in case we couldn't copy data to the
* window, zero it out so that we don't
* have any random leftovers in there.
*/
if (error)
memset(win, 0, bytelen);
}
ubc_release(win, UBC_WANT_UNMAP(vp) ? UBC_UNMAP : 0);
if (error)
break;
/* ok, I really need to admit: why's this? */
if (!async && oldoff >> 16 != uio->uio_offset >> 16) {
simple_lock(&vp->v_interlock);
error = VOP_PUTPAGES(vp, oldoff & ~0xffff,
uio->uio_offset & ~0xffff, PGO_CLEANIT);
if (error)
break;
}
}
/* didn't move everything? bad userspace. bail */
if (write_argp->pvnr_resid != 0) {
uio->uio_resid += write_argp->pvnr_resid;
uio->uio_offset -= write_argp->pvnr_resid;
error = EIO;
break;
if (error == 0 && ap->a_ioflag & IO_SYNC) {
simple_lock(&vp->v_interlock);
error = VOP_PUTPAGES(vp, trunc_page(origoff),
round_page(uio->uio_offset),
PGO_CLEANIT | PGO_SYNCIO);
}
puffs_updatenode(vp, uflags);
} else {
pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
argsize = sizeof(struct puffs_vnreq_write) + tomove;
write_argp = malloc(argsize, M_PUFFS, M_WAITOK | M_ZERO);
while (uio->uio_resid > 0) {
write_argp->pvnr_ioflag = ap->a_ioflag;
write_argp->pvnr_resid = tomove;
write_argp->pvnr_offset = uio->uio_offset;
puffs_credcvt(&write_argp->pvnr_cred, ap->a_cred);
error = uiomove(write_argp->pvnr_data, tomove, uio);
if (error)
break;
error = puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount),
PUFFS_VN_WRITE, write_argp, argsize,
VPTOPNC(ap->a_vp), ap->a_vp, NULL);
if (error) {
/* restore uiomove */
uio->uio_resid += tomove;
uio->uio_offset -= tomove;
break;
}
if (write_argp->pvnr_resid > tomove) {
/*
* XXX: correct file size is a mystery,
* we can only guess
*/
error = EINVAL;
break;
}
/* adjust file size */
uvm_vnp_setsize(vp, uio->uio_offset);
/* didn't move everything? bad userspace. bail */
if (write_argp->pvnr_resid != 0) {
uio->uio_resid += write_argp->pvnr_resid;
uio->uio_offset -= write_argp->pvnr_resid;
error = EIO;
break;
}
tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
}
}
out:
free(write_argp, M_PUFFS);
if (write_argp)
free(write_argp, M_PUFFS);
return error;
}
@ -1369,12 +1519,115 @@ puffs_advlock(void *v)
return puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_ADVLOCK,
&advlock_arg, sizeof(advlock_arg), VPTOPNC(ap->a_vp), NULL, NULL);
}
/*
* This maps itself to PUFFS_VN_READ/WRITE for data transfer.
*/
int
puffs_strategy(void *v)
{
struct vop_strategy_args /* {
const struct vnodeop_desc *a_desc;
struct vnode *a_vp;
struct buf *a_bp;
} */ *ap = v;
struct puffs_mount *pmp;
struct puffs_vnreq_read *read_argp;
struct puffs_vnreq_write *write_argp;
struct buf *bp;
size_t argsize;
int error;
pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
bp = ap->a_bp;
#ifdef DIAGNOSTIC
if (bp->b_bcount > pmp->pmp_req_maxsize - PUFFS_REQSTRUCT_MAX)
panic("puffs_strategy: wildly inappropriate buf bcount %d",
bp->b_bcount);
#endif
if (bp->b_flags & B_READ) {
argsize = sizeof(struct puffs_vnreq_read);
read_argp = malloc(argsize, M_PUFFS, M_WAITOK | M_ZERO);
read_argp->pvnr_ioflag = 0;
read_argp->pvnr_resid = bp->b_bcount;
read_argp->pvnr_offset = bp->b_blkno << DEV_BSHIFT;
/* XXX: puffs_credcvt */
error = puffs_vntouser_adjbuf(pmp, PUFFS_VN_READ,
(void **)&read_argp, &argsize, argsize,
VPTOPNC(ap->a_vp), LOCKEDVP(ap->a_vp), NULL);
if (error)
printf("virhe\n");
(void)memcpy(bp->b_data, read_argp->pvnr_data, bp->b_bcount);
free(read_argp, M_PUFFS);
} else {
argsize = sizeof(struct puffs_vnreq_write) + bp->b_bcount;
write_argp = malloc(argsize, M_PUFFS, M_WAITOK | M_ZERO);
write_argp->pvnr_ioflag = 0;
write_argp->pvnr_resid = bp->b_bcount;
write_argp->pvnr_offset = bp->b_blkno << DEV_BSHIFT;
/* XXX, stupid */
(void)memcpy(&write_argp->pvnr_data, bp->b_data, bp->b_bcount);
error = puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount),
PUFFS_VN_WRITE, write_argp, argsize,
VPTOPNC(ap->a_vp), ap->a_vp, NULL);
if (error)
goto out;
/* XXX: if any of the following trigger, we're in trouble */
/* check 1 */
if (write_argp->pvnr_resid != 0)
error = EIO;
/* check 2 */
if (write_argp->pvnr_resid > bp->b_bcount)
error = EINVAL;
}
out:
biodone(ap->a_bp);
return error;
}
/*
* The rest don't get a free trip to userspace and back, they
* have to stay within the kernel.
*/
/*
* bmap doesn't really make any sense for puffs, so just 1:1 map it.
* well, maybe somehow, somewhere, some day ....
*/
int
puffs_bmap(void *v)
{
struct vop_bmap_args /* {
const struct vnodeop_desc *a_desc;
struct vnode *a_vp;
daddr_t a_bn;
struct vnode **a_vpp;
daddr_t *a_bnp;
int *a_runp;
} */ *ap = v;
struct puffs_mount *pmp;
pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
if (ap->a_vpp)
*ap->a_vpp = ap->a_vp;
if (ap->a_bnp)
*ap->a_bnp = ap->a_bn;
if (ap->a_runp)
*ap->a_runp = pmp->pmp_req_maxsize - PUFFS_REQSTRUCT_MAX;
return 0;
}
/*
* moreXXX: yes, todo
*/
@ -1420,26 +1673,6 @@ puffs_islocked(void *v)
return rv;
}
#if 0
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;
}
#endif
int
puffs_generic(void *v)
{