Module Name: src Committed By: pooka Date: Thu Nov 11 17:26:01 UTC 2010
Modified Files: src/sys/rump/librump/rumpvfs: rumpfs.c Log Message: support read/write & ubc To generate a diff of this commit: cvs rdiff -u -r1.70 -r1.71 src/sys/rump/librump/rumpvfs/rumpfs.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/rump/librump/rumpvfs/rumpfs.c diff -u src/sys/rump/librump/rumpvfs/rumpfs.c:1.70 src/sys/rump/librump/rumpvfs/rumpfs.c:1.71 --- src/sys/rump/librump/rumpvfs/rumpfs.c:1.70 Thu Nov 11 16:08:31 2010 +++ src/sys/rump/librump/rumpvfs/rumpfs.c Thu Nov 11 17:26:01 2010 @@ -1,7 +1,7 @@ -/* $NetBSD: rumpfs.c,v 1.70 2010/11/11 16:08:31 pooka Exp $ */ +/* $NetBSD: rumpfs.c,v 1.71 2010/11/11 17:26:01 pooka Exp $ */ /* - * Copyright (c) 2009 Antti Kantee. All Rights Reserved. + * Copyright (c) 2009, 2010 Antti Kantee. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,10 +26,11 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: rumpfs.c,v 1.70 2010/11/11 16:08:31 pooka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: rumpfs.c,v 1.71 2010/11/11 17:26:01 pooka Exp $"); #include <sys/param.h> #include <sys/atomic.h> +#include <sys/buf.h> #include <sys/dirent.h> #include <sys/errno.h> #include <sys/filedesc.h> @@ -52,6 +53,8 @@ #include <miscfs/genfs/genfs.h> #include <miscfs/genfs/genfs_node.h> +#include <uvm/uvm_extern.h> + #include <rump/rumpuser.h> #include "rump_private.h" @@ -75,6 +78,8 @@ static int rump_vop_readlink(void *); static int rump_vop_whiteout(void *); static int rump_vop_pathconf(void *); +static int rump_vop_bmap(void *); +static int rump_vop_strategy(void *); int (**fifo_vnodeop_p)(void *); const struct vnodeopv_entry_desc fifo_vnodeop_entries[] = { @@ -114,6 +119,8 @@ { &vop_remove_desc, genfs_eopnotsupp }, { &vop_link_desc, genfs_eopnotsupp }, { &vop_pathconf_desc, rump_vop_pathconf }, + { &vop_bmap_desc, rump_vop_bmap }, + { &vop_strategy_desc, rump_vop_strategy }, { NULL, NULL } }; const struct vnodeopv_desc rump_vnodeop_opv_desc = @@ -165,6 +172,10 @@ int writefd; uint64_t offset; } reg; + struct { + void *data; + size_t dlen; + } reg_noet; struct { /* VDIR */ LIST_HEAD(, rumpfs_dent) dents; struct rumpfs_node *parent; @@ -179,6 +190,8 @@ #define rn_readfd rn_u.reg.readfd #define rn_writefd rn_u.reg.writefd #define rn_offset rn_u.reg.offset +#define rn_data rn_u.reg_noet.data +#define rn_dlen rn_u.reg_noet.dlen #define rn_dir rn_u.dir.dents #define rn_parent rn_u.dir.parent #define rn_linktarg rn_u.link.target @@ -193,7 +206,7 @@ struct vnode *rfsmp_rvp; }; -static struct rumpfs_node *makeprivate(enum vtype, dev_t, off_t); +static struct rumpfs_node *makeprivate(enum vtype, dev_t, off_t, bool); /* * Extra Terrestrial stuff. We map a given key (pathname) to a file on @@ -340,7 +353,7 @@ et = kmem_alloc(sizeof(*et), KM_SLEEP); strcpy(et->et_key, key); et->et_keylen = strlen(et->et_key); - et->et_rn = rn = makeprivate(ettype_to_vtype(ftype), rdev, size); + et->et_rn = rn = makeprivate(ettype_to_vtype(ftype), rdev, size, true); et->et_removing = false; et->et_blkmin = dmin; @@ -462,7 +475,7 @@ static kmutex_t reclock; static struct rumpfs_node * -makeprivate(enum vtype vt, dev_t rdev, off_t size) +makeprivate(enum vtype vt, dev_t rdev, off_t size, bool et) { struct rumpfs_node *rn; struct vattr *va; @@ -475,8 +488,10 @@ LIST_INIT(&rn->rn_dir); break; case VREG: - rn->rn_readfd = -1; - rn->rn_writefd = -1; + if (et) { + rn->rn_readfd = -1; + rn->rn_writefd = -1; + } break; default: break; @@ -668,10 +683,11 @@ return ENOENT; } - rn = makeprivate(hft_to_vtype(hft), NODEV, fsize); + rn = makeprivate(hft_to_vtype(hft), NODEV, fsize, true); rn->rn_flags |= RUMPNODE_CANRECLAIM; if (rnd->rn_flags & RUMPNODE_DIR_ETSUBS) { rn->rn_flags |= RUMPNODE_DIR_ET | RUMPNODE_DIR_ETSUBS; + rn->rn_flags |= RUMPNODE_ET_PHONE_HOST; } rn->rn_hostpath = newpath; @@ -754,7 +770,7 @@ struct rumpfs_node *rnd = dvp->v_data, *rn; int rv = 0; - rn = makeprivate(VDIR, NODEV, DEV_BSIZE); + rn = makeprivate(VDIR, NODEV, DEV_BSIZE, false); rn->rn_parent = rnd; rv = makevnode(dvp->v_mount, rn, vpp); if (rv) @@ -815,7 +831,7 @@ struct rumpfs_node *rnd = dvp->v_data, *rn; int rv; - rn = makeprivate(va->va_type, va->va_rdev, DEV_BSIZE); + rn = makeprivate(va->va_type, va->va_rdev, DEV_BSIZE, false); rv = makevnode(dvp->v_mount, rn, vpp); if (rv) goto out; @@ -846,7 +862,7 @@ int rv; newsize = va->va_type == VSOCK ? DEV_BSIZE : 0; - rn = makeprivate(va->va_type, NODEV, newsize); + rn = makeprivate(va->va_type, NODEV, newsize, false); rv = makevnode(dvp->v_mount, rn, vpp); if (rv) goto out; @@ -879,7 +895,7 @@ linklen = strlen(target); KASSERT(linklen < MAXPATHLEN); - rn = makeprivate(VLNK, NODEV, linklen); + rn = makeprivate(VLNK, NODEV, linklen, false); rv = makevnode(dvp->v_mount, rn, vpp); if (rv) goto out; @@ -1045,25 +1061,13 @@ } static int -rump_vop_read(void *v) +etread(struct rumpfs_node *rn, struct uio *uio) { - struct vop_read_args /* { - struct vnode *a_vp; - struct uio *a_uio; - int ioflags a_ioflag; - kauth_cred_t a_cred; - }; */ *ap = v; - struct vnode *vp = ap->a_vp; - struct rumpfs_node *rn = vp->v_data; - struct uio *uio = ap->a_uio; uint8_t *buf; size_t bufsize; ssize_t n; int error = 0; - if (rn->rn_readfd == -1) - return EOPNOTSUPP; - bufsize = uio->uio_resid; buf = kmem_alloc(bufsize, KM_SLEEP); if ((n = rumpuser_pread(rn->rn_readfd, buf, bufsize, @@ -1075,10 +1079,11 @@ out: kmem_free(buf, bufsize); return error; + } static int -rump_vop_write(void *v) +rump_vop_read(void *v) { struct vop_read_args /* { struct vnode *a_vp; @@ -1089,14 +1094,36 @@ struct vnode *vp = ap->a_vp; struct rumpfs_node *rn = vp->v_data; struct uio *uio = ap->a_uio; + const int advice = IO_ADV_DECODE(ap->a_ioflag); + off_t chunk; + int error; + + /* et op? */ + if (rn->rn_flags & RUMPNODE_ET_PHONE_HOST) + return etread(rn, uio); + + /* otherwise, it's off to ubc with us */ + while (uio->uio_resid > 0) { + chunk = MIN(uio->uio_resid, (off_t)rn->rn_dlen-uio->uio_offset); + if (chunk == 0) + break; + error = ubc_uiomove(&vp->v_uobj, uio, chunk, advice, + UBC_READ | UBC_PARTIALOK | UBC_WANT_UNMAP(vp)?UBC_UNMAP:0); + if (error) + break; + } + + return error; +} + +static int +etwrite(struct rumpfs_node *rn, struct uio *uio) +{ uint8_t *buf; size_t bufsize; ssize_t n; int error = 0; - if (rn->rn_writefd == -1) - return EOPNOTSUPP; - bufsize = uio->uio_resid; buf = kmem_alloc(bufsize, KM_SLEEP); error = uiomove(buf, bufsize, uio); @@ -1116,6 +1143,134 @@ } static int +rump_vop_write(void *v) +{ + struct vop_read_args /* { + struct vnode *a_vp; + struct uio *a_uio; + int ioflags a_ioflag; + kauth_cred_t a_cred; + }; */ *ap = v; + struct vnode *vp = ap->a_vp; + struct rumpfs_node *rn = vp->v_data; + struct uio *uio = ap->a_uio; + const int advice = IO_ADV_DECODE(ap->a_ioflag); + void *olddata; + size_t oldlen, newlen; + off_t chunk; + int error; + bool allocd = false; + + /* consult et? */ + if (rn->rn_flags & RUMPNODE_ET_PHONE_HOST) + return etwrite(rn, uio); + + /* + * Otherwise, it's a case of ubcmove. + */ + + /* + * First, make sure we have enough storage. + * + * No, you don't need to tell me it's not very efficient. + * No, it doesn't really support sparse files, just fakes it. + */ + newlen = uio->uio_offset + uio->uio_resid; + if (rn->rn_dlen < newlen) { + oldlen = rn->rn_dlen; + olddata = rn->rn_data; + + rn->rn_data = rump_hypermalloc(newlen, 0, true, "rumpfs"); + rn->rn_dlen = newlen; + memset(rn->rn_data, 0, newlen); + memcpy(rn->rn_data, olddata, oldlen); + allocd = true; + uvm_vnp_setsize(vp, newlen); + } + + /* ok, we have enough stooorage. write */ + while (uio->uio_resid > 0) { + chunk = MIN(uio->uio_resid, (off_t)rn->rn_dlen-uio->uio_offset); + if (chunk == 0) + break; + error = ubc_uiomove(&vp->v_uobj, uio, chunk, advice, + UBC_WRITE | UBC_PARTIALOK | UBC_WANT_UNMAP(vp)?UBC_UNMAP:0); + if (error) + break; + } + + if (allocd) { + if (error) { + rump_hyperfree(rn->rn_data, newlen); + rn->rn_data = olddata; + rn->rn_dlen = oldlen; + uvm_vnp_setsize(vp, oldlen); + } else { + rump_hyperfree(olddata, oldlen); + } + } + + return error; +} + +static int +rump_vop_bmap(void *v) +{ + struct vop_bmap_args /* { + struct vnode *a_vp; + daddr_t a_bn; + struct vnode **a_vpp; + daddr_t *a_bnp; + int *a_runp; + } */ *ap = v; + + /* 1:1 mapping */ + 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 = 16; + + return 0; +} + +static int +rump_vop_strategy(void *v) +{ + struct vop_strategy_args /* { + struct vnode *a_vp; + struct buf *a_bp; + } */ *ap = v; + struct vnode *vp = ap->a_vp; + struct rumpfs_node *rn = vp->v_data; + struct buf *bp = ap->a_bp; + off_t copylen, copyoff; + int error; + + if (vp->v_type != VREG || rn->rn_flags & RUMPNODE_ET_PHONE_HOST) { + error = EINVAL; + goto out; + } + + copyoff = bp->b_blkno << DEV_BSHIFT; + copylen = MIN(rn->rn_dlen - copyoff, bp->b_bcount); + if (BUF_ISWRITE(bp)) { + memcpy((uint8_t *)rn->rn_data + copyoff, bp->b_data, copylen); + } else { + memset((uint8_t*)bp->b_data + copylen, 0, bp->b_bcount-copylen); + memcpy(bp->b_data, (uint8_t *)rn->rn_data + copyoff, copylen); + } + bp->b_resid = 0; + error = 0; + + out: + bp->b_error = error; + biodone(bp); + return 0; +} + +static int rump_vop_pathconf(void *v) { struct vop_pathconf_args /* { @@ -1285,7 +1440,7 @@ rfsmp = kmem_alloc(sizeof(*rfsmp), KM_SLEEP); - rn = makeprivate(VDIR, NODEV, DEV_BSIZE); + rn = makeprivate(VDIR, NODEV, DEV_BSIZE, false); rn->rn_parent = rn; if ((error = makevnode(mp, rn, &rfsmp->rfsmp_rvp)) != 0) return error; @@ -1298,6 +1453,7 @@ mp->mnt_stat.f_iosize = 512; mp->mnt_flag |= MNT_LOCAL; mp->mnt_iflag |= IMNT_MPSAFE; + mp->mnt_fs_bshift = DEV_BSHIFT; vfs_getnewfsid(mp); return 0;